|
|
|
@ -13,7 +13,7 @@ import { validateAndNormalizePagination } from '@/utils/validators';
|
|
|
|
import { buildPaginatedResponse } from '@/utils/helpers';
|
|
|
|
import { buildPaginatedResponse } from '@/utils/helpers';
|
|
|
|
import { toImageResponse } from '@/types/responses';
|
|
|
|
import { toImageResponse } from '@/types/responses';
|
|
|
|
import { db } from '@/db';
|
|
|
|
import { db } from '@/db';
|
|
|
|
import { flows } from '@banatie/database';
|
|
|
|
import { flows, type Image } from '@banatie/database';
|
|
|
|
import { eq } from 'drizzle-orm';
|
|
|
|
import { eq } from 'drizzle-orm';
|
|
|
|
import type {
|
|
|
|
import type {
|
|
|
|
UploadImageResponse,
|
|
|
|
UploadImageResponse,
|
|
|
|
@ -704,13 +704,14 @@ imagesRouter.put(
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Assign a project-scoped alias to an image
|
|
|
|
* Assign or remove a project-scoped alias from an image
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Sets or updates the project-scoped alias for an image:
|
|
|
|
* Sets, updates, or removes the project-scoped alias for an image:
|
|
|
|
* - Alias must start with @ symbol
|
|
|
|
* - Alias must start with @ symbol (when assigning)
|
|
|
|
* - Must be unique within the project
|
|
|
|
* - Must be unique within the project
|
|
|
|
* - Replaces existing alias if image already has one
|
|
|
|
* - Replaces existing alias if image already has one
|
|
|
|
* - Used for alias resolution in generations and CDN access
|
|
|
|
* - Used for alias resolution in generations and CDN access
|
|
|
|
|
|
|
|
* - Set alias to null to remove existing alias
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This is a dedicated endpoint introduced in Section 6.1 to separate
|
|
|
|
* This is a dedicated endpoint introduced in Section 6.1 to separate
|
|
|
|
* alias assignment from general metadata updates.
|
|
|
|
* alias assignment from general metadata updates.
|
|
|
|
@ -722,24 +723,30 @@ imagesRouter.put(
|
|
|
|
* @param {string} req.params.id_or_alias - Image ID (UUID) or alias (@-prefixed)
|
|
|
|
* @param {string} req.params.id_or_alias - Image ID (UUID) or alias (@-prefixed)
|
|
|
|
* @param {string} [req.query.flowId] - Flow ID for flow-scoped alias resolution
|
|
|
|
* @param {string} [req.query.flowId] - Flow ID for flow-scoped alias resolution
|
|
|
|
* @param {object} req.body - Request body
|
|
|
|
* @param {object} req.body - Request body
|
|
|
|
* @param {string} req.body.alias - Project-scoped alias (e.g., "@hero-bg")
|
|
|
|
* @param {string|null} req.body.alias - Project-scoped alias (e.g., "@hero-bg") or null to remove
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @returns {UpdateImageResponse} 200 - Updated image with new alias
|
|
|
|
* @returns {UpdateImageResponse} 200 - Updated image with new/removed alias
|
|
|
|
* @returns {object} 404 - Image not found or access denied
|
|
|
|
* @returns {object} 404 - Image not found or access denied
|
|
|
|
* @returns {object} 400 - Missing or invalid alias
|
|
|
|
* @returns {object} 400 - Invalid alias format
|
|
|
|
* @returns {object} 401 - Missing or invalid API key
|
|
|
|
* @returns {object} 401 - Missing or invalid API key
|
|
|
|
* @returns {object} 409 - Alias already exists
|
|
|
|
* @returns {object} 409 - Alias already exists
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @throws {Error} IMAGE_NOT_FOUND - Image does not exist
|
|
|
|
* @throws {Error} IMAGE_NOT_FOUND - Image does not exist
|
|
|
|
* @throws {Error} VALIDATION_ERROR - Alias is required
|
|
|
|
* @throws {Error} VALIDATION_ERROR - Invalid alias format
|
|
|
|
* @throws {Error} ALIAS_CONFLICT - Alias already assigned to another image
|
|
|
|
* @throws {Error} ALIAS_CONFLICT - Alias already assigned to another image
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @example UUID identifier
|
|
|
|
* @example Assign alias
|
|
|
|
* PUT /api/v1/images/550e8400-e29b-41d4-a716-446655440000/alias
|
|
|
|
* PUT /api/v1/images/550e8400-e29b-41d4-a716-446655440000/alias
|
|
|
|
* {
|
|
|
|
* {
|
|
|
|
* "alias": "@hero-background"
|
|
|
|
* "alias": "@hero-background"
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
*
|
|
|
|
|
|
|
|
* @example Remove alias
|
|
|
|
|
|
|
|
* PUT /api/v1/images/550e8400-e29b-41d4-a716-446655440000/alias
|
|
|
|
|
|
|
|
* {
|
|
|
|
|
|
|
|
* "alias": null
|
|
|
|
|
|
|
|
* }
|
|
|
|
|
|
|
|
*
|
|
|
|
* @example Project-scoped alias identifier
|
|
|
|
* @example Project-scoped alias identifier
|
|
|
|
* PUT /api/v1/images/@old-hero/alias
|
|
|
|
* PUT /api/v1/images/@old-hero/alias
|
|
|
|
* {
|
|
|
|
* {
|
|
|
|
@ -762,11 +769,12 @@ imagesRouter.put(
|
|
|
|
const { flowId } = req.query;
|
|
|
|
const { flowId } = req.query;
|
|
|
|
const { alias } = req.body;
|
|
|
|
const { alias } = req.body;
|
|
|
|
|
|
|
|
|
|
|
|
if (!alias || typeof alias !== 'string') {
|
|
|
|
// Validate: alias must be null (to remove) or a non-empty string
|
|
|
|
|
|
|
|
if (alias !== null && (typeof alias !== 'string' || alias.trim() === '')) {
|
|
|
|
res.status(400).json({
|
|
|
|
res.status(400).json({
|
|
|
|
success: false,
|
|
|
|
success: false,
|
|
|
|
error: {
|
|
|
|
error: {
|
|
|
|
message: 'Alias is required and must be a string',
|
|
|
|
message: 'Alias must be null (to remove) or a non-empty string',
|
|
|
|
code: 'VALIDATION_ERROR',
|
|
|
|
code: 'VALIDATION_ERROR',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
@ -815,7 +823,16 @@ imagesRouter.put(
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const updated = await service.assignProjectAlias(imageId, alias);
|
|
|
|
// Either remove alias (null) or assign new one (override behavior per Section 5.2)
|
|
|
|
|
|
|
|
let updated: Image;
|
|
|
|
|
|
|
|
if (alias === null) {
|
|
|
|
|
|
|
|
// Remove alias
|
|
|
|
|
|
|
|
updated = await service.update(imageId, { alias: null });
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Reassign alias (clears from any existing image, then assigns to this one)
|
|
|
|
|
|
|
|
await service.reassignProjectAlias(alias, imageId, image.projectId);
|
|
|
|
|
|
|
|
updated = (await service.getById(imageId))!;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
res.json({
|
|
|
|
success: true,
|
|
|
|
success: true,
|
|
|
|
|