fix: aliases
This commit is contained in:
parent
88cb1f2c61
commit
8623442157
|
|
@ -43,6 +43,42 @@ const getAliasService = (): AliasService => {
|
|||
return aliasService;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve id_or_alias parameter to imageId
|
||||
* Supports both UUID and alias (@-prefixed) identifiers
|
||||
* Per Section 6.2 of api-refactoring-final.md
|
||||
*
|
||||
* @param identifier - UUID or alias string
|
||||
* @param projectId - Project ID for alias resolution
|
||||
* @param flowId - Optional flow ID for flow-scoped alias resolution
|
||||
* @returns imageId (UUID)
|
||||
* @throws Error if alias not found
|
||||
*/
|
||||
async function resolveImageIdentifier(
|
||||
identifier: string,
|
||||
projectId: string,
|
||||
flowId?: string
|
||||
): Promise<string> {
|
||||
// Check if parameter is alias (starts with @)
|
||||
if (identifier.startsWith('@')) {
|
||||
const aliasServiceInstance = getAliasService();
|
||||
const resolution = await aliasServiceInstance.resolve(
|
||||
identifier,
|
||||
projectId,
|
||||
flowId
|
||||
);
|
||||
|
||||
if (!resolution) {
|
||||
throw new Error(`Alias '${identifier}' not found`);
|
||||
}
|
||||
|
||||
return resolution.imageId;
|
||||
}
|
||||
|
||||
// Otherwise treat as UUID
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a single image file to project storage
|
||||
*
|
||||
|
|
@ -206,12 +242,17 @@ imagesRouter.post(
|
|||
fileSize: file.size,
|
||||
fileHash: null,
|
||||
source: 'uploaded',
|
||||
alias: alias || null,
|
||||
alias: null,
|
||||
meta: meta ? JSON.parse(meta) : {},
|
||||
width,
|
||||
height,
|
||||
});
|
||||
|
||||
// Reassign project alias if provided (override behavior per Section 5.2)
|
||||
if (alias) {
|
||||
await service.reassignProjectAlias(alias, imageRecord.id, projectId);
|
||||
}
|
||||
|
||||
// Eager flow creation if flowAlias is provided
|
||||
if (flowAlias) {
|
||||
// Use pendingFlowId if available, otherwise finalFlowId
|
||||
|
|
@ -344,8 +385,21 @@ imagesRouter.get(
|
|||
);
|
||||
|
||||
/**
|
||||
* @deprecated Use GET /api/v1/images/:alias directly instead (Section 6.2)
|
||||
*
|
||||
* Resolve an alias to an image using 3-tier precedence system
|
||||
*
|
||||
* **DEPRECATED**: This endpoint is deprecated as of Section 6.2. Use the main
|
||||
* GET /api/v1/images/:id_or_alias endpoint instead, which supports both UUIDs
|
||||
* and aliases (@-prefixed) directly in the path parameter.
|
||||
*
|
||||
* **Migration Guide**:
|
||||
* - Old: GET /api/v1/images/resolve/@hero
|
||||
* - New: GET /api/v1/images/@hero
|
||||
*
|
||||
* This endpoint remains functional for backwards compatibility but will be
|
||||
* removed in a future version.
|
||||
*
|
||||
* Resolves aliases through a priority-based lookup system:
|
||||
* 1. Technical aliases (@last, @first, @upload) - computed on-the-fly
|
||||
* 2. Flow-scoped aliases - looked up in flow's JSONB aliases field (requires flowId)
|
||||
|
|
@ -359,7 +413,7 @@ imagesRouter.get(
|
|||
* @param {string} req.params.alias - Alias to resolve (e.g., "@last", "@hero", "@step-1")
|
||||
* @param {string} [req.query.flowId] - Flow context for flow-scoped resolution
|
||||
*
|
||||
* @returns {ResolveAliasResponse} 200 - Resolved image with scope and details
|
||||
* @returns {ResolveAliasResponse} 200 - Resolved image with scope and details (includes X-Deprecated header)
|
||||
* @returns {object} 404 - Alias not found in any scope
|
||||
* @returns {object} 401 - Missing or invalid API key
|
||||
*
|
||||
|
|
@ -389,6 +443,12 @@ imagesRouter.get(
|
|||
|
||||
const projectId = req.apiKey.projectId;
|
||||
|
||||
// Add deprecation header
|
||||
res.setHeader(
|
||||
'X-Deprecated',
|
||||
'This endpoint is deprecated. Use GET /api/v1/images/:alias instead (Section 6.2)'
|
||||
);
|
||||
|
||||
try {
|
||||
const resolution = await aliasServiceInstance.resolve(
|
||||
alias,
|
||||
|
|
@ -453,10 +513,11 @@ imagesRouter.get(
|
|||
* - File metadata (size, MIME type, hash)
|
||||
* - Focal point and custom metadata
|
||||
*
|
||||
* @route GET /api/v1/images/:id
|
||||
* @route GET /api/v1/images/:id_or_alias
|
||||
* @authentication Project Key required
|
||||
*
|
||||
* @param {string} req.params.id - Image ID (UUID)
|
||||
* @param {string} req.params.id_or_alias - Image ID (UUID) or alias (@alias)
|
||||
* @param {string} [req.query.flowId] - Flow ID for flow-scoped alias resolution
|
||||
*
|
||||
* @returns {GetImageResponse} 200 - Complete image details
|
||||
* @returns {object} 404 - Image not found or access denied
|
||||
|
|
@ -466,16 +527,38 @@ imagesRouter.get(
|
|||
*
|
||||
* @example
|
||||
* GET /api/v1/images/550e8400-e29b-41d4-a716-446655440000
|
||||
* GET /api/v1/images/@hero
|
||||
* GET /api/v1/images/@hero?flowId=abc-123
|
||||
*/
|
||||
imagesRouter.get(
|
||||
'/:id',
|
||||
'/:id_or_alias',
|
||||
validateApiKey,
|
||||
requireProjectKey,
|
||||
asyncHandler(async (req: any, res: Response<GetImageResponse>) => {
|
||||
const service = getImageService();
|
||||
const { id } = req.params;
|
||||
const { id_or_alias } = req.params;
|
||||
const { flowId } = req.query;
|
||||
|
||||
const image = await service.getById(id);
|
||||
// Resolve alias to imageId if needed (Section 6.2)
|
||||
let imageId: string;
|
||||
try {
|
||||
imageId = await resolveImageIdentifier(
|
||||
id_or_alias,
|
||||
req.apiKey.projectId,
|
||||
flowId as string | undefined
|
||||
);
|
||||
} catch (error) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: {
|
||||
message: error instanceof Error ? error.message : 'Image not found',
|
||||
code: 'IMAGE_NOT_FOUND',
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const image = await service.getById(imageId);
|
||||
if (!image) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
|
|
@ -513,11 +596,13 @@ imagesRouter.get(
|
|||
* - Custom metadata (arbitrary JSON object)
|
||||
*
|
||||
* Note: Alias assignment moved to separate endpoint PUT /images/:id/alias (Section 6.1)
|
||||
* Supports both UUID and alias (@-prefixed) identifiers per Section 6.2.
|
||||
*
|
||||
* @route PUT /api/v1/images/:id
|
||||
* @route PUT /api/v1/images/:id_or_alias
|
||||
* @authentication Project Key required
|
||||
*
|
||||
* @param {string} req.params.id - Image ID (UUID)
|
||||
* @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 {UpdateImageRequest} req.body - Update parameters
|
||||
* @param {object} [req.body.focalPoint] - Focal point for cropping
|
||||
* @param {number} req.body.focalPoint.x - X coordinate (0.0-1.0)
|
||||
|
|
@ -530,23 +615,55 @@ imagesRouter.get(
|
|||
*
|
||||
* @throws {Error} IMAGE_NOT_FOUND - Image does not exist
|
||||
*
|
||||
* @example
|
||||
* @example UUID identifier
|
||||
* PUT /api/v1/images/550e8400-e29b-41d4-a716-446655440000
|
||||
* {
|
||||
* "focalPoint": { "x": 0.5, "y": 0.3 },
|
||||
* "meta": { "category": "hero", "priority": 1 }
|
||||
* }
|
||||
*
|
||||
* @example Project-scoped alias
|
||||
* PUT /api/v1/images/@hero-banner
|
||||
* {
|
||||
* "focalPoint": { "x": 0.5, "y": 0.3 }
|
||||
* }
|
||||
*
|
||||
* @example Flow-scoped alias
|
||||
* PUT /api/v1/images/@product-shot?flowId=123e4567-e89b-12d3-a456-426614174000
|
||||
* {
|
||||
* "meta": { "category": "product" }
|
||||
* }
|
||||
*/
|
||||
imagesRouter.put(
|
||||
'/:id',
|
||||
'/:id_or_alias',
|
||||
validateApiKey,
|
||||
requireProjectKey,
|
||||
asyncHandler(async (req: any, res: Response<UpdateImageResponse>) => {
|
||||
const service = getImageService();
|
||||
const { id } = req.params;
|
||||
const { id_or_alias } = req.params;
|
||||
const { flowId } = req.query;
|
||||
const { focalPoint, meta } = req.body; // Removed alias (Section 6.1)
|
||||
|
||||
const image = await service.getById(id);
|
||||
// Resolve alias to imageId if needed (Section 6.2)
|
||||
let imageId: string;
|
||||
try {
|
||||
imageId = await resolveImageIdentifier(
|
||||
id_or_alias,
|
||||
req.apiKey.projectId,
|
||||
flowId as string | undefined
|
||||
);
|
||||
} catch (error) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: {
|
||||
message: error instanceof Error ? error.message : 'Image not found',
|
||||
code: 'IMAGE_NOT_FOUND',
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const image = await service.getById(imageId);
|
||||
if (!image) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
|
|
@ -577,7 +694,7 @@ imagesRouter.put(
|
|||
if (focalPoint !== undefined) updates.focalPoint = focalPoint;
|
||||
if (meta !== undefined) updates.meta = meta;
|
||||
|
||||
const updated = await service.update(id, updates);
|
||||
const updated = await service.update(imageId, updates);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
|
|
@ -597,11 +714,13 @@ imagesRouter.put(
|
|||
*
|
||||
* This is a dedicated endpoint introduced in Section 6.1 to separate
|
||||
* alias assignment from general metadata updates.
|
||||
* Supports both UUID and alias (@-prefixed) identifiers per Section 6.2.
|
||||
*
|
||||
* @route PUT /api/v1/images/:id/alias
|
||||
* @route PUT /api/v1/images/:id_or_alias/alias
|
||||
* @authentication Project Key required
|
||||
*
|
||||
* @param {string} req.params.id - Image ID (UUID)
|
||||
* @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 {object} req.body - Request body
|
||||
* @param {string} req.body.alias - Project-scoped alias (e.g., "@hero-bg")
|
||||
*
|
||||
|
|
@ -615,19 +734,32 @@ imagesRouter.put(
|
|||
* @throws {Error} VALIDATION_ERROR - Alias is required
|
||||
* @throws {Error} ALIAS_CONFLICT - Alias already assigned to another image
|
||||
*
|
||||
* @example
|
||||
* @example UUID identifier
|
||||
* PUT /api/v1/images/550e8400-e29b-41d4-a716-446655440000/alias
|
||||
* {
|
||||
* "alias": "@hero-background"
|
||||
* }
|
||||
*
|
||||
* @example Project-scoped alias identifier
|
||||
* PUT /api/v1/images/@old-hero/alias
|
||||
* {
|
||||
* "alias": "@new-hero"
|
||||
* }
|
||||
*
|
||||
* @example Flow-scoped alias identifier
|
||||
* PUT /api/v1/images/@temp-product/alias?flowId=123e4567-e89b-12d3-a456-426614174000
|
||||
* {
|
||||
* "alias": "@final-product"
|
||||
* }
|
||||
*/
|
||||
imagesRouter.put(
|
||||
'/:id/alias',
|
||||
'/:id_or_alias/alias',
|
||||
validateApiKey,
|
||||
requireProjectKey,
|
||||
asyncHandler(async (req: any, res: Response<UpdateImageResponse>) => {
|
||||
const service = getImageService();
|
||||
const { id } = req.params;
|
||||
const { id_or_alias } = req.params;
|
||||
const { flowId } = req.query;
|
||||
const { alias } = req.body;
|
||||
|
||||
if (!alias || typeof alias !== 'string') {
|
||||
|
|
@ -641,7 +773,26 @@ imagesRouter.put(
|
|||
return;
|
||||
}
|
||||
|
||||
const image = await service.getById(id);
|
||||
// Resolve alias to imageId if needed (Section 6.2)
|
||||
let imageId: string;
|
||||
try {
|
||||
imageId = await resolveImageIdentifier(
|
||||
id_or_alias,
|
||||
req.apiKey.projectId,
|
||||
flowId as string | undefined
|
||||
);
|
||||
} catch (error) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: {
|
||||
message: error instanceof Error ? error.message : 'Image not found',
|
||||
code: 'IMAGE_NOT_FOUND',
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const image = await service.getById(imageId);
|
||||
if (!image) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
|
|
@ -664,7 +815,7 @@ imagesRouter.put(
|
|||
return;
|
||||
}
|
||||
|
||||
const updated = await service.assignProjectAlias(id, alias);
|
||||
const updated = await service.assignProjectAlias(imageId, alias);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
|
|
@ -685,11 +836,13 @@ imagesRouter.put(
|
|||
*
|
||||
* Use with caution: This is a destructive operation that permanently removes
|
||||
* the image file and all database references.
|
||||
* Supports both UUID and alias (@-prefixed) identifiers per Section 6.2.
|
||||
*
|
||||
* @route DELETE /api/v1/images/:id
|
||||
* @route DELETE /api/v1/images/:id_or_alias
|
||||
* @authentication Project Key required
|
||||
*
|
||||
* @param {string} req.params.id - Image ID (UUID)
|
||||
* @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
|
||||
*
|
||||
* @returns {DeleteImageResponse} 200 - Deletion confirmation with image ID
|
||||
* @returns {object} 404 - Image not found or access denied
|
||||
|
|
@ -697,7 +850,7 @@ imagesRouter.put(
|
|||
*
|
||||
* @throws {Error} IMAGE_NOT_FOUND - Image does not exist
|
||||
*
|
||||
* @example
|
||||
* @example UUID identifier
|
||||
* DELETE /api/v1/images/550e8400-e29b-41d4-a716-446655440000
|
||||
*
|
||||
* Response:
|
||||
|
|
@ -705,16 +858,42 @@ imagesRouter.put(
|
|||
* "success": true,
|
||||
* "data": { "id": "550e8400-e29b-41d4-a716-446655440000" }
|
||||
* }
|
||||
*
|
||||
* @example Project-scoped alias
|
||||
* DELETE /api/v1/images/@old-banner
|
||||
*
|
||||
* @example Flow-scoped alias
|
||||
* DELETE /api/v1/images/@temp-image?flowId=123e4567-e89b-12d3-a456-426614174000
|
||||
*/
|
||||
imagesRouter.delete(
|
||||
'/:id',
|
||||
'/:id_or_alias',
|
||||
validateApiKey,
|
||||
requireProjectKey,
|
||||
asyncHandler(async (req: any, res: Response<DeleteImageResponse>) => {
|
||||
const service = getImageService();
|
||||
const { id } = req.params;
|
||||
const { id_or_alias } = req.params;
|
||||
const { flowId } = req.query;
|
||||
|
||||
const image = await service.getById(id);
|
||||
// Resolve alias to imageId if needed (Section 6.2)
|
||||
let imageId: string;
|
||||
try {
|
||||
imageId = await resolveImageIdentifier(
|
||||
id_or_alias,
|
||||
req.apiKey.projectId,
|
||||
flowId as string | undefined
|
||||
);
|
||||
} catch (error) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
error: {
|
||||
message: error instanceof Error ? error.message : 'Image not found',
|
||||
code: 'IMAGE_NOT_FOUND',
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const image = await service.getById(imageId);
|
||||
if (!image) {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
|
|
@ -737,11 +916,11 @@ imagesRouter.delete(
|
|||
return;
|
||||
}
|
||||
|
||||
await service.hardDelete(id);
|
||||
await service.hardDelete(imageId);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: { id },
|
||||
data: { id: imageId },
|
||||
});
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -196,42 +196,43 @@ export class AliasService {
|
|||
throw new Error(reservedResult.error!.message);
|
||||
}
|
||||
|
||||
if (flowId) {
|
||||
await this.checkFlowAliasConflict(alias, flowId, projectId);
|
||||
} else {
|
||||
await this.checkProjectAliasConflict(alias, projectId);
|
||||
}
|
||||
// NOTE: Conflict checks removed per Section 5.2 of api-refactoring-final.md
|
||||
// Aliases now use override behavior - new requests take priority over existing aliases
|
||||
// Flow alias conflicts are handled by JSONB field overwrite (no check needed)
|
||||
}
|
||||
|
||||
private async checkProjectAliasConflict(alias: string, projectId: string): Promise<void> {
|
||||
const existing = await db.query.images.findFirst({
|
||||
where: and(
|
||||
eq(images.projectId, projectId),
|
||||
eq(images.alias, alias),
|
||||
isNull(images.deletedAt),
|
||||
isNull(images.flowId)
|
||||
),
|
||||
});
|
||||
// DEPRECATED: Removed per Section 5.2 - aliases now use override behavior
|
||||
// private async checkProjectAliasConflict(alias: string, projectId: string): Promise<void> {
|
||||
// const existing = await db.query.images.findFirst({
|
||||
// where: and(
|
||||
// eq(images.projectId, projectId),
|
||||
// eq(images.alias, alias),
|
||||
// isNull(images.deletedAt),
|
||||
// isNull(images.flowId)
|
||||
// ),
|
||||
// });
|
||||
//
|
||||
// if (existing) {
|
||||
// throw new Error(ERROR_MESSAGES.ALIAS_CONFLICT);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (existing) {
|
||||
throw new Error(ERROR_MESSAGES.ALIAS_CONFLICT);
|
||||
}
|
||||
}
|
||||
|
||||
private async checkFlowAliasConflict(alias: string, flowId: string, projectId: string): Promise<void> {
|
||||
const flow = await db.query.flows.findFirst({
|
||||
where: and(eq(flows.id, flowId), eq(flows.projectId, projectId)),
|
||||
});
|
||||
|
||||
if (!flow) {
|
||||
throw new Error(ERROR_MESSAGES.FLOW_NOT_FOUND);
|
||||
}
|
||||
|
||||
const flowAliases = flow.aliases as Record<string, string>;
|
||||
if (flowAliases[alias]) {
|
||||
throw new Error(ERROR_MESSAGES.ALIAS_CONFLICT);
|
||||
}
|
||||
}
|
||||
// DEPRECATED: Removed per Section 5.2 - flow aliases now use override behavior
|
||||
// Flow alias conflicts are naturally handled by JSONB field overwrite in assignFlowAlias()
|
||||
// private async checkFlowAliasConflict(alias: string, flowId: string, projectId: string): Promise<void> {
|
||||
// const flow = await db.query.flows.findFirst({
|
||||
// where: and(eq(flows.id, flowId), eq(flows.projectId, projectId)),
|
||||
// });
|
||||
//
|
||||
// if (!flow) {
|
||||
// throw new Error(ERROR_MESSAGES.FLOW_NOT_FOUND);
|
||||
// }
|
||||
//
|
||||
// const flowAliases = flow.aliases as Record<string, string>;
|
||||
// if (flowAliases[alias]) {
|
||||
// throw new Error(ERROR_MESSAGES.ALIAS_CONFLICT);
|
||||
// }
|
||||
// }
|
||||
|
||||
async resolveMultiple(
|
||||
aliases: string[],
|
||||
|
|
|
|||
|
|
@ -180,12 +180,21 @@ export class GenerationService {
|
|||
fileSize: genResult.size || 0,
|
||||
fileHash,
|
||||
source: 'generated',
|
||||
alias: params.alias || null,
|
||||
alias: null,
|
||||
meta: params.meta || {},
|
||||
width: genResult.generatedImageData?.width ?? null,
|
||||
height: genResult.generatedImageData?.height ?? null,
|
||||
});
|
||||
|
||||
// Reassign project alias if provided (override behavior per Section 5.2)
|
||||
if (params.alias) {
|
||||
await this.imageService.reassignProjectAlias(
|
||||
params.alias,
|
||||
imageRecord.id,
|
||||
params.projectId
|
||||
);
|
||||
}
|
||||
|
||||
// Eager flow creation if flowAlias is provided (Section 4.2)
|
||||
if (params.flowAlias) {
|
||||
// If we have pendingFlowId, create flow and link pending generations
|
||||
|
|
|
|||
|
|
@ -257,6 +257,46 @@ export class ImageService {
|
|||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reassign a project-scoped alias to a new image
|
||||
* Clears the alias from any existing image and assigns it to the new image
|
||||
* Implements override behavior per Section 5.2 of api-refactoring-final.md
|
||||
*
|
||||
* @param alias - The alias to reassign (e.g., "@hero")
|
||||
* @param newImageId - ID of the image to receive the alias
|
||||
* @param projectId - Project ID for scope validation
|
||||
*/
|
||||
async reassignProjectAlias(
|
||||
alias: string,
|
||||
newImageId: string,
|
||||
projectId: string
|
||||
): Promise<void> {
|
||||
// Step 1: Clear alias from any existing image with this alias
|
||||
await db
|
||||
.update(images)
|
||||
.set({
|
||||
alias: null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(images.projectId, projectId),
|
||||
eq(images.alias, alias),
|
||||
isNull(images.deletedAt),
|
||||
isNull(images.flowId)
|
||||
)
|
||||
);
|
||||
|
||||
// Step 2: Assign alias to new image
|
||||
await db
|
||||
.update(images)
|
||||
.set({
|
||||
alias: alias,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(eq(images.id, newImageId));
|
||||
}
|
||||
|
||||
async getByStorageKey(storageKey: string): Promise<Image | null> {
|
||||
const image = await db.query.images.findFirst({
|
||||
where: and(
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ X-API-Key: {{apiKey}}
|
|||
###
|
||||
|
||||
### Test 7: Resolve project-scoped alias
|
||||
# Expected: Resolves to uploadedImageId, scope=project
|
||||
GET {{base}}/api/v1/images/resolve/@test-logo
|
||||
# Expected: Resolves to uploadedImageId (Section 6.2: direct alias support)
|
||||
GET {{base}}/api/v1/images/@test-logo
|
||||
X-API-Key: {{apiKey}}
|
||||
|
||||
###
|
||||
|
|
@ -142,15 +142,15 @@ Content-Type: application/json
|
|||
###
|
||||
|
||||
### Test 9.2: Verify new alias works
|
||||
# Expected: Resolves to same uploadedImageId
|
||||
GET {{base}}/api/v1/images/resolve/@new-test-logo
|
||||
# Expected: Resolves to same uploadedImageId (Section 6.2: direct alias support)
|
||||
GET {{base}}/api/v1/images/@new-test-logo
|
||||
X-API-Key: {{apiKey}}
|
||||
|
||||
###
|
||||
|
||||
### Test 10: Verify old alias doesn't work after update
|
||||
# Expected: 404 - Alias not found
|
||||
GET {{base}}/api/v1/images/resolve/@test-logo
|
||||
GET {{base}}/api/v1/images/@test-logo
|
||||
X-API-Key: {{apiKey}}
|
||||
|
||||
###
|
||||
|
|
@ -176,7 +176,7 @@ X-API-Key: {{apiKey}}
|
|||
|
||||
### Test 11.3: Verify alias resolution fails
|
||||
# Expected: 404 - Alias not found
|
||||
GET {{base}}/api/v1/images/resolve/@new-test-logo
|
||||
GET {{base}}/api/v1/images/@new-test-logo
|
||||
X-API-Key: {{apiKey}}
|
||||
|
||||
###
|
||||
|
|
@ -283,8 +283,8 @@ X-API-Key: {{apiKey}}
|
|||
###
|
||||
|
||||
### Test 14.4: Verify alias resolution works
|
||||
# Expected: Resolves to heroImageId
|
||||
GET {{base}}/api/v1/images/resolve/@hero-banner
|
||||
# Expected: Resolves to heroImageId (Section 6.2: direct alias support)
|
||||
GET {{base}}/api/v1/images/@hero-banner
|
||||
X-API-Key: {{apiKey}}
|
||||
|
||||
###
|
||||
|
|
@ -314,8 +314,8 @@ X-API-Key: {{apiKey}}
|
|||
@secondHeroImageId = {{genConflict.response.body.$.data.outputImageId}}
|
||||
|
||||
### Test 15.3: Verify second image has the alias
|
||||
# Expected: Resolves to secondHeroImageId (not heroImageId)
|
||||
GET {{base}}/api/v1/images/resolve/@hero-banner
|
||||
# Expected: Resolves to secondHeroImageId (not heroImageId) (Section 6.2: direct alias support)
|
||||
GET {{base}}/api/v1/images/@hero-banner
|
||||
X-API-Key: {{apiKey}}
|
||||
|
||||
###
|
||||
|
|
|
|||
|
|
@ -294,9 +294,10 @@ export async function resolveAlias(
|
|||
alias: string,
|
||||
flowId?: string
|
||||
): Promise<any> {
|
||||
// Section 6.2: Use direct alias identifier instead of /resolve/ endpoint
|
||||
const endpoint = flowId
|
||||
? `${endpoints.images}/resolve/${alias}?flowId=${flowId}`
|
||||
: `${endpoints.images}/resolve/${alias}`;
|
||||
? `${endpoints.images}/${alias}?flowId=${flowId}`
|
||||
: `${endpoints.images}/${alias}`;
|
||||
|
||||
const result = await api(endpoint);
|
||||
return result.data.data;
|
||||
|
|
|
|||
Loading…
Reference in New Issue