88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
import { createConfigError } from './cliError';
|
|
|
|
interface WorkerMetadataBinding {
|
|
name?: string;
|
|
text?: unknown;
|
|
}
|
|
|
|
interface WorkerMetadata {
|
|
project_name?: string;
|
|
bindings?: WorkerMetadataBinding[];
|
|
}
|
|
|
|
function parseWorkerMetadata(metadataContent: string): WorkerMetadata {
|
|
try {
|
|
return JSON.parse(metadataContent);
|
|
} catch (error) {
|
|
throw createConfigError('Worker metadata must be valid JSON.', [
|
|
'The `/create_worker` API should return JSON metadata for backend deployment.',
|
|
'Retry `pinme create`.',
|
|
]);
|
|
}
|
|
}
|
|
|
|
function isRealBindingValue(value: unknown): value is string {
|
|
if (typeof value !== 'string') {
|
|
return false;
|
|
}
|
|
|
|
const trimmed = value.trim();
|
|
return Boolean(trimmed)
|
|
&& trimmed !== 'xxx'
|
|
&& trimmed !== 'project_name'
|
|
&& !trimmed.startsWith('__PINME_');
|
|
}
|
|
|
|
function findBinding(metadata: WorkerMetadata, name: string): WorkerMetadataBinding | undefined {
|
|
return metadata.bindings?.find((binding) => binding.name === name);
|
|
}
|
|
|
|
export function validateWorkerMetadataForCreate(
|
|
metadataContent: string,
|
|
projectName: string,
|
|
): void {
|
|
const metadata = parseWorkerMetadata(metadataContent);
|
|
const apiKeyBinding = findBinding(metadata, 'API_KEY');
|
|
const projectNameBinding = findBinding(metadata, 'PROJECT_NAME');
|
|
|
|
if (!isRealBindingValue(apiKeyBinding?.text)) {
|
|
throw createConfigError('Worker metadata is missing a real API_KEY binding.', [
|
|
'The template metadata contains placeholder values and cannot be deployed as-is.',
|
|
'Retry `pinme create` so Pinme can fetch fresh worker metadata from `/create_worker`.',
|
|
]);
|
|
}
|
|
|
|
if (projectNameBinding?.text !== projectName) {
|
|
throw createConfigError('Worker metadata is missing a matching PROJECT_NAME binding.', [
|
|
`Expected PROJECT_NAME binding text to be \`${projectName}\`.`,
|
|
'Retry `pinme create` so Pinme can fetch fresh worker metadata from `/create_worker`.',
|
|
]);
|
|
}
|
|
|
|
if (metadata.project_name && metadata.project_name !== projectName) {
|
|
throw createConfigError('Worker metadata project_name does not match the created project.', [
|
|
`Expected metadata project_name to be \`${projectName}\`.`,
|
|
`Received metadata project_name \`${metadata.project_name}\`.`,
|
|
]);
|
|
}
|
|
}
|
|
|
|
export function getValidatedWorkerMetadataContent(
|
|
metadata: unknown,
|
|
projectName: string,
|
|
): string {
|
|
if (!metadata) {
|
|
throw createConfigError('Worker metadata is missing from project creation response.', [
|
|
'The `/create_worker` API should return backend metadata before the prebuilt worker is deployed.',
|
|
'Retry `pinme create`.',
|
|
]);
|
|
}
|
|
|
|
const metadataContent = typeof metadata === 'string'
|
|
? metadata
|
|
: JSON.stringify(metadata, null, 2);
|
|
|
|
validateWorkerMetadataForCreate(metadataContent, projectName);
|
|
return metadataContent;
|
|
}
|