@supacloud/compiler 0.31.2 → 0.33.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/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,21 @@ 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
+ allProcedures.push({
2384
+ method: route.method,
2385
+ path: fullPath,
2386
+ controller: controller.className,
2387
+ handler: route.handler,
2388
+ kind: procedureKind,
2389
+ ...command?.name === undefined ? {} : { command: command.name },
2390
+ ...command?.permission === undefined ? {} : { permission: command.permission },
2391
+ idempotency: idempotencyMode
2392
+ });
2378
2393
  routeMethods.push(`
2379
- ${route.handler}: makeRoute<${requestTypeName}, ${responseType === "never" ? "never" : responseTypeName}>(${JSON.stringify(route.method)}, ${JSON.stringify(fullPath)}, ${responseSchemaArgument}, ${responseKindArgument}, ${route.parse === "none"}),`);
2394
+ ${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)}),`);
2380
2395
  }
2381
2396
  controllerEntries.push(`
2382
2397
  ${controllerKey}: {${routeMethods.join("")}
@@ -2407,6 +2422,43 @@ function renderClient(graph, options) {
2407
2422
  "",
2408
2423
  "export type ResponseDecoder<T> = (value: unknown) => T;",
2409
2424
  "",
2425
+ 'export type ProcedureKind = "query" | "mutation";',
2426
+ 'export type IdempotencyMode = "required" | "none";',
2427
+ "",
2428
+ "export interface ProcedureExecutionOptions {",
2429
+ " /** Reuse the same key when retrying an uncertain mutation. */",
2430
+ " idempotencyKey?: string;",
2431
+ " signal?: AbortSignal;",
2432
+ "}",
2433
+ "",
2434
+ "export type RequiredProcedureExecutionOptions = ProcedureExecutionOptions & { idempotencyKey: string };",
2435
+ "",
2436
+ "type ProcedureResult<Result> = [Result] extends [never] ? unknown : Result;",
2437
+ "",
2438
+ "type ProcedureArgs<Options extends ClientRequestOptions, Idempotency extends IdempotencyMode> =",
2439
+ ' Idempotency extends "required"',
2440
+ " ? {} extends Options",
2441
+ " ? [execution: RequiredProcedureExecutionOptions] | [input: Options, execution: RequiredProcedureExecutionOptions]",
2442
+ " : [input: Options, execution: RequiredProcedureExecutionOptions]",
2443
+ " : {} extends Options",
2444
+ " ? [input?: Options, execution?: ProcedureExecutionOptions]",
2445
+ " : [input: Options, execution?: ProcedureExecutionOptions];",
2446
+ "",
2447
+ "export type ProcedureCall<",
2448
+ " Options extends ClientRequestOptions = ClientRequestOptions,",
2449
+ " Result = never,",
2450
+ ' Idempotency extends IdempotencyMode = "none",',
2451
+ "> = (...args: ProcedureArgs<Options, Idempotency>) => Promise<ProcedureResult<Result>>;",
2452
+ "",
2453
+ "export type ProcedureMember<",
2454
+ " Options extends ClientRequestOptions,",
2455
+ " Result,",
2456
+ " Kind extends ProcedureKind,",
2457
+ " Idempotency extends IdempotencyMode,",
2458
+ '> = Kind extends "query"',
2459
+ " ? { query: ProcedureCall<Options, Result, Idempotency> }",
2460
+ " : { mutate: ProcedureCall<Options, Result, Idempotency> };",
2461
+ "",
2410
2462
  'export type ApiClientErrorCode = "API_HTTP_ERROR" | "API_RESPONSE_INVALID" | "API_RESPONSE_UNDECLARED";',
2411
2463
  "",
2412
2464
  "export interface ApiClientErrorDetails {",
@@ -2450,6 +2502,17 @@ function renderClient(graph, options) {
2450
2502
  " : { (options: Options): Promise<Result>; <T>(options: Options, decode: ResponseDecoder<T>): Promise<T> }",
2451
2503
  ") & ((...args: {} extends Options ? [options?: Options] : [options: Options]) => Promise<[Result] extends [never] ? unknown : Result>);",
2452
2504
  "",
2505
+ "export interface ApiProcedureDefinition {",
2506
+ " method: string;",
2507
+ " path: string;",
2508
+ " controller: string;",
2509
+ " handler: string;",
2510
+ " kind: ProcedureKind;",
2511
+ " command?: string;",
2512
+ " permission?: string;",
2513
+ " idempotency: IdempotencyMode;",
2514
+ "}",
2515
+ "",
2453
2516
  ...routeTypes,
2454
2517
  ...routeTypes.length > 0 ? [""] : [],
2455
2518
  "export interface HttpInterceptorRequest {",
@@ -2457,6 +2520,7 @@ function renderClient(graph, options) {
2457
2520
  " url: string;",
2458
2521
  " headers: Record<string, string>;",
2459
2522
  " body?: unknown;",
2523
+ " signal?: AbortSignal;",
2460
2524
  "}",
2461
2525
  "",
2462
2526
  "export type HttpInterceptorFn = (",
@@ -2475,6 +2539,8 @@ function renderClient(graph, options) {
2475
2539
  "",
2476
2540
  "export const API_ROUTES = " + JSON.stringify(allRoutes, null, 2) + " as const;",
2477
2541
  "",
2542
+ "export const API_PROCEDURES: readonly ApiProcedureDefinition[] = " + JSON.stringify(allProcedures, null, 2) + ";",
2543
+ "",
2478
2544
  "export type AppRoutePath = typeof API_ROUTES[number]['path'];",
2479
2545
  "",
2480
2546
  "export const API_SCHEMAS = [",
@@ -2700,6 +2766,7 @@ function renderClient(graph, options) {
2700
2766
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2701
2767
  " responseKind?: string,",
2702
2768
  " raw?: boolean,",
2769
+ " execution?: ProcedureExecutionOptions,",
2703
2770
  " ): Promise<T>;",
2704
2771
  " async function request<T>(",
2705
2772
  " method: string,",
@@ -2709,6 +2776,7 @@ function renderClient(graph, options) {
2709
2776
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2710
2777
  " responseKind?: string,",
2711
2778
  " raw?: boolean,",
2779
+ " execution?: ProcedureExecutionOptions,",
2712
2780
  " ): Promise<T | unknown>;",
2713
2781
  " async function request(",
2714
2782
  " method: string,",
@@ -2723,6 +2791,7 @@ function renderClient(graph, options) {
2723
2791
  ` responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>,`,
2724
2792
  " responseKind?: string,",
2725
2793
  " raw = false,",
2794
+ " execution?: ProcedureExecutionOptions,",
2726
2795
  " ): Promise<T | unknown> {",
2727
2796
  " const url = `${baseUrl}${buildRouteUrl(path, options.params, options.query)}`;",
2728
2797
  ' const customHeaders = typeof config.headers === "function" ? await config.headers() : config.headers;',
@@ -2748,9 +2817,10 @@ function renderClient(graph, options) {
2748
2817
  " headers: reqPayload.headers,",
2749
2818
  " ...(reqPayload.body === undefined ? {} : { body: raw ? rawBody(reqPayload.body) : JSON.stringify(reqPayload.body) }),",
2750
2819
  ' ...(raw && reqPayload.body instanceof ReadableStream ? { duplex: "half" } : {}),',
2820
+ " ...(reqPayload.signal === undefined ? {} : { signal: reqPayload.signal }),",
2751
2821
  " });",
2752
2822
  " };",
2753
- " const response = await executeChain(0, { method, url, headers, body: options.body });",
2823
+ " const response = await executeChain(0, { method, url, headers, body: options.body, ...(execution?.signal === undefined ? {} : { signal: execution.signal }) });",
2754
2824
  " const declaredSchema = responseSchemas ? selectResponseSchema(response.status, responseSchemas) : undefined;",
2755
2825
  " const failure = (code: ApiClientErrorCode, message: string) => new ApiClientError(message, {",
2756
2826
  ' code, method, path, status: response.status, requestId: response.headers.get("x-request-id"),',
@@ -2788,7 +2858,44 @@ function renderClient(graph, options) {
2788
2858
  " return decode ? decode(checked) : checked;",
2789
2859
  " }",
2790
2860
  "",
2791
- ` function makeRoute<Options extends ClientRequestOptions, Result = never>(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false): RouteMethod<Options, Result> {`,
2861
+ " function hasHeader(headers: Record<string, string>, name: string): boolean {",
2862
+ " return Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());",
2863
+ " }",
2864
+ "",
2865
+ " function withProcedureExecution(",
2866
+ " options: ClientRequestOptions,",
2867
+ " execution: ProcedureExecutionOptions | undefined,",
2868
+ " idempotency: IdempotencyMode,",
2869
+ " ): ClientRequestOptions {",
2870
+ " const headers = { ...(options.headers as Record<string, string> | undefined) };",
2871
+ " if (execution?.idempotencyKey !== undefined) {",
2872
+ " if (!/^[A-Za-z0-9._:-]{1,512}$/.test(execution.idempotencyKey)) {",
2873
+ ' throw new TypeError("idempotencyKey must contain only safe header characters and be at most 512 characters");',
2874
+ " }",
2875
+ ' headers["idempotency-key"] = execution.idempotencyKey;',
2876
+ " }",
2877
+ ' if (idempotency === "required" && !hasHeader(headers, "idempotency-key")) {',
2878
+ ' throw new TypeError("This mutation requires an idempotencyKey");',
2879
+ " }",
2880
+ " return Object.keys(headers).length === 0 ? options : { ...options, headers };",
2881
+ " }",
2882
+ "",
2883
+ " function isProcedureExecution(value: unknown): value is ProcedureExecutionOptions {",
2884
+ ' if (value === null || typeof value !== "object" || Array.isArray(value)) return false;',
2885
+ ' return Object.hasOwn(value, "idempotencyKey") || Object.hasOwn(value, "signal");',
2886
+ " }",
2887
+ "",
2888
+ ` function makeProcedure<Options extends ClientRequestOptions, Result = never, Idempotency extends IdempotencyMode = "none">(method: string, path: string, responseSchemas?: Readonly<Record<string, ${responseSchemaType}>>, responseKind?: string, raw = false, idempotency: Idempotency = "none" as Idempotency): ProcedureCall<Options, Result, Idempotency> {`,
2889
+ " const procedure = async (first?: Options | ProcedureExecutionOptions, second?: ProcedureExecutionOptions): Promise<unknown> => {",
2890
+ " const execution = second ?? (isProcedureExecution(first) ? first : undefined);",
2891
+ " const input = (execution === first ? undefined : first) ?? {};",
2892
+ " const requestOptions = withProcedureExecution(input as ClientRequestOptions, execution, idempotency);",
2893
+ " return request(method, path, requestOptions, undefined, responseSchemas, responseKind, raw, execution);",
2894
+ " };",
2895
+ " return procedure as ProcedureCall<Options, Result, Idempotency>;",
2896
+ " }",
2897
+ "",
2898
+ ` 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): RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency> {`,
2792
2899
  " function route<T>(options: Options, decode: ResponseDecoder<T>): Promise<T>;",
2793
2900
  " function route(options: Options): Promise<Result>;",
2794
2901
  " function route(options?: Options): Promise<unknown>;",
@@ -2796,13 +2903,16 @@ function renderClient(graph, options) {
2796
2903
  " const requestOptions = options ?? {};",
2797
2904
  " return request(method, path, requestOptions, decode, responseSchemas, responseKind, raw);",
2798
2905
  " }",
2799
- " return route as RouteMethod<Options, Result>;",
2906
+ ' if (kind === "query") Object.assign(route, { query: makeProcedure<Options, Result, Idempotency>(method, path, responseSchemas, responseKind, raw, idempotency) });',
2907
+ ' if (kind === "mutation") Object.assign(route, { mutate: makeProcedure<Options, Result, Idempotency>(method, path, responseSchemas, responseKind, raw, idempotency) });',
2908
+ " return route as RouteMethod<Options, Result> & ProcedureMember<Options, Result, Kind, Idempotency>;",
2800
2909
  " }",
2801
2910
  "",
2802
2911
  " return {",
2803
2912
  " request,",
2804
2913
  " buildRouteUrl,",
2805
2914
  " routes: API_ROUTES,",
2915
+ " procedures: API_PROCEDURES,",
2806
2916
  ...controllerEntries,
2807
2917
  " };",
2808
2918
  "}",
@@ -15283,6 +15393,65 @@ var init_application_development2 = __esm(() => {
15283
15393
  };
15284
15394
  });
15285
15395
 
15396
+ // node_modules/@supacloud/delivery/src/worker-execution.ts
15397
+ function parseWorkerExecutionGroup(value) {
15398
+ if (!Check2(WorkerExecutionGroupSchema, value) || value.replicas > value.maxReplicas || !value.queue.endsWith(`_v${value.definitionVersion}`) || value.lifecycle.visibilityTimeoutSeconds < value.lifecycle.executionTimeoutSeconds + value.lifecycle.shutdownGraceSeconds + 30) {
15399
+ throw new Error("WORKER_EXECUTION_INVALID");
15400
+ }
15401
+ return structuredClone(value);
15402
+ }
15403
+ function validateWorkerExecution(groups) {
15404
+ const names = new Set, targets = new Set, queues = new Set, routes = new Set;
15405
+ for (const candidate of groups) {
15406
+ const group = parseWorkerExecutionGroup(candidate);
15407
+ const route = `${group.taskKey}:${group.definitionVersion}`;
15408
+ if (names.has(group.name) || targets.has(group.target) || queues.has(group.queue) || routes.has(route)) {
15409
+ throw new Error("WORKER_EXECUTION_CONFLICT");
15410
+ }
15411
+ names.add(group.name);
15412
+ targets.add(group.target);
15413
+ queues.add(group.queue);
15414
+ routes.add(route);
15415
+ }
15416
+ }
15417
+ var closed3, positive = (maximum) => Integer({ minimum: 1, maximum }), WorkerExecutionGroupSchema, WorkerExecutionSchema;
15418
+ var init_worker_execution = __esm(() => {
15419
+ init_build();
15420
+ init_value2();
15421
+ closed3 = { additionalProperties: false };
15422
+ WorkerExecutionGroupSchema = _Object_({
15423
+ name: String2({ pattern: "^[a-z][a-z0-9-]{0,47}$" }),
15424
+ target: String2({ pattern: "^[a-z][a-z0-9-]{0,53}$" }),
15425
+ workloadClass: Union([Literal("interactive"), Literal("batch")]),
15426
+ executor: Literal("pgflow-queue"),
15427
+ runtime: Literal("bun"),
15428
+ queue: String2({ pattern: "^scw_[a-z0-9_]{1,40}$" }),
15429
+ taskKey: String2({ pattern: "^[a-z][a-z0-9_.-]{0,99}$" }),
15430
+ definitionVersion: String2({ pattern: "^[1-9][0-9]{0,8}$" }),
15431
+ replicas: positive(16),
15432
+ maxReplicas: positive(16),
15433
+ concurrencyPerReplica: positive(32),
15434
+ resources: _Object_({
15435
+ cpuLimit: Number2({ minimum: 0.1, maximum: 64, multipleOf: 0.1 }),
15436
+ memoryLimitMiB: Integer({ minimum: 64, maximum: 262144 })
15437
+ }, closed3),
15438
+ database: _Object_({
15439
+ engineConnectionsPerReplica: positive(16),
15440
+ handlerConnectionsPerReplica: positive(16)
15441
+ }, closed3),
15442
+ lifecycle: _Object_({
15443
+ executionTimeoutSeconds: positive(3500),
15444
+ visibilityTimeoutSeconds: Integer({ minimum: 15, maximum: 3600 }),
15445
+ shutdownGraceSeconds: positive(300)
15446
+ }, closed3),
15447
+ retry: _Object_({ maxAttempts: Integer({ minimum: 1, maximum: 10 }) }, closed3),
15448
+ admission: _Object_({ maxOutstandingOperations: positive(1e6) }, closed3)
15449
+ }, closed3);
15450
+ WorkerExecutionSchema = _Object_({
15451
+ groups: _Array_(WorkerExecutionGroupSchema, { minItems: 1, maxItems: 32 })
15452
+ }, closed3);
15453
+ });
15454
+
15286
15455
  // node_modules/@supacloud/delivery/src/delivery-schema.ts
15287
15456
  function parseDeliveryOptions(value) {
15288
15457
  if (value === undefined)
@@ -15290,6 +15459,11 @@ function parseDeliveryOptions(value) {
15290
15459
  if (!Check2(DeliveryOptionsSchema, value))
15291
15460
  throw new DeliveryConfigurationError;
15292
15461
  const migrations = value.build?.migrations ?? [];
15462
+ try {
15463
+ validateWorkerExecution(value.execution?.groups ?? []);
15464
+ } catch {
15465
+ throw new DeliveryConfigurationError;
15466
+ }
15293
15467
  if (new Set(migrations.map((item) => item.version)).size !== migrations.length || new Set(migrations.map((item) => item.source)).size !== migrations.length || migrations.some((item) => BigInt(item.version) > 9223372036854775807n || !/\.sql$/i.test(item.source) || item.source.split("/").includes("node_modules"))) {
15294
15468
  throw new DeliveryConfigurationError;
15295
15469
  }
@@ -15304,6 +15478,7 @@ var objectOptions, reference2, references, kind2, isolation, DeliveryFilePathSch
15304
15478
  var init_delivery_schema = __esm(() => {
15305
15479
  init_build();
15306
15480
  init_value2();
15481
+ init_worker_execution();
15307
15482
  objectOptions = { additionalProperties: false };
15308
15483
  reference2 = String2({ minLength: 1, maxLength: 128, pattern: "^[A-Za-z][A-Za-z0-9_.:/-]*$" });
15309
15484
  references = _Array_(reference2, { uniqueItems: true });
@@ -15315,6 +15490,7 @@ var init_delivery_schema = __esm(() => {
15315
15490
  });
15316
15491
  DeliveryOptionsSchema = _Object_({
15317
15492
  version: Literal(1),
15493
+ execution: Optional(WorkerExecutionSchema),
15318
15494
  targets: Optional(_Array_(_Object_({
15319
15495
  name: String2({ pattern: "^[a-z][a-z0-9-]{0,62}$" }),
15320
15496
  kind: kind2,
@@ -15387,6 +15563,7 @@ var init_delivery_schema = __esm(() => {
15387
15563
  name: String2(),
15388
15564
  kind: kind2,
15389
15565
  isolation,
15566
+ execution: Optional(WorkerExecutionGroupSchema),
15390
15567
  roots: _Array_(String2()),
15391
15568
  modules: _Array_(_Object_({
15392
15569
  name: String2(),
@@ -15602,6 +15779,15 @@ function deliveryObjectDigest(object) {
15602
15779
  function parseDeliveryBuildManifest(value) {
15603
15780
  if (!Check2(DeliveryBuildManifestSchema, value))
15604
15781
  throw new Error("Invalid delivery build manifest.");
15782
+ validateWorkerExecution(value.plan.targets.flatMap((target) => target.execution ? [target.execution] : []));
15783
+ if (value.plan.targets.reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
15784
+ throw new Error("Invalid delivery replica count.");
15785
+ }
15786
+ for (const target of value.plan.targets) {
15787
+ 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")) {
15788
+ throw new Error("Invalid delivery execution binding.");
15789
+ }
15790
+ }
15605
15791
  if (new Set(value.objects.map((item) => item.name)).size !== value.objects.length) {
15606
15792
  throw new Error("Duplicate delivery object owner.");
15607
15793
  }
@@ -15610,7 +15796,7 @@ function parseDeliveryBuildManifest(value) {
15610
15796
  }
15611
15797
  for (const object of value.objects) {
15612
15798
  const target = value.plan.targets.find((target) => target.name === object.name);
15613
- if (object.entryKind === "bun-worker-application" && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
15799
+ if (["bun-worker-application", "go-worker-application", "scriptc-worker-application"].includes(object.entryKind) && target?.kind !== "jobs" || object.entryKind === "bun-http-application" && target?.kind === "jobs") {
15614
15800
  throw new Error("Delivery executable kind does not match its target.");
15615
15801
  }
15616
15802
  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) {
@@ -15631,13 +15817,14 @@ function parseDeliveryBuildResult(value) {
15631
15817
  parseDeliveryBuildManifest(value.manifest);
15632
15818
  return value;
15633
15819
  }
15634
- var closed3, digest2, DeliveryObjectSchema, DeliveryBuildManifestSchema, resultFields, DeliveryBuildResultSchema;
15820
+ var closed4, digest2, DeliveryObjectSchema, DeliveryBuildManifestSchema, resultFields, DeliveryBuildResultSchema;
15635
15821
  var init_delivery_build_schema = __esm(() => {
15636
15822
  init_build();
15637
15823
  init_value2();
15638
15824
  init_delivery_schema();
15639
15825
  init_delivery_files();
15640
- closed3 = { additionalProperties: false };
15826
+ init_worker_execution();
15827
+ closed4 = { additionalProperties: false };
15641
15828
  digest2 = String2({ pattern: "^[a-f0-9]{64}$" });
15642
15829
  DeliveryObjectSchema = _Object_({
15643
15830
  name: String2({ pattern: "^[a-z][a-z0-9-]{0,62}$" }),
@@ -15647,15 +15834,17 @@ var init_delivery_build_schema = __esm(() => {
15647
15834
  entryKind: Union([
15648
15835
  Literal("compiled-module-factory"),
15649
15836
  Literal("bun-http-application"),
15650
- Literal("bun-worker-application")
15837
+ Literal("bun-worker-application"),
15838
+ Literal("go-worker-application"),
15839
+ Literal("scriptc-worker-application")
15651
15840
  ]),
15652
15841
  runtimeImports: _Array_(String2()),
15653
15842
  files: _Array_(_Object_({
15654
15843
  path: DeliveryFilePathSchema,
15655
15844
  sha256: digest2,
15656
15845
  bytes: Integer({ minimum: 0 })
15657
- }, closed3), { minItems: 1 })
15658
- }, closed3);
15846
+ }, closed4), { minItems: 1 })
15847
+ }, closed4);
15659
15848
  DeliveryBuildManifestSchema = _Object_({
15660
15849
  schemaVersion: Literal(1),
15661
15850
  producer: Literal("@supacloud/compiler/delivery-build-v1"),
@@ -15666,9 +15855,9 @@ var init_delivery_build_schema = __esm(() => {
15666
15855
  method: String2(),
15667
15856
  path: String2(),
15668
15857
  target: String2()
15669
- }, closed3)),
15670
- jobs: _Array_(_Object_({ name: String2(), target: String2() }, closed3))
15671
- }, closed3);
15858
+ }, closed4)),
15859
+ jobs: _Array_(_Object_({ name: String2(), target: String2() }, closed4))
15860
+ }, closed4);
15672
15861
  resultFields = {
15673
15862
  diagnostics: _Array_(DeliveryDiagnosticSchema),
15674
15863
  written: _Array_(String2()),
@@ -15682,13 +15871,13 @@ var init_delivery_build_schema = __esm(() => {
15682
15871
  changedTargets: _Array_(String2()),
15683
15872
  unchangedTargets: _Array_(String2()),
15684
15873
  removedTargets: _Array_(String2())
15685
- }, closed3),
15874
+ }, closed4),
15686
15875
  _Object_({
15687
15876
  ...resultFields,
15688
15877
  written: _Array_(String2(), { maxItems: 0 }),
15689
15878
  ok: Literal(false),
15690
15879
  manifest: Null()
15691
- }, closed3)
15880
+ }, closed4)
15692
15881
  ]);
15693
15882
  });
15694
15883
 
@@ -16063,6 +16252,7 @@ var init_application_release = __esm(() => {
16063
16252
  init_build();
16064
16253
  init_value2();
16065
16254
  init_delivery_files();
16255
+ init_worker_execution();
16066
16256
  ApplicationIdSchema = String2({ pattern: "^[A-Za-z0-9_-]{1,64}$" });
16067
16257
  ApplicationReleaseIdSchema = String2({ pattern: "^[a-f0-9]{64}$" });
16068
16258
  ApplicationReleaseRecordSchema = _Object_({
@@ -16076,7 +16266,8 @@ var init_application_release = __esm(() => {
16076
16266
  name: String2({ pattern: "^[a-z][a-z0-9-]{0,62}$" }),
16077
16267
  object_id: ApplicationReleaseIdSchema,
16078
16268
  kind: Union([Literal("http"), Literal("worker")]),
16079
- entrypoint: Literal("bundle/index.js")
16269
+ entrypoint: Literal("bundle/index.js"),
16270
+ execution: Optional(WorkerExecutionGroupSchema)
16080
16271
  }, { additionalProperties: false }), { minItems: 1, maxItems: 32 })
16081
16272
  }, { additionalProperties: false });
16082
16273
  });
@@ -16140,7 +16331,9 @@ var init_application_configuration = __esm(() => {
16140
16331
  "SUPACLOUD_ACTIVATION_ID",
16141
16332
  "SUPACLOUD_ENVIRONMENT_ID",
16142
16333
  "SUPACLOUD_TARGET",
16143
- "SUPACLOUD_OBJECT_ID"
16334
+ "SUPACLOUD_OBJECT_ID",
16335
+ "SUPACLOUD_WORKER_EXECUTION",
16336
+ "SUPACLOUD_WORKER_REPLICA"
16144
16337
  ]);
16145
16338
  });
16146
16339
 
@@ -16174,6 +16367,107 @@ var init_application_activation = __esm(() => {
16174
16367
  }, { additionalProperties: false });
16175
16368
  });
16176
16369
 
16370
+ // node_modules/@supacloud/delivery/src/deployment-evidence.ts
16371
+ var closed6, sha256, isoDate, status, evidenceStatus, DEPLOYMENT_EVIDENCE_SCHEMA = "supacloud.deployment-evidence.v1", DatabaseProviderSchema, componentName, DeploymentComponentEvidenceSchema, DeploymentEvidenceSchema;
16372
+ var init_deployment_evidence = __esm(() => {
16373
+ init_build();
16374
+ init_value2();
16375
+ init_application_configuration();
16376
+ init_application_release();
16377
+ closed6 = { additionalProperties: false };
16378
+ sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
16379
+ isoDate = String2({ minLength: 20, maxLength: 40 });
16380
+ status = Union([
16381
+ Literal("confirmed"),
16382
+ Literal("failed"),
16383
+ Literal("unknown")
16384
+ ]);
16385
+ evidenceStatus = Union([
16386
+ Literal("confirmed"),
16387
+ Literal("failed"),
16388
+ Literal("unknown"),
16389
+ Literal("incomplete")
16390
+ ]);
16391
+ DatabaseProviderSchema = _Object_({
16392
+ provider: String2({ minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9_.-]*$" }),
16393
+ version: String2({ minLength: 1, maxLength: 64 }),
16394
+ topology: Union([Literal("single-node"), Literal("distributed")]),
16395
+ migration: _Object_({
16396
+ status,
16397
+ inventory_sha256: Union([sha256, Null()]),
16398
+ compatibility: Union([
16399
+ Literal("verified"),
16400
+ Literal("not-proven"),
16401
+ Literal("failed")
16402
+ ])
16403
+ }, closed6),
16404
+ backup: _Object_({
16405
+ status,
16406
+ latest_success_at: Union([isoDate, Null()]),
16407
+ freshness_seconds: Union([Integer({ minimum: 0 }), Null()])
16408
+ }, closed6),
16409
+ recovery: _Object_({
16410
+ status,
16411
+ drill_id: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
16412
+ rpo_seconds: Union([Integer({ minimum: 0 }), Null()]),
16413
+ rto_seconds: Union([Integer({ minimum: 0 }), Null()])
16414
+ }, closed6)
16415
+ }, closed6);
16416
+ componentName = Union([
16417
+ Literal("management-api"),
16418
+ Literal("web-console"),
16419
+ Literal("edge-runtime"),
16420
+ Literal("worker"),
16421
+ Literal("postgres"),
16422
+ Literal("postgrest"),
16423
+ Literal("gotrue"),
16424
+ Literal("storage"),
16425
+ Literal("realtime")
16426
+ ]);
16427
+ DeploymentComponentEvidenceSchema = _Object_({
16428
+ name: componentName,
16429
+ version: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
16430
+ status,
16431
+ health_check: Union([String2({ minLength: 1, maxLength: 256 }), Null()]),
16432
+ checked_at: Union([isoDate, Null()])
16433
+ }, closed6);
16434
+ DeploymentEvidenceSchema = _Object_({
16435
+ schema: Literal(DEPLOYMENT_EVIDENCE_SCHEMA),
16436
+ status: evidenceStatus,
16437
+ recorded_at: isoDate,
16438
+ scope: _Object_({
16439
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
16440
+ application_id: ApplicationIdSchema,
16441
+ environment_id: ApplicationIdSchema
16442
+ }, closed6),
16443
+ source: _Object_({
16444
+ commit_sha: Union([String2({ pattern: "^[0-9a-f]{7,64}$" }), Null()]),
16445
+ manifest_sha256: sha256,
16446
+ contract_schema: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
16447
+ environment_binding_version: Union([sha256, Null()])
16448
+ }, closed6),
16449
+ database: DatabaseProviderSchema,
16450
+ components: _Array_(DeploymentComponentEvidenceSchema, { minItems: 1, maxItems: 32 }),
16451
+ activation: _Object_({
16452
+ release_id: ApplicationReleaseIdSchema,
16453
+ configuration_id: ApplicationConfigurationIdSchema,
16454
+ activation_id: ApplicationConfigurationIdSchema
16455
+ }, closed6),
16456
+ health: _Object_({
16457
+ status,
16458
+ checked_at: Union([isoDate, Null()]),
16459
+ authenticated_smoke: status
16460
+ }, closed6),
16461
+ rollback: _Object_({
16462
+ release_id: Union([ApplicationReleaseIdSchema, Null()]),
16463
+ configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
16464
+ status: Union([Literal("ready"), Literal("not-ready"), Literal("unknown")]),
16465
+ result: Union([status, Null()])
16466
+ }, closed6),
16467
+ notes: _Array_(String2({ minLength: 1, maxLength: 512 }), { maxItems: 32 })
16468
+ }, closed6);
16469
+ });
16470
+
16177
16471
  // node_modules/@supacloud/delivery/src/application-runtime-identity.ts
16178
16472
  var APPLICATION_RUNTIME_PROBE_PATH = "/.well-known/supacloud/runtime", ApplicationRuntimeIdentitySchema, ApplicationReadinessReportSchema;
16179
16473
  var init_application_runtime_identity = __esm(() => {
@@ -16292,9 +16586,11 @@ var init_delivery_migration_plan = () => {};
16292
16586
  // node_modules/@supacloud/delivery/src/index.ts
16293
16587
  var init_src = __esm(() => {
16294
16588
  init_delivery_artifact();
16589
+ init_worker_execution();
16295
16590
  init_application_activation();
16296
16591
  init_application_release();
16297
16592
  init_application_configuration();
16593
+ init_deployment_evidence();
16298
16594
  init_application_runtime_identity();
16299
16595
  init_delivery_build_schema();
16300
16596
  init_delivery_migration_archive();
@@ -21352,6 +21648,17 @@ function createDeliveryPlan(graph, input) {
21352
21648
  }
21353
21649
  }
21354
21650
  }
21651
+ for (const group of options.execution?.groups ?? []) {
21652
+ const target = targets.get(group.target);
21653
+ if (!target || target.kind !== "jobs" || target.isolation !== "process" || target.jobs.length !== 1 || target.jobs[0]?.name !== group.taskKey || !options.build?.workerApplications?.some((item) => item.target === group.target)) {
21654
+ fail("delivery-execution-binding-invalid", `Execution group "${group.name}" requires one matching compiled Job and a Worker host.`, "Bind one versioned queue/task to one process-isolated jobs target with build.workerApplications.");
21655
+ } else {
21656
+ target.execution = group;
21657
+ }
21658
+ }
21659
+ if ([...targets.values()].reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
21660
+ fail("delivery-execution-replica-limit", "A release supports at most 32 runtime targets including replicas.", "Reduce the replica count or split independent applications.");
21661
+ }
21355
21662
  const canonicalDiagnostics = [...new Map(diagnostics.map((item) => [JSON.stringify(item), item])).values()].sort((a, b) => compare2(JSON.stringify(a), JSON.stringify(b)));
21356
21663
  if (canonicalDiagnostics.some((item) => item.severity === "error")) {
21357
21664
  return parseDeliveryPlanResult({ ok: false, plan: null, diagnostics: canonicalDiagnostics, written: [] });
@@ -21531,7 +21838,7 @@ function staticDeliveryImports(path, contents) {
21531
21838
  // src/delivery-bundle-protocol.ts
21532
21839
  init_build();
21533
21840
  init_value2();
21534
- var closed4 = { additionalProperties: false };
21841
+ var closed5 = { additionalProperties: false };
21535
21842
  var requestSchema = _Object_({
21536
21843
  parentPid: Integer({ minimum: 1 }),
21537
21844
  name: String2(),
@@ -21539,15 +21846,15 @@ var requestSchema = _Object_({
21539
21846
  project: String2(),
21540
21847
  generatedDirectory: String2(),
21541
21848
  options: DeliveryOptionsSchema
21542
- }, closed4);
21849
+ }, closed5);
21543
21850
  var responseSchema = Union([
21544
21851
  _Object_({
21545
21852
  ok: Literal(true),
21546
21853
  files: _Array_(Tuple([DeliveryFilePathSchema, String2({ pattern: "^[A-Za-z0-9+/]*={0,2}$" })])),
21547
21854
  inputs: _Array_(Tuple([String2(), String2({ pattern: "^[a-f0-9]{64}$" })])),
21548
21855
  runtimeImports: _Array_(String2())
21549
- }, closed4),
21550
- _Object_({ ok: Literal(false) }, closed4)
21856
+ }, closed5),
21857
+ _Object_({ ok: Literal(false) }, closed5)
21551
21858
  ]);
21552
21859
  function parseDeliveryBundleRequest(input) {
21553
21860
  if (!Check2(requestSchema, input))
@@ -21863,6 +22170,7 @@ function renderDeliveryWorkerEntry(generatedDirectory, hostPath) {
21863
22170
  const specifier = relativeImportPath(generatedDirectory, hostPath);
21864
22171
  return `
21865
22172
  import deliveryProcess from "node:process";
22173
+ import { isDeepStrictEqual as deliveryPolicyEqual } from "node:util";
21866
22174
  import { createDeliveryWorker } from ${JSON.stringify(specifier)};
21867
22175
  ${renderDeliveryRuntimeIdentity()}
21868
22176
 
@@ -21870,6 +22178,8 @@ interface DeliveryWorkerHost {
21870
22178
  start(): void | Promise<void>;
21871
22179
  close(): void | Promise<void>;
21872
22180
  failure?: Promise<never>;
22181
+ execution?: unknown;
22182
+ health?(): Promise<{ ready: boolean; active: number; completed: number; failed: number; timedOut: number }>;
21873
22183
  }
21874
22184
 
21875
22185
  {
@@ -21881,6 +22191,7 @@ interface DeliveryWorkerHost {
21881
22191
  let closing: Promise<void> | undefined;
21882
22192
  let deadline: ReturnType<typeof setTimeout> | undefined;
21883
22193
  let keepAlive: ReturnType<typeof setInterval> | undefined;
22194
+ let healthPending = false;
21884
22195
  const finish = (failed: boolean) => {
21885
22196
  clearTimeout(deadline);
21886
22197
  clearInterval(keepAlive);
@@ -21941,6 +22252,13 @@ interface DeliveryWorkerHost {
21941
22252
  const candidate = await createHost(createCompiledModules(), { signal: lifecycle.signal });
21942
22253
  if (!candidate || typeof candidate.close !== "function") throw new Error("Invalid delivery worker host.");
21943
22254
  host = candidate;
22255
+ const execution = deliveryProcess.env.SUPACLOUD_WORKER_EXECUTION;
22256
+ if (execution) {
22257
+ const expected: unknown = JSON.parse(Buffer.from(execution, "base64").toString("utf8"));
22258
+ if (!deliveryPolicyEqual(host.execution, expected) || typeof host.health !== "function" || !host.failure) {
22259
+ throw new Error("Delivery worker execution policy was not adopted.");
22260
+ }
22261
+ }
21944
22262
  if (typeof host.start !== "function") throw new Error("Invalid delivery worker host.");
21945
22263
  if (host.failure !== undefined) {
21946
22264
  if (!host.failure || typeof host.failure.then !== "function") throw new Error("Invalid worker failure signal.");
@@ -21952,7 +22270,18 @@ interface DeliveryWorkerHost {
21952
22270
  await finishShutdown();
21953
22271
  } else {
21954
22272
  running = true;
21955
- keepAlive = setInterval(() => {}, 1000);
22273
+ const health = async () => {
22274
+ if (!execution || !host?.health || healthPending || lifecycle.signal.aborted) return;
22275
+ healthPending = true;
22276
+ try {
22277
+ const status = await host.health();
22278
+ console.log(JSON.stringify({ event: "delivery-worker-health", identity, observedAt: new Date().toISOString(), ...status }));
22279
+ } catch {
22280
+ console.log(JSON.stringify({ event: "delivery-worker-health", identity, observedAt: new Date().toISOString(), ready: false }));
22281
+ } finally { healthPending = false; }
22282
+ };
22283
+ keepAlive = setInterval(() => { void health(); }, execution ? 5000 : 1000);
22284
+ await health();
21956
22285
  console.log(JSON.stringify({ event: "delivery-worker-started", ...(identity ? { identity } : {}) }));
21957
22286
  }
21958
22287
  } catch {
@@ -23296,7 +23625,7 @@ function isRecord2(value) {
23296
23625
  function arrayLength(value) {
23297
23626
  return Array.isArray(value) ? value.length : undefined;
23298
23627
  }
23299
- async function sha256(path) {
23628
+ async function sha2562(path) {
23300
23629
  return createHash10("sha256").update(await readFile11(path)).digest("hex");
23301
23630
  }
23302
23631
  function overallStatus(findings) {
@@ -23370,7 +23699,7 @@ async function assessMigration(options) {
23370
23699
  contractsManifest = {
23371
23700
  path: contractsManifestPath,
23372
23701
  present: true,
23373
- sha256: await sha256(contractsManifestPath),
23702
+ sha256: await sha2562(contractsManifestPath),
23374
23703
  version: 1,
23375
23704
  ...arrayLength(parsed.commands) === undefined ? {} : { commands: arrayLength(parsed.commands) },
23376
23705
  ...arrayLength(parsed.routes) === undefined ? {} : { routes: arrayLength(parsed.routes) },
@@ -23393,9 +23722,9 @@ async function assessMigration(options) {
23393
23722
  const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
23394
23723
  openApi = {
23395
23724
  baselinePath,
23396
- baselineSha256: await sha256(baselinePath),
23725
+ baselineSha256: await sha2562(baselinePath),
23397
23726
  currentPath,
23398
- currentSha256: await sha256(currentPath),
23727
+ currentSha256: await sha2562(currentPath),
23399
23728
  diff
23400
23729
  };
23401
23730
  if (!diff.ok) {