@supacloud/compiler 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -495,6 +495,11 @@ route 会自动按 HTTP status 执行内置 response decoder,并返回 schema
495
495
  OpenAPI。`buildRouteUrl` 和 `createApiClient` 可直接复用,也支持动态 headers
496
496
  和请求拦截器。
497
497
 
498
+ 每个生成 route 还会按 HTTP 方法暴露 `.query()` 或 `.mutate()` procedure
499
+ facade,并在 `API_PROCEDURES` 中输出 Command/幂等元数据。声明
500
+ `idempotency: "required"` 的 mutation 必须显式传入稳定的 `idempotencyKey`;
501
+ 客户端不会静默生成新 key。
502
+
498
503
  ### Migration from manual decoders
499
504
 
500
505
  旧版本要求调用方为每个有响应 schema 的 route 传入 decoder。升级后删除该
package/dist/cli.js CHANGED
@@ -2245,6 +2245,8 @@ function renderClient(graph, options) {
2245
2245
  const schemaLocals = new Map;
2246
2246
  const usedTypeNames = new Set;
2247
2247
  const allRoutes = [];
2248
+ const allProcedures = [];
2249
+ const commandByClassName = new Map(graph.modules.flatMap((module) => module.commands.map((command) => [command.className, command])));
2248
2250
  let usesStatic = false;
2249
2251
  let usesValue = false;
2250
2252
  const uniqueTypeName = (candidate) => {
@@ -2375,8 +2377,30 @@ function renderClient(graph, options) {
2375
2377
  const responseSchemaEntries = hasResponseMap ? Object.entries(responseSchemas).map(([status, ref]) => [status, ref.local]) : responseSchema ? [["200", responseSchema.local]] : [];
2376
2378
  const responseSchemaArgument = responseSchemaEntries.length > 0 ? `{ ${responseSchemaEntries.map(([status, local]) => `${JSON.stringify(status)}: ${local}`).join(", ")} }` : "undefined";
2377
2379
  const responseKindArgument = responseKind === undefined ? "undefined" : JSON.stringify(responseKind);
2380
+ const command = route.command === undefined ? undefined : commandByClassName.get(route.command);
2381
+ const procedureKind = route.method === "GET" || route.method === "HEAD" ? "query" : "mutation";
2382
+ const idempotencyMode = command?.idempotency ?? "none";
2383
+ const procedureMetadata = {
2384
+ key: `${controller.className}.${route.handler}`,
2385
+ method: route.method,
2386
+ path: fullPath,
2387
+ controller: controller.className,
2388
+ handler: route.handler,
2389
+ kind: procedureKind,
2390
+ idempotency: idempotencyMode
2391
+ };
2392
+ allProcedures.push({
2393
+ method: route.method,
2394
+ path: fullPath,
2395
+ controller: controller.className,
2396
+ handler: route.handler,
2397
+ kind: procedureKind,
2398
+ ...command?.name === undefined ? {} : { command: command.name },
2399
+ ...command?.permission === undefined ? {} : { permission: command.permission },
2400
+ idempotency: idempotencyMode
2401
+ });
2378
2402
  routeMethods.push(`
2379
- ${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}),`);
2403
+ ${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}, ${JSON.stringify(procedureMetadata)}),`);
2380
2404
  }
2381
2405
  controllerEntries.push(`
2382
2406
  ${controllerKey}: {${routeMethods.join("")}
@@ -2407,6 +2431,66 @@ function renderClient(graph, options) {
2407
2431
  "",
2408
2432
  "export type ResponseDecoder<T> = (value: unknown) => T;",
2409
2433
  "",
2434
+ 'export type ProcedureKind = "query" | "mutation";',
2435
+ 'export type IdempotencyMode = "required" | "none";',
2436
+ "",
2437
+ "export interface ProcedureMetadata<",
2438
+ " Kind extends ProcedureKind = ProcedureKind,",
2439
+ " Idempotency extends IdempotencyMode = IdempotencyMode,",
2440
+ "> {",
2441
+ " key: string;",
2442
+ " method: string;",
2443
+ " path: string;",
2444
+ " controller: string;",
2445
+ " handler: string;",
2446
+ " kind: Kind;",
2447
+ " idempotency: Idempotency;",
2448
+ "}",
2449
+ "",
2450
+ "export interface ProcedureExecutionOptions {",
2451
+ " /** Reuse the same key when retrying an uncertain mutation. */",
2452
+ " idempotencyKey?: string;",
2453
+ " signal?: AbortSignal;",
2454
+ "}",
2455
+ "",
2456
+ "export type RequiredProcedureExecutionOptions = ProcedureExecutionOptions & { idempotencyKey: string };",
2457
+ "",
2458
+ "type ProcedureResult<Result> = [Result] extends [never] ? unknown : Result;",
2459
+ "",
2460
+ "type ProcedureArgs<Options extends ClientRequestOptions, Idempotency extends IdempotencyMode> =",
2461
+ ' Idempotency extends "required"',
2462
+ " ? {} extends Options",
2463
+ " ? [execution: RequiredProcedureExecutionOptions] | [input: Options, execution: RequiredProcedureExecutionOptions]",
2464
+ " : [input: Options, execution: RequiredProcedureExecutionOptions]",
2465
+ " : {} extends Options",
2466
+ " ? [input?: Options, execution?: ProcedureExecutionOptions]",
2467
+ " : [input: Options, execution?: ProcedureExecutionOptions];",
2468
+ "",
2469
+ "export type ProcedureCall<",
2470
+ " Options extends ClientRequestOptions = ClientRequestOptions,",
2471
+ " Result = never,",
2472
+ ' Idempotency extends IdempotencyMode = "none",',
2473
+ "> = (...args: ProcedureArgs<Options, Idempotency>) => Promise<ProcedureResult<Result>>;",
2474
+ "",
2475
+ "export type QueryableProcedure<",
2476
+ " Options extends ClientRequestOptions,",
2477
+ " Result,",
2478
+ " Idempotency extends IdempotencyMode,",
2479
+ " Kind extends ProcedureKind,",
2480
+ "> = ProcedureCall<Options, Result, Idempotency> & {",
2481
+ " readonly __supacloudProcedure: ProcedureMetadata<Kind, Idempotency>;",
2482
+ " readonly __supacloudInput?: Options;",
2483
+ "};",
2484
+ "",
2485
+ "export type ProcedureMember<",
2486
+ " Options extends ClientRequestOptions,",
2487
+ " Result,",
2488
+ " Kind extends ProcedureKind,",
2489
+ " Idempotency extends IdempotencyMode,",
2490
+ '> = Kind extends "query"',
2491
+ ' ? { query: QueryableProcedure<Options, Result, Idempotency, "query"> }',
2492
+ ' : { mutate: QueryableProcedure<Options, Result, Idempotency, "mutation"> };',
2493
+ "",
2410
2494
  'export type ApiClientErrorCode = "API_HTTP_ERROR" | "API_RESPONSE_INVALID" | "API_RESPONSE_UNDECLARED";',
2411
2495
  "",
2412
2496
  "export interface ApiClientErrorDetails {",
@@ -2450,6 +2534,17 @@ function renderClient(graph, options) {
2450
2534
  " : { (options: Options): Promise<Result>; <T>(options: Options, decode: ResponseDecoder<T>): Promise<T> }",
2451
2535
  ") & ((...args: {} extends Options ? [options?: Options] : [options: Options]) => Promise<[Result] extends [never] ? unknown : Result>);",
2452
2536
  "",
2537
+ "export interface ApiProcedureDefinition {",
2538
+ " method: string;",
2539
+ " path: string;",
2540
+ " controller: string;",
2541
+ " handler: string;",
2542
+ " kind: ProcedureKind;",
2543
+ " command?: string;",
2544
+ " permission?: string;",
2545
+ " idempotency: IdempotencyMode;",
2546
+ "}",
2547
+ "",
2453
2548
  ...routeTypes,
2454
2549
  ...routeTypes.length > 0 ? [""] : [],
2455
2550
  "export interface HttpInterceptorRequest {",
@@ -2457,6 +2552,7 @@ function renderClient(graph, options) {
2457
2552
  " url: string;",
2458
2553
  " headers: Record<string, string>;",
2459
2554
  " body?: unknown;",
2555
+ " signal?: AbortSignal;",
2460
2556
  "}",
2461
2557
  "",
2462
2558
  "export type HttpInterceptorFn = (",
@@ -2475,6 +2571,8 @@ function renderClient(graph, options) {
2475
2571
  "",
2476
2572
  "export const API_ROUTES = " + JSON.stringify(allRoutes, null, 2) + " as const;",
2477
2573
  "",
2574
+ "export const API_PROCEDURES: readonly ApiProcedureDefinition[] = " + JSON.stringify(allProcedures, null, 2) + ";",
2575
+ "",
2478
2576
  "export type AppRoutePath = typeof API_ROUTES[number]['path'];",
2479
2577
  "",
2480
2578
  "export const API_SCHEMAS = [",
@@ -2700,6 +2798,7 @@ function renderClient(graph, options) {
2700
2798
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2701
2799
  " responseKind?: string,",
2702
2800
  " raw?: boolean,",
2801
+ " execution?: ProcedureExecutionOptions,",
2703
2802
  " ): Promise<T>;",
2704
2803
  " async function request<T>(",
2705
2804
  " method: string,",
@@ -2709,6 +2808,7 @@ function renderClient(graph, options) {
2709
2808
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2710
2809
  " responseKind?: string,",
2711
2810
  " raw?: boolean,",
2811
+ " execution?: ProcedureExecutionOptions,",
2712
2812
  " ): Promise<T | unknown>;",
2713
2813
  " async function request(",
2714
2814
  " method: string,",
@@ -2723,6 +2823,7 @@ function renderClient(graph, options) {
2723
2823
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2724
2824
  " responseKind?: string,",
2725
2825
  " raw = false,",
2826
+ " execution?: ProcedureExecutionOptions,",
2726
2827
  " ): Promise<T | unknown> {",
2727
2828
  " const url = `${baseUrl}${buildRouteUrl(path, options.params, options.query)}`;",
2728
2829
  ' const customHeaders = typeof config.headers === "function" ? await config.headers() : config.headers;',
@@ -2748,9 +2849,10 @@ function renderClient(graph, options) {
2748
2849
  " headers: reqPayload.headers,",
2749
2850
  " ...(reqPayload.body === undefined ? {} : { body: raw ? rawBody(reqPayload.body) : JSON.stringify(reqPayload.body) }),",
2750
2851
  ' ...(raw && reqPayload.body instanceof ReadableStream ? { duplex: "half" } : {}),',
2852
+ " ...(reqPayload.signal === undefined ? {} : { signal: reqPayload.signal }),",
2751
2853
  " });",
2752
2854
  " };",
2753
- " const response = await executeChain(0, { method, url, headers, body: options.body });",
2855
+ " const response = await executeChain(0, { method, url, headers, body: options.body, ...(execution?.signal === undefined ? {} : { signal: execution.signal }) });",
2754
2856
  " const declaredSchema = responseSchemas ? selectResponseSchema(response.status, responseSchemas) : undefined;",
2755
2857
  " const failure = (code: ApiClientErrorCode, message: string) => new ApiClientError(message, {",
2756
2858
  ' code, method, path, status: response.status, requestId: response.headers.get("x-request-id"),',
@@ -2788,7 +2890,44 @@ function renderClient(graph, options) {
2788
2890
  " return decode ? decode(checked) : checked;",
2789
2891
  " }",
2790
2892
  "",
2791
- ` function makeRoute<Options extends ClientRequestOptions, Result = never>(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false): RouteMethod<Options, Result> {`,
2893
+ " function hasHeader(headers: Record<string, string>, name: string): boolean {",
2894
+ " return Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());",
2895
+ " }",
2896
+ "",
2897
+ " function withProcedureExecution(",
2898
+ " options: ClientRequestOptions,",
2899
+ " execution: ProcedureExecutionOptions | undefined,",
2900
+ " idempotency: IdempotencyMode,",
2901
+ " ): ClientRequestOptions {",
2902
+ " const headers = { ...(options.headers as Record<string, string> | undefined) };",
2903
+ " if (execution?.idempotencyKey !== undefined) {",
2904
+ " if (!/^[A-Za-z0-9._:-]{1,512}$/.test(execution.idempotencyKey)) {",
2905
+ ' throw new TypeError("idempotencyKey must contain only safe header characters and be at most 512 characters");',
2906
+ " }",
2907
+ ' headers["idempotency-key"] = execution.idempotencyKey;',
2908
+ " }",
2909
+ ' if (idempotency === "required" && !hasHeader(headers, "idempotency-key")) {',
2910
+ ' throw new TypeError("This mutation requires an idempotencyKey");',
2911
+ " }",
2912
+ " return Object.keys(headers).length === 0 ? options : { ...options, headers };",
2913
+ " }",
2914
+ "",
2915
+ " function isProcedureExecution(value: unknown): value is ProcedureExecutionOptions {",
2916
+ ' if (value === null || typeof value !== "object" || Array.isArray(value)) return false;',
2917
+ ' return Object.hasOwn(value, "idempotencyKey") || Object.hasOwn(value, "signal");',
2918
+ " }",
2919
+ "",
2920
+ ` function makeProcedure<Options extends ClientRequestOptions, Result = never, Idempotency extends IdempotencyMode = "none", Kind extends ProcedureKind = ProcedureKind>(metadata: ProcedureMetadata<Kind, Idempotency>, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false): QueryableProcedure<Options, Result, Idempotency, Kind> {`,
2921
+ " const procedure = async (first?: Options | ProcedureExecutionOptions, second?: ProcedureExecutionOptions): Promise<unknown> => {",
2922
+ " const execution = second ?? (isProcedureExecution(first) ? first : undefined);",
2923
+ " const input = (execution === first ? undefined : first) ?? {};",
2924
+ " const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, metadata.idempotency);",
2925
+ " return request(metadata.method, metadata.path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
2926
+ " };",
2927
+ " return Object.assign(procedure, { __supacloudProcedure: Object.freeze(metadata) }) as QueryableProcedure<Options, Result, Idempotency, Kind>;",
2928
+ " }",
2929
+ "",
2930
+ ` function makeRoute<Options extends ClientRequestOptions, Result = never, Kind extends ProcedureKind = never, Idempotency extends IdempotencyMode = "none">(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false, kind?: Kind, idempotency: Idempotency = "none" as Idempotency, metadata?: ProcedureMetadata<Kind, Idempotency>): RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency> {`,
2792
2931
  " function route<T>(options: Options, decode: ResponseDecoder<T>): Promise<T>;",
2793
2932
  " function route(options: Options): Promise<Result>;",
2794
2933
  " function route(options?: Options): Promise<unknown>;",
@@ -2796,13 +2935,16 @@ function renderClient(graph, options) {
2796
2935
  " const requestOptions = options ?? {};",
2797
2936
  " return request(method, path, requestOptions, decode, responseSchemas, responseKind, raw);",
2798
2937
  " }",
2799
- " return route as RouteMethod<Options, Result>;",
2938
+ ' if (kind === "query" && metadata) Object.assign(route, { query: makeProcedure<Options, Result, Idempotency, "query">(metadata as ProcedureMetadata<"query", Idempotency>, responseSchemas, responseKind, raw) });',
2939
+ ' if (kind === "mutation" && metadata) Object.assign(route, { mutate: makeProcedure<Options, Result, Idempotency, "mutation">(metadata as ProcedureMetadata<"mutation", Idempotency>, responseSchemas, responseKind, raw) });',
2940
+ " return route as RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency>;",
2800
2941
  " }",
2801
2942
  "",
2802
2943
  " return {",
2803
2944
  " request,",
2804
2945
  " buildRouteUrl,",
2805
2946
  " routes: API_ROUTES,",
2947
+ " procedures: API_PROCEDURES,",
2806
2948
  ...controllerEntries,
2807
2949
  " };",
2808
2950
  "}",
@@ -15670,6 +15812,9 @@ function parseDeliveryBuildManifest(value) {
15670
15812
  if (!Check2(DeliveryBuildManifestSchema, value))
15671
15813
  throw new Error("Invalid delivery build manifest.");
15672
15814
  validateWorkerExecution(value.plan.targets.flatMap((target) => target.execution ? [target.execution] : []));
15815
+ if (value.plan.targets.reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
15816
+ throw new Error("Invalid delivery replica count.");
15817
+ }
15673
15818
  for (const target of value.plan.targets) {
15674
15819
  if (target.execution && (target.kind !== "jobs" || target.isolation !== "process" || target.execution.target !== target.name || target.jobs.length !== 1 || target.jobs[0]?.name !== target.execution.taskKey || value.objects.find((object) => object.name === target.name)?.entryKind !== "bun-worker-application")) {
15675
15820
  throw new Error("Invalid delivery execution binding.");
@@ -15683,7 +15828,7 @@ function parseDeliveryBuildManifest(value) {
15683
15828
  }
15684
15829
  for (const object of value.objects) {
15685
15830
  const target = value.plan.targets.find((target) => target.name === object.name);
15686
- if (object.entryKind === "bun-worker-application" && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
15831
+ if (["bun-worker-application", "go-worker-application", "scriptc-worker-application"].includes(object.entryKind) && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
15687
15832
  throw new Error("Delivery executable kind does not match its target.");
15688
15833
  }
15689
15834
  if (new Set(object.files.map((file) => file.path)).size !== object.files.length || !object.files.some((file) => file.path === object.entrypoint) || deliveryObjectDigest(object) !== object.objectId) {
@@ -15721,7 +15866,9 @@ var init_delivery_build_schema = __esm(() => {
15721
15866
  entryKind: Union([
15722
15867
  Literal("compiled-module-factory"),
15723
15868
  Literal("bun-http-application"),
15724
- Literal("bun-worker-application")
15869
+ Literal("bun-worker-application"),
15870
+ Literal("go-worker-application"),
15871
+ Literal("scriptc-worker-application")
15725
15872
  ]),
15726
15873
  runtimeImports: _Array_(String2()),
15727
15874
  files: _Array_(_Object_({
@@ -16252,6 +16399,107 @@ var init_application_activation = __esm(() => {
16252
16399
  }, { additionalProperties: false });
16253
16400
  });
16254
16401
 
16402
+ // node_modules/@supacloud/delivery/src/deployment-evidence.ts
16403
+ var closed6, sha256, isoDate, status, evidenceStatus, DEPLOYMENT_EVIDENCE_SCHEMA = "supacloud.deployment-evidence.v1", DatabaseProviderSchema, componentName, DeploymentComponentEvidenceSchema, DeploymentEvidenceSchema;
16404
+ var init_deployment_evidence = __esm(() => {
16405
+ init_build();
16406
+ init_value2();
16407
+ init_application_configuration();
16408
+ init_application_release();
16409
+ closed6 = { additionalProperties: false };
16410
+ sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
16411
+ isoDate = String2({ minLength: 20, maxLength: 40 });
16412
+ status = Union([
16413
+ Literal("confirmed"),
16414
+ Literal("failed"),
16415
+ Literal("unknown")
16416
+ ]);
16417
+ evidenceStatus = Union([
16418
+ Literal("confirmed"),
16419
+ Literal("failed"),
16420
+ Literal("unknown"),
16421
+ Literal("incomplete")
16422
+ ]);
16423
+ DatabaseProviderSchema = _Object_({
16424
+ provider: String2({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_.-]*$" }),
16425
+ version: String2({ minLength: 1, maxLength: 64 }),
16426
+ topology: Union([Literal("single-node"), Literal("distributed")]),
16427
+ migration: _Object_({
16428
+ status,
16429
+ inventory_sha256: Union([sha256, Null()]),
16430
+ compatibility: Union([
16431
+ Literal("verified"),
16432
+ Literal("not-proven"),
16433
+ Literal("failed")
16434
+ ])
16435
+ }, closed6),
16436
+ backup: _Object_({
16437
+ status,
16438
+ latest_success_at: Union([isoDate, Null()]),
16439
+ freshness_seconds: Union([Integer({ minimum: 0 }), Null()])
16440
+ }, closed6),
16441
+ recovery: _Object_({
16442
+ status,
16443
+ drill_id: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
16444
+ rpo_seconds: Union([Integer({ minimum: 0 }), Null()]),
16445
+ rto_seconds: Union([Integer({ minimum: 0 }), Null()])
16446
+ }, closed6)
16447
+ }, closed6);
16448
+ componentName = Union([
16449
+ Literal("management-api"),
16450
+ Literal("web-console"),
16451
+ Literal("edge-runtime"),
16452
+ Literal("worker"),
16453
+ Literal("postgres"),
16454
+ Literal("postgrest"),
16455
+ Literal("gotrue"),
16456
+ Literal("storage"),
16457
+ Literal("realtime")
16458
+ ]);
16459
+ DeploymentComponentEvidenceSchema = _Object_({
16460
+ name: componentName,
16461
+ version: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
16462
+ status,
16463
+ health_check: Union([String2({ minLength: 1, maxLength: 256 }), Null()]),
16464
+ checked_at: Union([isoDate, Null()])
16465
+ }, closed6);
16466
+ DeploymentEvidenceSchema = _Object_({
16467
+ schema: Literal(DEPLOYMENT_EVIDENCE_SCHEMA),
16468
+ status: evidenceStatus,
16469
+ recorded_at: isoDate,
16470
+ scope: _Object_({
16471
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
16472
+ application_id: ApplicationIdSchema,
16473
+ environment_id: ApplicationIdSchema
16474
+ }, closed6),
16475
+ source: _Object_({
16476
+ commit_sha: Union([String2({ pattern: "^[0-9a-f]{7,64}$" }), Null()]),
16477
+ manifest_sha256: sha256,
16478
+ contract_schema: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
16479
+ environment_binding_version: Union([sha256, Null()])
16480
+ }, closed6),
16481
+ database: DatabaseProviderSchema,
16482
+ components: _Array_(DeploymentComponentEvidenceSchema, { minItems: 1, maxItems: 32 }),
16483
+ activation: _Object_({
16484
+ release_id: ApplicationReleaseIdSchema,
16485
+ configuration_id: ApplicationConfigurationIdSchema,
16486
+ activation_id: ApplicationConfigurationIdSchema
16487
+ }, closed6),
16488
+ health: _Object_({
16489
+ status,
16490
+ checked_at: Union([isoDate, Null()]),
16491
+ authenticated_smoke: status
16492
+ }, closed6),
16493
+ rollback: _Object_({
16494
+ release_id: Union([ApplicationReleaseIdSchema, Null()]),
16495
+ configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
16496
+ status: Union([Literal("ready"), Literal("not-ready"), Literal("unknown")]),
16497
+ result: Union([status, Null()])
16498
+ }, closed6),
16499
+ notes: _Array_(String2({ minLength: 1, maxLength: 512 }), { maxItems: 32 })
16500
+ }, closed6);
16501
+ });
16502
+
16255
16503
  // node_modules/@supacloud/delivery/src/application-runtime-identity.ts
16256
16504
  var APPLICATION_RUNTIME_PROBE_PATH = "/.well-known/supacloud/runtime", ApplicationRuntimeIdentitySchema, ApplicationReadinessReportSchema;
16257
16505
  var init_application_runtime_identity = __esm(() => {
@@ -16374,6 +16622,7 @@ var init_src = __esm(() => {
16374
16622
  init_application_activation();
16375
16623
  init_application_release();
16376
16624
  init_application_configuration();
16625
+ init_deployment_evidence();
16377
16626
  init_application_runtime_identity();
16378
16627
  init_delivery_build_schema();
16379
16628
  init_delivery_migration_archive();
@@ -23408,7 +23657,7 @@ function isRecord2(value) {
23408
23657
  function arrayLength(value) {
23409
23658
  return Array.isArray(value) ? value.length : undefined;
23410
23659
  }
23411
- async function sha256(path) {
23660
+ async function sha2562(path) {
23412
23661
  return createHash10("sha256").update(await readFile11(path)).digest("hex");
23413
23662
  }
23414
23663
  function overallStatus(findings) {
@@ -23482,7 +23731,7 @@ async function assessMigration(options) {
23482
23731
  contractsManifest = {
23483
23732
  path: contractsManifestPath,
23484
23733
  present: true,
23485
- sha256: await sha256(contractsManifestPath),
23734
+ sha256: await sha2562(contractsManifestPath),
23486
23735
  version: 1,
23487
23736
  ...arrayLength(parsed.commands) === undefined ? {} : { commands: arrayLength(parsed.commands) },
23488
23737
  ...arrayLength(parsed.routes) === undefined ? {} : { routes: arrayLength(parsed.routes) },
@@ -23505,9 +23754,9 @@ async function assessMigration(options) {
23505
23754
  const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
23506
23755
  openApi = {
23507
23756
  baselinePath,
23508
- baselineSha256: await sha256(baselinePath),
23757
+ baselineSha256: await sha2562(baselinePath),
23509
23758
  currentPath,
23510
- currentSha256: await sha256(currentPath),
23759
+ currentSha256: await sha2562(currentPath),
23511
23760
  diff
23512
23761
  };
23513
23762
  if (!diff.ok) {
package/dist/index.js CHANGED
@@ -2244,6 +2244,8 @@ function renderClient(graph, options) {
2244
2244
  const schemaLocals = new Map;
2245
2245
  const usedTypeNames = new Set;
2246
2246
  const allRoutes = [];
2247
+ const allProcedures = [];
2248
+ const commandByClassName = new Map(graph.modules.flatMap((module) => module.commands.map((command) => [command.className, command])));
2247
2249
  let usesStatic = false;
2248
2250
  let usesValue = false;
2249
2251
  const uniqueTypeName = (candidate) => {
@@ -2374,8 +2376,30 @@ function renderClient(graph, options) {
2374
2376
  const responseSchemaEntries = hasResponseMap ? Object.entries(responseSchemas).map(([status, ref]) => [status, ref.local]) : responseSchema ? [["200", responseSchema.local]] : [];
2375
2377
  const responseSchemaArgument = responseSchemaEntries.length > 0 ? `{ ${responseSchemaEntries.map(([status, local]) => `${JSON.stringify(status)}: ${local}`).join(", ")} }` : "undefined";
2376
2378
  const responseKindArgument = responseKind === undefined ? "undefined" : JSON.stringify(responseKind);
2379
+ const command = route.command === undefined ? undefined : commandByClassName.get(route.command);
2380
+ const procedureKind = route.method === "GET" || route.method === "HEAD" ? "query" : "mutation";
2381
+ const idempotencyMode = command?.idempotency ?? "none";
2382
+ const procedureMetadata = {
2383
+ key: `${controller.className}.${route.handler}`,
2384
+ method: route.method,
2385
+ path: fullPath,
2386
+ controller: controller.className,
2387
+ handler: route.handler,
2388
+ kind: procedureKind,
2389
+ idempotency: idempotencyMode
2390
+ };
2391
+ allProcedures.push({
2392
+ method: route.method,
2393
+ path: fullPath,
2394
+ controller: controller.className,
2395
+ handler: route.handler,
2396
+ kind: procedureKind,
2397
+ ...command?.name === undefined ? {} : { command: command.name },
2398
+ ...command?.permission === undefined ? {} : { permission: command.permission },
2399
+ idempotency: idempotencyMode
2400
+ });
2377
2401
  routeMethods.push(`
2378
- ${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}),`);
2402
+ ${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}, ${JSON.stringify(procedureKind)}, ${JSON.stringify(idempotencyMode)}, ${JSON.stringify(procedureMetadata)}),`);
2379
2403
  }
2380
2404
  controllerEntries.push(`
2381
2405
  ${controllerKey}: {${routeMethods.join("")}
@@ -2406,6 +2430,66 @@ function renderClient(graph, options) {
2406
2430
  "",
2407
2431
  "export type ResponseDecoder<T> = (value: unknown) => T;",
2408
2432
  "",
2433
+ 'export type ProcedureKind = "query" | "mutation";',
2434
+ 'export type IdempotencyMode = "required" | "none";',
2435
+ "",
2436
+ "export interface ProcedureMetadata<",
2437
+ " Kind extends ProcedureKind = ProcedureKind,",
2438
+ " Idempotency extends IdempotencyMode = IdempotencyMode,",
2439
+ "> {",
2440
+ " key: string;",
2441
+ " method: string;",
2442
+ " path: string;",
2443
+ " controller: string;",
2444
+ " handler: string;",
2445
+ " kind: Kind;",
2446
+ " idempotency: Idempotency;",
2447
+ "}",
2448
+ "",
2449
+ "export interface ProcedureExecutionOptions {",
2450
+ " /** Reuse the same key when retrying an uncertain mutation. */",
2451
+ " idempotencyKey?: string;",
2452
+ " signal?: AbortSignal;",
2453
+ "}",
2454
+ "",
2455
+ "export type RequiredProcedureExecutionOptions = ProcedureExecutionOptions & { idempotencyKey: string };",
2456
+ "",
2457
+ "type ProcedureResult<Result> = [Result] extends [never] ? unknown : Result;",
2458
+ "",
2459
+ "type ProcedureArgs<Options extends ClientRequestOptions, Idempotency extends IdempotencyMode> =",
2460
+ ' Idempotency extends "required"',
2461
+ " ? {} extends Options",
2462
+ " ? [execution: RequiredProcedureExecutionOptions] | [input: Options, execution: RequiredProcedureExecutionOptions]",
2463
+ " : [input: Options, execution: RequiredProcedureExecutionOptions]",
2464
+ " : {} extends Options",
2465
+ " ? [input?: Options, execution?: ProcedureExecutionOptions]",
2466
+ " : [input: Options, execution?: ProcedureExecutionOptions];",
2467
+ "",
2468
+ "export type ProcedureCall<",
2469
+ " Options extends ClientRequestOptions = ClientRequestOptions,",
2470
+ " Result = never,",
2471
+ ' Idempotency extends IdempotencyMode = "none",',
2472
+ "> = (...args: ProcedureArgs<Options, Idempotency>) => Promise<ProcedureResult<Result>>;",
2473
+ "",
2474
+ "export type QueryableProcedure<",
2475
+ " Options extends ClientRequestOptions,",
2476
+ " Result,",
2477
+ " Idempotency extends IdempotencyMode,",
2478
+ " Kind extends ProcedureKind,",
2479
+ "> = ProcedureCall<Options, Result, Idempotency> & {",
2480
+ " readonly __supacloudProcedure: ProcedureMetadata<Kind, Idempotency>;",
2481
+ " readonly __supacloudInput?: Options;",
2482
+ "};",
2483
+ "",
2484
+ "export type ProcedureMember<",
2485
+ " Options extends ClientRequestOptions,",
2486
+ " Result,",
2487
+ " Kind extends ProcedureKind,",
2488
+ " Idempotency extends IdempotencyMode,",
2489
+ '> = Kind extends "query"',
2490
+ ' ? { query: QueryableProcedure<Options, Result, Idempotency, "query"> }',
2491
+ ' : { mutate: QueryableProcedure<Options, Result, Idempotency, "mutation"> };',
2492
+ "",
2409
2493
  'export type ApiClientErrorCode = "API_HTTP_ERROR" | "API_RESPONSE_INVALID" | "API_RESPONSE_UNDECLARED";',
2410
2494
  "",
2411
2495
  "export interface ApiClientErrorDetails {",
@@ -2449,6 +2533,17 @@ function renderClient(graph, options) {
2449
2533
  " : { (options: Options): Promise<Result>; <T>(options: Options, decode: ResponseDecoder<T>): Promise<T> }",
2450
2534
  ") & ((...args: {} extends Options ? [options?: Options] : [options: Options]) => Promise<[Result] extends [never] ? unknown : Result>);",
2451
2535
  "",
2536
+ "export interface ApiProcedureDefinition {",
2537
+ " method: string;",
2538
+ " path: string;",
2539
+ " controller: string;",
2540
+ " handler: string;",
2541
+ " kind: ProcedureKind;",
2542
+ " command?: string;",
2543
+ " permission?: string;",
2544
+ " idempotency: IdempotencyMode;",
2545
+ "}",
2546
+ "",
2452
2547
  ...routeTypes,
2453
2548
  ...routeTypes.length > 0 ? [""] : [],
2454
2549
  "export interface HttpInterceptorRequest {",
@@ -2456,6 +2551,7 @@ function renderClient(graph, options) {
2456
2551
  " url: string;",
2457
2552
  " headers: Record<string, string>;",
2458
2553
  " body?: unknown;",
2554
+ " signal?: AbortSignal;",
2459
2555
  "}",
2460
2556
  "",
2461
2557
  "export type HttpInterceptorFn = (",
@@ -2474,6 +2570,8 @@ function renderClient(graph, options) {
2474
2570
  "",
2475
2571
  "export const API_ROUTES = " + JSON.stringify(allRoutes, null, 2) + " as const;",
2476
2572
  "",
2573
+ "export const API_PROCEDURES: readonly ApiProcedureDefinition[] = " + JSON.stringify(allProcedures, null, 2) + ";",
2574
+ "",
2477
2575
  "export type AppRoutePath = typeof API_ROUTES[number]['path'];",
2478
2576
  "",
2479
2577
  "export const API_SCHEMAS = [",
@@ -2699,6 +2797,7 @@ function renderClient(graph, options) {
2699
2797
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2700
2798
  " responseKind?: string,",
2701
2799
  " raw?: boolean,",
2800
+ " execution?: ProcedureExecutionOptions,",
2702
2801
  " ): Promise<T>;",
2703
2802
  " async function request<T>(",
2704
2803
  " method: string,",
@@ -2708,6 +2807,7 @@ function renderClient(graph, options) {
2708
2807
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2709
2808
  " responseKind?: string,",
2710
2809
  " raw?: boolean,",
2810
+ " execution?: ProcedureExecutionOptions,",
2711
2811
  " ): Promise<T | unknown>;",
2712
2812
  " async function request(",
2713
2813
  " method: string,",
@@ -2722,6 +2822,7 @@ function renderClient(graph, options) {
2722
2822
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2723
2823
  " responseKind?: string,",
2724
2824
  " raw = false,",
2825
+ " execution?: ProcedureExecutionOptions,",
2725
2826
  " ): Promise<T | unknown> {",
2726
2827
  " const url = `${baseUrl}${buildRouteUrl(path, options.params, options.query)}`;",
2727
2828
  ' const customHeaders = typeof config.headers === "function" ? await config.headers() : config.headers;',
@@ -2747,9 +2848,10 @@ function renderClient(graph, options) {
2747
2848
  " headers: reqPayload.headers,",
2748
2849
  " ...(reqPayload.body === undefined ? {} : { body: raw ? rawBody(reqPayload.body) : JSON.stringify(reqPayload.body) }),",
2749
2850
  ' ...(raw && reqPayload.body instanceof ReadableStream ? { duplex: "half" } : {}),',
2851
+ " ...(reqPayload.signal === undefined ? {} : { signal: reqPayload.signal }),",
2750
2852
  " });",
2751
2853
  " };",
2752
- " const response = await executeChain(0, { method, url, headers, body: options.body });",
2854
+ " const response = await executeChain(0, { method, url, headers, body: options.body, ...(execution?.signal === undefined ? {} : { signal: execution.signal }) });",
2753
2855
  " const declaredSchema = responseSchemas ? selectResponseSchema(response.status, responseSchemas) : undefined;",
2754
2856
  " const failure = (code: ApiClientErrorCode, message: string) => new ApiClientError(message, {",
2755
2857
  ' code, method, path, status: response.status, requestId: response.headers.get("x-request-id"),',
@@ -2787,7 +2889,44 @@ function renderClient(graph, options) {
2787
2889
  " return decode ? decode(checked) : checked;",
2788
2890
  " }",
2789
2891
  "",
2790
- ` function makeRoute<Options extends ClientRequestOptions, Result = never>(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false): RouteMethod<Options, Result> {`,
2892
+ " function hasHeader(headers: Record<string, string>, name: string): boolean {",
2893
+ " return Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());",
2894
+ " }",
2895
+ "",
2896
+ " function withProcedureExecution(",
2897
+ " options: ClientRequestOptions,",
2898
+ " execution: ProcedureExecutionOptions | undefined,",
2899
+ " idempotency: IdempotencyMode,",
2900
+ " ): ClientRequestOptions {",
2901
+ " const headers = { ...(options.headers as Record<string, string> | undefined) };",
2902
+ " if (execution?.idempotencyKey !== undefined) {",
2903
+ " if (!/^[A-Za-z0-9._:-]{1,512}$/.test(execution.idempotencyKey)) {",
2904
+ ' throw new TypeError("idempotencyKey must contain only safe header characters and be at most 512 characters");',
2905
+ " }",
2906
+ ' headers["idempotency-key"] = execution.idempotencyKey;',
2907
+ " }",
2908
+ ' if (idempotency === "required" && !hasHeader(headers, "idempotency-key")) {',
2909
+ ' throw new TypeError("This mutation requires an idempotencyKey");',
2910
+ " }",
2911
+ " return Object.keys(headers).length === 0 ? options : { ...options, headers };",
2912
+ " }",
2913
+ "",
2914
+ " function isProcedureExecution(value: unknown): value is ProcedureExecutionOptions {",
2915
+ ' if (value === null || typeof value !== "object" || Array.isArray(value)) return false;',
2916
+ ' return Object.hasOwn(value, "idempotencyKey") || Object.hasOwn(value, "signal");',
2917
+ " }",
2918
+ "",
2919
+ ` function makeProcedure<Options extends ClientRequestOptions, Result = never, Idempotency extends IdempotencyMode = "none", Kind extends ProcedureKind = ProcedureKind>(metadata: ProcedureMetadata<Kind, Idempotency>, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false): QueryableProcedure<Options, Result, Idempotency, Kind> {`,
2920
+ " const procedure = async (first?: Options | ProcedureExecutionOptions, second?: ProcedureExecutionOptions): Promise<unknown> => {",
2921
+ " const execution = second ?? (isProcedureExecution(first) ? first : undefined);",
2922
+ " const input = (execution === first ? undefined : first) ?? {};",
2923
+ " const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, metadata.idempotency);",
2924
+ " return request(metadata.method, metadata.path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
2925
+ " };",
2926
+ " return Object.assign(procedure, { __supacloudProcedure: Object.freeze(metadata) }) as QueryableProcedure<Options, Result, Idempotency, Kind>;",
2927
+ " }",
2928
+ "",
2929
+ ` function makeRoute<Options extends ClientRequestOptions, Result = never, Kind extends ProcedureKind = never, Idempotency extends IdempotencyMode = "none">(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false, kind?: Kind, idempotency: Idempotency = "none" as Idempotency, metadata?: ProcedureMetadata<Kind, Idempotency>): RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency> {`,
2791
2930
  " function route<T>(options: Options, decode: ResponseDecoder<T>): Promise<T>;",
2792
2931
  " function route(options: Options): Promise<Result>;",
2793
2932
  " function route(options?: Options): Promise<unknown>;",
@@ -2795,13 +2934,16 @@ function renderClient(graph, options) {
2795
2934
  " const requestOptions = options ?? {};",
2796
2935
  " return request(method, path, requestOptions, decode, responseSchemas, responseKind, raw);",
2797
2936
  " }",
2798
- " return route as RouteMethod<Options, Result>;",
2937
+ ' if (kind === "query" && metadata) Object.assign(route, { query: makeProcedure<Options, Result, Idempotency, "query">(metadata as ProcedureMetadata<"query", Idempotency>, responseSchemas, responseKind, raw) });',
2938
+ ' if (kind === "mutation" && metadata) Object.assign(route, { mutate: makeProcedure<Options, Result, Idempotency, "mutation">(metadata as ProcedureMetadata<"mutation", Idempotency>, responseSchemas, responseKind, raw) });',
2939
+ " return route as RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency>;",
2799
2940
  " }",
2800
2941
  "",
2801
2942
  " return {",
2802
2943
  " request,",
2803
2944
  " buildRouteUrl,",
2804
2945
  " routes: API_ROUTES,",
2946
+ " procedures: API_PROCEDURES,",
2805
2947
  ...controllerEntries,
2806
2948
  " };",
2807
2949
  "}",
@@ -14551,6 +14693,9 @@ function parseDeliveryBuildManifest(value) {
14551
14693
  if (!Check2(DeliveryBuildManifestSchema, value))
14552
14694
  throw new Error("Invalid delivery build manifest.");
14553
14695
  validateWorkerExecution(value.plan.targets.flatMap((target) => target.execution ? [target.execution] : []));
14696
+ if (value.plan.targets.reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
14697
+ throw new Error("Invalid delivery replica count.");
14698
+ }
14554
14699
  for (const target of value.plan.targets) {
14555
14700
  if (target.execution && (target.kind !== "jobs" || target.isolation !== "process" || target.execution.target !== target.name || target.jobs.length !== 1 || target.jobs[0]?.name !== target.execution.taskKey || value.objects.find((object) => object.name === target.name)?.entryKind !== "bun-worker-application")) {
14556
14701
  throw new Error("Invalid delivery execution binding.");
@@ -14564,7 +14709,7 @@ function parseDeliveryBuildManifest(value) {
14564
14709
  }
14565
14710
  for (const object of value.objects) {
14566
14711
  const target = value.plan.targets.find((target) => target.name === object.name);
14567
- if (object.entryKind === "bun-worker-application" && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
14712
+ if (["bun-worker-application", "go-worker-application", "scriptc-worker-application"].includes(object.entryKind) && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
14568
14713
  throw new Error("Delivery executable kind does not match its target.");
14569
14714
  }
14570
14715
  if (new Set(object.files.map((file) => file.path)).size !== object.files.length || !object.files.some((file) => file.path === object.entrypoint) || deliveryObjectDigest(object) !== object.objectId) {
@@ -14602,7 +14747,9 @@ var init_delivery_build_schema = __esm(() => {
14602
14747
  entryKind: Union([
14603
14748
  Literal("compiled-module-factory"),
14604
14749
  Literal("bun-http-application"),
14605
- Literal("bun-worker-application")
14750
+ Literal("bun-worker-application"),
14751
+ Literal("go-worker-application"),
14752
+ Literal("scriptc-worker-application")
14606
14753
  ]),
14607
14754
  runtimeImports: _Array_(String2()),
14608
14755
  files: _Array_(_Object_({
@@ -15703,6 +15850,107 @@ var init_application_activation = __esm(() => {
15703
15850
  }, { additionalProperties: false });
15704
15851
  });
15705
15852
 
15853
+ // node_modules/@supacloud/delivery/src/deployment-evidence.ts
15854
+ var closed6, sha256, isoDate, status, evidenceStatus, DEPLOYMENT_EVIDENCE_SCHEMA = "supacloud.deployment-evidence.v1", DatabaseProviderSchema, componentName, DeploymentComponentEvidenceSchema, DeploymentEvidenceSchema;
15855
+ var init_deployment_evidence = __esm(() => {
15856
+ init_build();
15857
+ init_value2();
15858
+ init_application_configuration();
15859
+ init_application_release();
15860
+ closed6 = { additionalProperties: false };
15861
+ sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
15862
+ isoDate = String2({ minLength: 20, maxLength: 40 });
15863
+ status = Union([
15864
+ Literal("confirmed"),
15865
+ Literal("failed"),
15866
+ Literal("unknown")
15867
+ ]);
15868
+ evidenceStatus = Union([
15869
+ Literal("confirmed"),
15870
+ Literal("failed"),
15871
+ Literal("unknown"),
15872
+ Literal("incomplete")
15873
+ ]);
15874
+ DatabaseProviderSchema = _Object_({
15875
+ provider: String2({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_.-]*$" }),
15876
+ version: String2({ minLength: 1, maxLength: 64 }),
15877
+ topology: Union([Literal("single-node"), Literal("distributed")]),
15878
+ migration: _Object_({
15879
+ status,
15880
+ inventory_sha256: Union([sha256, Null()]),
15881
+ compatibility: Union([
15882
+ Literal("verified"),
15883
+ Literal("not-proven"),
15884
+ Literal("failed")
15885
+ ])
15886
+ }, closed6),
15887
+ backup: _Object_({
15888
+ status,
15889
+ latest_success_at: Union([isoDate, Null()]),
15890
+ freshness_seconds: Union([Integer({ minimum: 0 }), Null()])
15891
+ }, closed6),
15892
+ recovery: _Object_({
15893
+ status,
15894
+ drill_id: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
15895
+ rpo_seconds: Union([Integer({ minimum: 0 }), Null()]),
15896
+ rto_seconds: Union([Integer({ minimum: 0 }), Null()])
15897
+ }, closed6)
15898
+ }, closed6);
15899
+ componentName = Union([
15900
+ Literal("management-api"),
15901
+ Literal("web-console"),
15902
+ Literal("edge-runtime"),
15903
+ Literal("worker"),
15904
+ Literal("postgres"),
15905
+ Literal("postgrest"),
15906
+ Literal("gotrue"),
15907
+ Literal("storage"),
15908
+ Literal("realtime")
15909
+ ]);
15910
+ DeploymentComponentEvidenceSchema = _Object_({
15911
+ name: componentName,
15912
+ version: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
15913
+ status,
15914
+ health_check: Union([String2({ minLength: 1, maxLength: 256 }), Null()]),
15915
+ checked_at: Union([isoDate, Null()])
15916
+ }, closed6);
15917
+ DeploymentEvidenceSchema = _Object_({
15918
+ schema: Literal(DEPLOYMENT_EVIDENCE_SCHEMA),
15919
+ status: evidenceStatus,
15920
+ recorded_at: isoDate,
15921
+ scope: _Object_({
15922
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
15923
+ application_id: ApplicationIdSchema,
15924
+ environment_id: ApplicationIdSchema
15925
+ }, closed6),
15926
+ source: _Object_({
15927
+ commit_sha: Union([String2({ pattern: "^[0-9a-f]{7,64}$" }), Null()]),
15928
+ manifest_sha256: sha256,
15929
+ contract_schema: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
15930
+ environment_binding_version: Union([sha256, Null()])
15931
+ }, closed6),
15932
+ database: DatabaseProviderSchema,
15933
+ components: _Array_(DeploymentComponentEvidenceSchema, { minItems: 1, maxItems: 32 }),
15934
+ activation: _Object_({
15935
+ release_id: ApplicationReleaseIdSchema,
15936
+ configuration_id: ApplicationConfigurationIdSchema,
15937
+ activation_id: ApplicationConfigurationIdSchema
15938
+ }, closed6),
15939
+ health: _Object_({
15940
+ status,
15941
+ checked_at: Union([isoDate, Null()]),
15942
+ authenticated_smoke: status
15943
+ }, closed6),
15944
+ rollback: _Object_({
15945
+ release_id: Union([ApplicationReleaseIdSchema, Null()]),
15946
+ configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
15947
+ status: Union([Literal("ready"), Literal("not-ready"), Literal("unknown")]),
15948
+ result: Union([status, Null()])
15949
+ }, closed6),
15950
+ notes: _Array_(String2({ minLength: 1, maxLength: 512 }), { maxItems: 32 })
15951
+ }, closed6);
15952
+ });
15953
+
15706
15954
  // node_modules/@supacloud/delivery/src/application-runtime-identity.ts
15707
15955
  var APPLICATION_RUNTIME_PROBE_PATH = "/.well-known/supacloud/runtime", ApplicationRuntimeIdentitySchema, ApplicationReadinessReportSchema;
15708
15956
  var init_application_runtime_identity = __esm(() => {
@@ -15825,6 +16073,7 @@ var init_src = __esm(() => {
15825
16073
  init_application_activation();
15826
16074
  init_application_release();
15827
16075
  init_application_configuration();
16076
+ init_deployment_evidence();
15828
16077
  init_application_runtime_identity();
15829
16078
  init_delivery_build_schema();
15830
16079
  init_delivery_migration_archive();
@@ -23140,7 +23389,7 @@ function isRecord2(value) {
23140
23389
  function arrayLength(value) {
23141
23390
  return Array.isArray(value) ? value.length : undefined;
23142
23391
  }
23143
- async function sha256(path) {
23392
+ async function sha2562(path) {
23144
23393
  return createHash10("sha256").update(await readFile11(path)).digest("hex");
23145
23394
  }
23146
23395
  function overallStatus(findings) {
@@ -23214,7 +23463,7 @@ async function assessMigration(options) {
23214
23463
  contractsManifest = {
23215
23464
  path: contractsManifestPath,
23216
23465
  present: true,
23217
- sha256: await sha256(contractsManifestPath),
23466
+ sha256: await sha2562(contractsManifestPath),
23218
23467
  version: 1,
23219
23468
  ...arrayLength(parsed.commands) === undefined ? {} : { commands: arrayLength(parsed.commands) },
23220
23469
  ...arrayLength(parsed.routes) === undefined ? {} : { routes: arrayLength(parsed.routes) },
@@ -23237,9 +23486,9 @@ async function assessMigration(options) {
23237
23486
  const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
23238
23487
  openApi = {
23239
23488
  baselinePath,
23240
- baselineSha256: await sha256(baselinePath),
23489
+ baselineSha256: await sha2562(baselinePath),
23241
23490
  currentPath,
23242
- currentSha256: await sha256(currentPath),
23491
+ currentSha256: await sha2562(currentPath),
23243
23492
  diff
23244
23493
  };
23245
23494
  if (!diff.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/compiler",
3
- "version": "0.32.0",
3
+ "version": "0.34.0",
4
4
  "description": "Static compiler for @supacloud/app metadata: builds the application graph from AST, validates it, and generates reflection-free factory code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,7 +54,7 @@
54
54
  "directory": "packages/compiler"
55
55
  },
56
56
  "dependencies": {
57
- "@supacloud/delivery": "0.5.0",
57
+ "@supacloud/delivery": "0.7.0",
58
58
  "typebox": "1.3.34",
59
59
  "@graphql-codegen/core": "^6.2.0",
60
60
  "@graphql-codegen/typed-document-node": "^7.1.0",