123 lines
3.6 KiB
TypeScript
123 lines
3.6 KiB
TypeScript
/**
|
|
* DevController - REST API for development-time content editing
|
|
*
|
|
* Endpoints:
|
|
* - POST /dev/read-locale - Read locale file content
|
|
* - POST /dev/write-locale - Write locale file with backup
|
|
* - POST /dev/image-metadata - Get image variation metadata
|
|
*
|
|
* Security: All endpoints protected by DevGuard (NODE_ENV === 'development')
|
|
*/
|
|
|
|
import { Controller, Post, Body, UseGuards, Logger } from '@nestjs/common';
|
|
import { DevGuard } from '../auth/dev.guard';
|
|
import { DevService } from './dev.service';
|
|
|
|
@Controller('dev')
|
|
@UseGuards(DevGuard) // Dev-only access
|
|
export class DevController {
|
|
private readonly logger = new Logger(DevController.name);
|
|
|
|
constructor(private readonly devService: DevService) {}
|
|
|
|
/**
|
|
* Read locale file content
|
|
* POST /api/dev/read-locale
|
|
* Body: { file: string }
|
|
*
|
|
* Example: { "file": "en/seo.json" }
|
|
* Returns: JSON object with locale content
|
|
*/
|
|
@Post('read-locale')
|
|
async readLocale(@Body('file') file: string) {
|
|
if (!file) {
|
|
return { success: false, error: 'Missing required field: file' };
|
|
}
|
|
|
|
try {
|
|
this.logger.log(`Reading locale file: ${file}`);
|
|
const content = await this.devService.readLocaleFile(file);
|
|
return { success: true, content };
|
|
} catch (error) {
|
|
this.logger.error(`Failed to read locale: ${(error as Error).message}`, (error as Error).stack);
|
|
return { success: false, error: (error as Error).message };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write locale file content
|
|
* POST /api/dev/write-locale
|
|
* Body: { file: string, path: string, content: string, backup?: boolean }
|
|
*
|
|
* Example: {
|
|
* "file": "en/seo.json",
|
|
* "path": "homepage.hero.title",
|
|
* "content": "New Title",
|
|
* "backup": true
|
|
* }
|
|
* Returns: { success: boolean, backup?: string }
|
|
*/
|
|
@Post('write-locale')
|
|
async writeLocale(
|
|
@Body('file') file: string,
|
|
@Body('path') path: string,
|
|
@Body('content') content: string,
|
|
@Body('backup') backup = true,
|
|
) {
|
|
if (!file || !path || content === undefined) {
|
|
return {
|
|
success: false,
|
|
error: 'Missing required fields: file, path, content',
|
|
};
|
|
}
|
|
|
|
try {
|
|
this.logger.log(`Writing locale file: ${file}, path: ${path}`);
|
|
const result = await this.devService.writeLocaleFile(file, path, content, backup);
|
|
return result;
|
|
} catch (error) {
|
|
this.logger.error(`Failed to write locale: ${(error as Error).message}`, (error as Error).stack);
|
|
return { success: false, error: (error as Error).message };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get image metadata
|
|
* POST /api/dev/image-metadata
|
|
* Body: { type: string, id: string, variant: string, family: string }
|
|
*
|
|
* Example: {
|
|
* "type": "seo",
|
|
* "id": "homepage-v2",
|
|
* "variant": "hero",
|
|
* "family": "cyberpunk"
|
|
* }
|
|
* Returns: Image metadata including URL, dimensions, prompt, etc.
|
|
*/
|
|
@Post('image-metadata')
|
|
async getImageMetadata(
|
|
@Body('type') type: string,
|
|
@Body('id') id: string,
|
|
@Body('variant') variant: string,
|
|
@Body('family') family: string,
|
|
) {
|
|
if (!type || !id || !variant || !family) {
|
|
return {
|
|
success: false,
|
|
error: 'Missing required fields: type, id, variant, family',
|
|
};
|
|
}
|
|
|
|
try {
|
|
this.logger.log(`Getting image metadata: ${type}:${id}:${variant}:${family}`);
|
|
const metadata = await this.devService.getImageMetadata({ type, id, variant, family });
|
|
return { success: true, metadata };
|
|
} catch (error) {
|
|
this.logger.error(
|
|
`Failed to get image metadata: ${(error as Error).message}`,
|
|
(error as Error).stack,
|
|
);
|
|
return { success: false, error: (error as Error).message };
|
|
}
|
|
}
|
|
}
|