import { z } from "zod"; import { InvalidMetadata } from "./installation-errors.ts"; export const registryName = (subject: string) => `owner:${subject}`; export const installationId = z.string().regex(/^[a-f0-9]{32}$/); export const ownerSubject = z .string() .min(1) .max(512) .refine((value) => !!value.trim() && !/[\u0000-\u001f\u007f]/.test(value)); const resourceId = z .string() .regex( /^(?:[a-f0-9]{32}|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$/, ); const timestamp = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER); export const releaseIdentity = z.strictObject({ version: z .string() .max(128) .regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/), sourceRevision: z.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/), artifactDigest: z.string().regex(/^[a-f0-9]{64}$/), }); const resourceFields = { personalAgentNamespaceId: resourceId.nullable(), sandboxNamespaceId: resourceId.nullable(), sandboxApplicationId: resourceId.nullable(), runtimeOrigin: z.string().max(253).nullable(), }; const status = z.enum([ "reserved", "installing", "ready", "updating", "failed", ]); export const installationProgress = z.enum([ "preparing", "deploying", "provisioning", "verifying", "complete", ]); const errorCode = z .enum([ "recovery_required", "artifact_unavailable", "setup_required", "reauthorization_required", "account_denied", "resource_conflict", "deployment_failed", "health_failed", "temporarily_unavailable", ]) .nullable(); const installationSchema = z.strictObject({ schemaVersion: z.literal(1), installationId, ownerSubject, accountId: installationId, createdAt: timestamp, updatedAt: timestamp, revision: z.number().int().positive().max(Number.MAX_SAFE_INTEGER), resources: z.strictObject({ workerName: z.string(), sandboxApplicationName: z.string(), ...resourceFields, }), desiredRelease: releaseIdentity.nullable(), installedRelease: releaseIdentity .extend({ installedAt: timestamp }) .nullable(), status, // Older records have no checkpoint; absence never implies verified health. progress: installationProgress.nullable().default(null), errorCode, operationId: installationId.nullable(), }); // Keep schema-derived models named when they pass through RPC and Effect types. export interface Installation extends z.infer {} export interface ReleaseIdentity extends z.infer {} // No identity, account, names, installed release or timestamps can be assigned. // Only the trusted provisioner can call the registry's update RPC. export const installationChanges = z .strictObject({ resources: z.strictObject(resourceFields).partial().optional(), desiredRelease: releaseIdentity.optional(), status: status.exclude(["reserved"]).optional(), progress: installationProgress.optional(), errorCode: errorCode.optional(), operationId: installationId.optional(), }) .refine((value) => Object.keys(value).length > 0); export interface InstallationChanges extends z.infer< typeof installationChanges > {} export function parse(schema: z.ZodType, value: unknown): T { const result = schema.safeParse(value); if (!result.success) throw new InvalidMetadata(); return result.data; } export function sameRelease( a: ReleaseIdentity | null, b: ReleaseIdentity | null, ) { return ( a === b || (!!a && !!b && a.version === b.version && a.sourceRevision === b.sourceRevision && a.artifactDigest === b.artifactDigest) ); } function hasOwnedResources(record: Installation) { const { resources, installationId } = record; return ( resources.workerName === `flarebot-${installationId}` && resources.sandboxApplicationName === `flarebot-shell-${installationId}` && (resources.runtimeOrigin === null || new RegExp( `^https://flarebot-${installationId}\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.workers\\.dev$`, ).test(resources.runtimeOrigin)) ); } function hasValidTimestamps(record: Installation) { return ( record.updatedAt >= record.createdAt && (!record.installedRelease || (record.installedRelease.installedAt >= record.createdAt && record.installedRelease.installedAt <= record.updatedAt)) ); } function hasValidProgress(record: Installation) { if (record.status === "reserved") return record.progress === null; if (record.status === "ready") return record.progress === null || record.progress === "complete"; return record.progress !== "complete"; } const resourceKeys = Object.keys( resourceFields, ) as (keyof typeof resourceFields)[]; function hasValidReleaseState(record: Installation) { if ((record.status === "failed") !== (record.errorCode !== null)) return false; if ( record.installedRelease && resourceKeys.some((key) => record.resources[key] === null) ) return false; if ( record.status !== "reserved" && (!record.desiredRelease || !record.operationId) ) return false; switch (record.status) { case "reserved": return ( !record.desiredRelease && !record.installedRelease && !record.operationId && resourceKeys.every((key) => record.resources[key] === null) ); case "installing": return record.installedRelease === null; case "updating": return record.installedRelease !== null; case "ready": return ( record.installedRelease !== null && sameRelease(record.desiredRelease, record.installedRelease) ); case "failed": return true; } } const validatedInstallation = installationSchema .refine(hasOwnedResources) .refine(hasValidTimestamps) .refine(hasValidProgress) .refine(hasValidReleaseState); // Revalidate even typed values at every storage/read/export boundary. Strict // nested schemas reject JS spreads containing credentials or customer content. export function parseInstallation(value: unknown): Installation { return parse(validatedInstallation, value); }