@supacloud/compiler 0.45.1 → 0.46.1

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/index.js CHANGED
@@ -807,12 +807,15 @@ function validateGraph(graph, options = false) {
807
807
  if (typeof options === "object" && options.commandCapabilities) {
808
808
  const hostCaps = options.commandCapabilities;
809
809
  const rpcCaps = command.rpc && Object.hasOwn(hostCaps.rpc ?? {}, command.rpc) ? hostCaps.rpc?.[command.rpc] : undefined;
810
- if (hostCaps.requirePersistentAdapters && (command.rpc !== undefined && (!rpcCaps?.boundary || rpcCaps.audit !== true || rpcCaps.idempotency !== true) || hostCaps.permission !== true || !command.permission || !command.audit || command.idempotency !== "required" || command.rpc !== undefined && rpcCaps?.boundary === "database" && (rpcCaps.transaction !== true || command.transaction !== "required") || command.rpc === undefined && (hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true || command.transaction !== "required"))) {
810
+ if (hostCaps.requirePersistentAdapters && (command.rpc !== undefined && (!rpcCaps?.boundary || rpcCaps.audit !== true || rpcCaps.idempotency !== true) || hostCaps.permission !== true || !command.permission || !command.audit || command.idempotency !== "required" || command.rpc !== undefined && rpcCaps?.boundary === "database" && (rpcCaps.transaction !== true || command.transaction !== "required") || command.rpc === undefined && (hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true || command.transaction !== "required") || command.rpc !== undefined && rpcCaps?.boundary === "external" && rpcCaps.reconcile !== true)) {
811
811
  error("command-persistence-required", `Command ${command.name} requires an explicit persistent adapter, permission, audit and idempotency policy.`, module.file, module.line, "Register a named database/external adapter, enable permission checks and declare permission, audit and required idempotency on the command.");
812
812
  }
813
813
  if (rpcCaps?.boundary === "external" && (command.transaction === "required" || rpcCaps.transaction === true)) {
814
814
  error("command-external-transaction", `Command ${command.name} calls an external service; use durable intent and reconciliation, not transaction: 'required'.`, module.file, module.line, "Use transaction: 'none' with createExternalCommand; recover with read-only reconciliation. Do not claim a database transaction covers a remote request.");
815
815
  }
816
+ if (rpcCaps?.boundary === "external" && rpcCaps.reconcile !== true) {
817
+ error("command-reconcile-required", `Command ${command.name} uses an external adapter without a receipt reconciliation capability.`, module.file, module.line, "Declare reconcile: true only when the adapter can look up the same idempotency key and resolve unknown outcomes without redispatching.");
818
+ }
816
819
  const caps = command.rpc ? {
817
820
  permission: hostCaps.permission,
818
821
  audit: rpcCaps?.audit === true,
@@ -1229,6 +1232,7 @@ var init_validate = __esm(() => {
1229
1232
  "invalid-job-timeout": { code: "SC4015", docsUrl: "https://supacloud.dev/errors/SC4015" },
1230
1233
  "invalid-job-attempts": { code: "SC4016", docsUrl: "https://supacloud.dev/errors/SC4016" },
1231
1234
  "invalid-job-idempotency": { code: "SC4017", docsUrl: "https://supacloud.dev/errors/SC4017" },
1235
+ "job-retry-idempotency-required": { code: "SC4027", docsUrl: "https://supacloud.dev/errors/SC4027" },
1232
1236
  "invalid-job-mode": { code: "SC4018", docsUrl: "https://supacloud.dev/errors/SC4018" },
1233
1237
  "invalid-job-schema": { code: "SC4019", docsUrl: "https://supacloud.dev/errors/SC4019" },
1234
1238
  "command-persistence-required": { code: "SC4020", docsUrl: "https://supacloud.dev/errors/SC4020" },
@@ -1238,6 +1242,7 @@ var init_validate = __esm(() => {
1238
1242
  "command-idempotency-unsupported": { code: "SC4024", docsUrl: "https://supacloud.dev/errors/SC4024" },
1239
1243
  "command-transaction-rpc-only": { code: "SC4025", docsUrl: "https://supacloud.dev/errors/SC4025" },
1240
1244
  "command-transaction-unsupported": { code: "SC4026", docsUrl: "https://supacloud.dev/errors/SC4026" },
1245
+ "command-reconcile-required": { code: "SC4028", docsUrl: "https://supacloud.dev/errors/SC4028" },
1241
1246
  "invalid-route-contract": { code: "SC3020", docsUrl: "https://supacloud.dev/errors/SC3020" },
1242
1247
  "route-contract-required": { code: "SC3021", docsUrl: "https://supacloud.dev/errors/SC3021" },
1243
1248
  "route-contract-unverified": { code: "SC3022", docsUrl: "https://supacloud.dev/errors/SC3022" },
@@ -14557,6 +14562,11 @@ function parseDeliveryOptions(value) {
14557
14562
  if (value.targets?.some((target) => target.compute && target.isolation === "shared")) {
14558
14563
  throw new DeliveryConfigurationError;
14559
14564
  }
14565
+ for (const target of value.targets ?? []) {
14566
+ const invalidShape = target.kind === "function" ? target.function === undefined || target.modules !== undefined || target.compute !== undefined : target.modules === undefined || target.function !== undefined;
14567
+ if (invalidShape)
14568
+ throw new DeliveryConfigurationError;
14569
+ }
14560
14570
  const migrations = value.build?.migrations ?? [];
14561
14571
  try {
14562
14572
  validateWorkerExecution(value.execution?.groups ?? []);
@@ -14573,7 +14583,7 @@ function parseDeliveryPlanResult(value) {
14573
14583
  throw new Error("Invalid delivery plan result.");
14574
14584
  return value;
14575
14585
  }
14576
- var objectOptions, reference, references, kind, isolation, DeliveryFilePathSchema, DeliveryOptionsSchema, DeliveryDiagnosticSchema, routeSchema, jobSchema, DeliveryTargetSchema, DeliveryPlanSchema, DeliveryPlanResultSchema, DeliveryConfigurationError;
14586
+ var objectOptions, reference, references, kind, isolation, DeliveryFilePathSchema, functionTarget, DeliveryOptionsSchema, DeliveryDiagnosticSchema, routeSchema, jobSchema, DeliveryTargetSchema, DeliveryPlanSchema, DeliveryPlanResultSchema, DeliveryConfigurationError;
14577
14587
  var init_delivery_schema = __esm(() => {
14578
14588
  init_build();
14579
14589
  init_value2();
@@ -14581,22 +14591,28 @@ var init_delivery_schema = __esm(() => {
14581
14591
  objectOptions = { additionalProperties: false };
14582
14592
  reference = String2({ minLength: 1, maxLength: 128, pattern: "^[A-Za-z][A-Za-z0-9_.:/-]*$" });
14583
14593
  references = _Array_(reference, { uniqueItems: true });
14584
- kind = Union([Literal("api"), Literal("jobs"), Literal("webhook")]);
14594
+ kind = Union([Literal("api"), Literal("jobs"), Literal("webhook"), Literal("function")]);
14585
14595
  isolation = Union([Literal("shared"), Literal("process")]);
14586
14596
  DeliveryFilePathSchema = String2({
14587
14597
  maxLength: 512,
14588
14598
  pattern: "^(?:[A-Za-z0-9_-][A-Za-z0-9_.-]*/)*[A-Za-z0-9_-][A-Za-z0-9_.-]*$"
14589
14599
  });
14600
+ functionTarget = _Object_({
14601
+ slug: String2({ pattern: "^[a-z][a-z0-9-]{0,62}$" }),
14602
+ entrypoint: DeliveryFilePathSchema,
14603
+ verifyJwt: Boolean2()
14604
+ }, objectOptions);
14590
14605
  DeliveryOptionsSchema = _Object_({
14591
14606
  version: Literal(1),
14592
14607
  execution: Optional(WorkerExecutionSchema),
14593
14608
  targets: Optional(_Array_(_Object_({
14594
14609
  name: String2({ pattern: "^[a-z][a-z0-9-]{0,62}$" }),
14595
14610
  kind,
14596
- modules: _Array_(reference, { minItems: 1, uniqueItems: true }),
14611
+ modules: Optional(_Array_(reference, { minItems: 1, uniqueItems: true })),
14597
14612
  isolation: Optional(isolation),
14598
14613
  capabilities: Optional(references),
14599
- compute: Optional(ComputeResourcesSchema)
14614
+ compute: Optional(ComputeResourcesSchema),
14615
+ function: Optional(functionTarget)
14600
14616
  }, objectOptions))),
14601
14617
  runtime: Optional(_Object_({
14602
14618
  processIsolation: Boolean2(),
@@ -14674,6 +14690,7 @@ var init_delivery_schema = __esm(() => {
14674
14690
  routes: _Array_(routeSchema),
14675
14691
  jobs: _Array_(jobSchema),
14676
14692
  externalTokens: _Array_(String2()),
14693
+ function: Optional(functionTarget),
14677
14694
  requirements: _Object_({
14678
14695
  processIsolation: Boolean2(),
14679
14696
  durableQueue: Boolean2(),
@@ -15059,7 +15076,7 @@ function createContextPack(graph, subject) {
15059
15076
  }
15060
15077
  }
15061
15078
  }
15062
- const modules = graph.modules.filter((module) => selected.has(module.name));
15079
+ const modules = graph.modules.filter((module) => selected.has(module.name)).map(sanitizeContextModule);
15063
15080
  const queryDocuments = graph.graphql?.documents.filter((file) => modules.some((module) => {
15064
15081
  const path = relative6(dirname5(module.file), file);
15065
15082
  return path !== ".." && !path.startsWith(`..${sep6}`);
@@ -15101,7 +15118,12 @@ function createContextPack(graph, subject) {
15101
15118
  singleResult: "async-await",
15102
15119
  eventComposition: "rxjs",
15103
15120
  angularHost: "@supacloud/app/angular",
15104
- cancellation: "explicit-owner-signal"
15121
+ cancellation: "explicit-owner-signal",
15122
+ readTransport: "postgrest-supabase-js",
15123
+ writeTransport: "command-rpc",
15124
+ writeRetry: "disabled",
15125
+ externalOutcome: "receipt-reconcile",
15126
+ databaseSource: "drizzle-append-only"
15105
15127
  },
15106
15128
  relatedModules: {
15107
15129
  imports: subjectModule.imports.filter((name) => selected.has(name)),
@@ -15109,6 +15131,44 @@ function createContextPack(graph, subject) {
15109
15131
  }
15110
15132
  };
15111
15133
  }
15134
+ function sanitizeContextModule(module) {
15135
+ const sanitizeAspect = (aspect) => ({
15136
+ ...aspect,
15137
+ expression: "[omitted]"
15138
+ });
15139
+ return {
15140
+ ...module,
15141
+ providers: module.providers.map((provider) => ({
15142
+ ...provider,
15143
+ ...provider.useValueExpr === undefined ? {} : { useValueExpr: "[omitted]" },
15144
+ ...provider.useFactoryName === undefined ? {} : { useFactoryName: "[omitted]" },
15145
+ ...provider.functionalInjects === undefined ? {} : {
15146
+ functionalInjects: provider.functionalInjects.map((inject) => ({ ...inject, expression: "[omitted]" }))
15147
+ }
15148
+ })),
15149
+ ...module.aspects === undefined ? {} : { aspects: module.aspects.map(sanitizeAspect) },
15150
+ controllers: module.controllers.map((controller) => ({
15151
+ ...controller,
15152
+ ...controller.functionalInjects === undefined ? {} : {
15153
+ functionalInjects: controller.functionalInjects.map((inject) => ({ ...inject, expression: "[omitted]" }))
15154
+ },
15155
+ routes: controller.routes.map((route) => ({
15156
+ ...route,
15157
+ ...route.aspects === undefined ? {} : { aspects: route.aspects.map(sanitizeAspect) }
15158
+ }))
15159
+ })),
15160
+ commands: module.commands.map((command) => ({
15161
+ ...command,
15162
+ ...command.aspects === undefined ? {} : { aspects: command.aspects.map(sanitizeAspect) }
15163
+ })),
15164
+ ...module.jobs === undefined ? {} : {
15165
+ jobs: module.jobs.map((job) => ({
15166
+ ...job,
15167
+ ...job.aspects === undefined ? {} : { aspects: job.aspects.map(sanitizeAspect) }
15168
+ }))
15169
+ }
15170
+ };
15171
+ }
15112
15172
  function resolveContextModule(graph, subject) {
15113
15173
  const exact = graph.modules.find((module) => module.name === subject);
15114
15174
  if (exact)
@@ -16425,8 +16485,172 @@ var init_deployment_evidence = __esm(() => {
16425
16485
  }, closed8);
16426
16486
  });
16427
16487
 
16488
+ // node_modules/@supacloud/delivery/src/delivery-tuple.ts
16489
+ var sha2563, commit, isoDate2, DELIVERY_TUPLE_SCHEMA = "supacloud.fa-delivery-tuple.v1", FaDeliveryTupleSchema;
16490
+ var init_delivery_tuple = __esm(() => {
16491
+ init_build();
16492
+ init_value2();
16493
+ sha2563 = String2({ pattern: "^[a-f0-9]{64}$" });
16494
+ commit = String2({ pattern: "^(?:[a-f0-9]{40}|[a-f0-9]{64})$" });
16495
+ isoDate2 = String2({ minLength: 20, maxLength: 40 });
16496
+ FaDeliveryTupleSchema = _Object_({
16497
+ schema: Literal(DELIVERY_TUPLE_SCHEMA),
16498
+ customer: Literal("xigu-fa"),
16499
+ fa_commit: commit,
16500
+ cli: _Object_({
16501
+ version: String2({ pattern: "^\\d+\\.\\d+\\.\\d+$" })
16502
+ }, { additionalProperties: false }),
16503
+ platform_commit: commit,
16504
+ edge_runtime: _Object_({
16505
+ version: String2({ minLength: 1, maxLength: 128 }),
16506
+ artifact_sha256: sha2563
16507
+ }, { additionalProperties: false }),
16508
+ compatibility_window: _Object_({
16509
+ contract_schema: String2({ minLength: 1, maxLength: 128 }),
16510
+ starts_at: isoDate2,
16511
+ ends_at: isoDate2,
16512
+ old_client_supported: Boolean2(),
16513
+ partial_deployment_supported: Boolean2()
16514
+ }, { additionalProperties: false })
16515
+ }, { additionalProperties: false });
16516
+ });
16517
+
16518
+ // node_modules/@supacloud/delivery/src/contract-matrix.ts
16519
+ var closed9, sha2564, generation, versions, CONTRACT_MATRIX_SCHEMA = "supacloud.consumer-contract-matrix.v1", FA_CONTRACT_SCENARIOS, ConsumerContractMatrixSchema;
16520
+ var init_contract_matrix = __esm(() => {
16521
+ init_build();
16522
+ init_value2();
16523
+ closed9 = { additionalProperties: false };
16524
+ sha2564 = String2({ pattern: "^[a-f0-9]{64}$" });
16525
+ generation = Union([Literal("old"), Literal("new")]);
16526
+ versions = _Object_({ old: sha2564, new: sha2564 }, closed9);
16527
+ FA_CONTRACT_SCENARIOS = [
16528
+ "missing-display-field",
16529
+ "missing-authority-field",
16530
+ "added-field",
16531
+ "legacy-envelope",
16532
+ "lost-write-response",
16533
+ "downgrade"
16534
+ ];
16535
+ ConsumerContractMatrixSchema = _Object_({
16536
+ schema: Literal(CONTRACT_MATRIX_SCHEMA),
16537
+ customer: Literal("xigu-fa"),
16538
+ baseline_tuple_sha256: sha2564,
16539
+ candidate_tuple_sha256: sha2564,
16540
+ artifacts: _Object_({ frontend: versions, functions: versions, database: versions }, closed9),
16541
+ cases: _Array_(_Object_({
16542
+ frontend: generation,
16543
+ functions: generation,
16544
+ database: generation,
16545
+ scenarios: _Array_(_Object_({
16546
+ name: Enum(FA_CONTRACT_SCENARIOS),
16547
+ expected: Union([Literal("compatible"), Literal("blocked-safely")])
16548
+ }, closed9), { minItems: FA_CONTRACT_SCENARIOS.length, maxItems: FA_CONTRACT_SCENARIOS.length })
16549
+ }, closed9), { minItems: 8, maxItems: 8 })
16550
+ }, closed9);
16551
+ });
16552
+
16553
+ // node_modules/@supacloud/delivery/src/fa-stability.ts
16554
+ var closed10, hash3, label, timestamp2, count2, environment2, FA_REQUIRED_ACCEPTANCE, FA_BUSINESS_OPERATIONS, operation, proof, FaBusinessObservationSchema, FaServiceObjectivesSchema, FaStabilityEvidenceSchema;
16555
+ var init_fa_stability = __esm(() => {
16556
+ init_build();
16557
+ init_value2();
16558
+ init_delivery_files();
16559
+ init_contract_matrix();
16560
+ init_delivery_tuple();
16561
+ closed10 = { additionalProperties: false };
16562
+ hash3 = String2({ pattern: "^[a-f0-9]{64}$" });
16563
+ label = String2({ minLength: 1, maxLength: 256, pattern: "\\S" });
16564
+ timestamp2 = String2({ minLength: 24, maxLength: 24 });
16565
+ count2 = Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER });
16566
+ environment2 = Union([Literal("test"), Literal("production")]);
16567
+ FA_REQUIRED_ACCEPTANCE = {
16568
+ login: "real-browser",
16569
+ permissions: "real-http",
16570
+ upload: "real-http",
16571
+ "async-task": "real-worker",
16572
+ deploy: "real-http",
16573
+ "database-migration": "real-database",
16574
+ schedule: "real-worker",
16575
+ rollback: "real-drill",
16576
+ "error-policy": "real-http",
16577
+ "alert-delivery": "real-drill"
16578
+ };
16579
+ FA_BUSINESS_OPERATIONS = ["login", "permissions", "upload", "async-task", "report", "deploy"];
16580
+ operation = Enum(FA_BUSINESS_OPERATIONS);
16581
+ proof = _Object_({
16582
+ path: String2({ pattern: "^[A-Za-z0-9_-][A-Za-z0-9_./-]{0,255}$" }),
16583
+ sha256: hash3
16584
+ }, closed10);
16585
+ FaBusinessObservationSchema = _Object_({
16586
+ id: String2({ pattern: "^[A-Za-z0-9_-]{1,128}$" }),
16587
+ tuple_sha256: hash3,
16588
+ operation,
16589
+ started_at: timestamp2,
16590
+ finished_at: timestamp2,
16591
+ outcome: Enum(["success", "failure", "timeout", "unknown"]),
16592
+ attempts: Integer({ minimum: 1, maximum: 1000 }),
16593
+ rollbacks: count2
16594
+ }, closed10);
16595
+ FaServiceObjectivesSchema = _Object_({
16596
+ status: Literal("approved"),
16597
+ owner: label,
16598
+ approval_reference: label,
16599
+ approved_at: timestamp2,
16600
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
16601
+ environment: environment2,
16602
+ alert_route: label,
16603
+ window_hours: Number2({ exclusiveMinimum: 0, maximum: 8760 }),
16604
+ max_evidence_age_hours: Number2({ exclusiveMinimum: 0, maximum: 168 }),
16605
+ operations: _Array_(_Object_({
16606
+ operation,
16607
+ minimum_samples: Integer({ minimum: 1, maximum: Number.MAX_SAFE_INTEGER }),
16608
+ availability_percent: Number2({ exclusiveMinimum: 0, maximum: 100 }),
16609
+ p95_ms: Number2({ exclusiveMinimum: 0, maximum: Number.MAX_SAFE_INTEGER })
16610
+ }, closed10), { minItems: FA_BUSINESS_OPERATIONS.length, maxItems: FA_BUSINESS_OPERATIONS.length })
16611
+ }, closed10);
16612
+ FaStabilityEvidenceSchema = _Object_({
16613
+ schema: Literal("supacloud.fa-stability-evidence.v1"),
16614
+ environment: environment2,
16615
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
16616
+ tuple_sha256: hash3,
16617
+ matrix_sha256: hash3,
16618
+ objectives_sha256: hash3,
16619
+ recorded_at: timestamp2,
16620
+ window_start: timestamp2,
16621
+ window_end: timestamp2,
16622
+ reviewed_by: label,
16623
+ review_reference: label,
16624
+ acceptance: _Array_(_Object_({
16625
+ id: Enum(Object.keys(FA_REQUIRED_ACCEPTANCE)),
16626
+ execution: Enum([
16627
+ "real-browser",
16628
+ "real-http",
16629
+ "real-worker",
16630
+ "real-database",
16631
+ "real-drill",
16632
+ "local-fake"
16633
+ ]),
16634
+ passed: Boolean2(),
16635
+ measured_at: timestamp2,
16636
+ proof
16637
+ }, closed10), { minItems: 10, maxItems: 10 }),
16638
+ matrix: _Array_(_Object_({
16639
+ combination: label,
16640
+ scenario: label,
16641
+ outcome: Union([Literal("compatible"), Literal("blocked-safely")]),
16642
+ execution: Union([Literal("real-http-and-database"), Literal("local-fake")]),
16643
+ passed: Boolean2(),
16644
+ measured_at: timestamp2,
16645
+ proof
16646
+ }, closed10), { minItems: 48, maxItems: 48 }),
16647
+ observation: proof,
16648
+ alert: _Object_({ route: label, acknowledged_by: label, delivered_at: timestamp2 }, closed10)
16649
+ }, closed10);
16650
+ });
16651
+
16428
16652
  // node_modules/@supacloud/delivery/src/application-promotion.ts
16429
- var closed9, projectRef2, sha2563, nullableActivation2, nullableDigest, observation, blocker, ApplicationPromotionPlanSchema;
16653
+ var closed11, projectRef2, sha2565, nullableActivation2, nullableDigest, observation, blocker, ApplicationPromotionPlanSchema;
16430
16654
  var init_application_promotion = __esm(() => {
16431
16655
  init_build();
16432
16656
  init_value2();
@@ -16434,11 +16658,11 @@ var init_application_promotion = __esm(() => {
16434
16658
  init_application_activation();
16435
16659
  init_application_configuration();
16436
16660
  init_application_release();
16437
- closed9 = { additionalProperties: false };
16661
+ closed11 = { additionalProperties: false };
16438
16662
  projectRef2 = String2({ pattern: "^[a-z0-9-]{1,20}$" });
16439
- sha2563 = ApplicationReleaseIdSchema;
16663
+ sha2565 = ApplicationReleaseIdSchema;
16440
16664
  nullableActivation2 = Union([ApplicationActivationIdSchema, Null()]);
16441
- nullableDigest = Union([sha2563, Null()]);
16665
+ nullableDigest = Union([sha2565, Null()]);
16442
16666
  observation = {
16443
16667
  activation_id: nullableActivation2,
16444
16668
  receipt_confirmed: Boolean2(),
@@ -16464,33 +16688,33 @@ var init_application_promotion = __esm(() => {
16464
16688
  project_ref: projectRef2,
16465
16689
  application_id: ApplicationIdSchema,
16466
16690
  environment_id: ApplicationIdSchema,
16467
- manifest_sha256: sha2563,
16468
- plan_sha256: sha2563,
16691
+ manifest_sha256: sha2565,
16692
+ plan_sha256: sha2565,
16469
16693
  source: _Object_({
16470
16694
  project_ref: projectRef2,
16471
16695
  environment_id: ApplicationIdSchema,
16472
- release_id: sha2563,
16696
+ release_id: sha2565,
16473
16697
  ...observation
16474
- }, closed9),
16698
+ }, closed11),
16475
16699
  target: _Object_({
16476
- candidate_release_id: sha2563,
16477
- current_release_id: Union([sha2563, Null()]),
16700
+ candidate_release_id: sha2565,
16701
+ current_release_id: Union([sha2565, Null()]),
16478
16702
  artifact_action: Union([Literal("materialize"), Literal("reuse")]),
16479
16703
  configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
16480
16704
  configuration: Union([ApplicationConfigurationViewSchema, Null()]),
16481
16705
  ...observation
16482
- }, closed9),
16706
+ }, closed11),
16483
16707
  migrations: _Object_({
16484
- ledger_digest: sha2563,
16708
+ ledger_digest: sha2565,
16485
16709
  ledger_compatible: Boolean2(),
16486
16710
  project_migrations_applied: Boolean2(),
16487
16711
  pending_versions: _Array_(String2({ pattern: "^\\d{1,20}$" }), { maxItems: 4096, uniqueItems: true }),
16488
16712
  operator_provisioning_required: Boolean2()
16489
- }, closed9),
16713
+ }, closed11),
16490
16714
  backup: _Object_({
16491
16715
  required: Boolean2(),
16492
16716
  confirmed: Literal(false)
16493
- }, closed9),
16717
+ }, closed11),
16494
16718
  action: Union([Literal("promote"), Literal("no-op"), Literal("blocked")]),
16495
16719
  blockers: _Array_(Enum([...blocker]), {
16496
16720
  maxItems: blocker.length,
@@ -16499,7 +16723,7 @@ var init_application_promotion = __esm(() => {
16499
16723
  steps: _Array_(String2({ minLength: 1, maxLength: 64 }), { maxItems: 8, uniqueItems: true }),
16500
16724
  execution_performed: Literal(false),
16501
16725
  data_recovery: Literal("separate-required")
16502
- }, closed9);
16726
+ }, closed11);
16503
16727
  });
16504
16728
 
16505
16729
  // node_modules/@supacloud/delivery/src/application-runtime-identity.ts
@@ -16631,6 +16855,9 @@ var init_src = __esm(() => {
16631
16855
  init_application_release_transfer();
16632
16856
  init_application_configuration();
16633
16857
  init_deployment_evidence();
16858
+ init_delivery_tuple();
16859
+ init_contract_matrix();
16860
+ init_fa_stability();
16634
16861
  init_application_promotion();
16635
16862
  init_application_runtime_identity();
16636
16863
  init_delivery_build_schema();
@@ -17377,7 +17604,7 @@ import { createHash as createHash12 } from "node:crypto";
17377
17604
  import { mkdir as mkdir6, readFile as readFile14 } from "node:fs/promises";
17378
17605
  import { dirname as dirname12, relative as relative12, resolve as resolve24 } from "node:path";
17379
17606
  import * as ts18 from "@typescript/typescript6";
17380
- function hash3(value) {
17607
+ function hash4(value) {
17381
17608
  return createHash12("sha256").update(value).digest("hex");
17382
17609
  }
17383
17610
  function importPath(out, path) {
@@ -17443,7 +17670,7 @@ async function generateDatabaseContracts(options, check = false) {
17443
17670
  const inputs = {};
17444
17671
  const addInput = async (path) => {
17445
17672
  const absolute = resolve24(rootDir, path);
17446
- inputs[relative12(rootDir, absolute).replaceAll("\\", "/")] = hash3(await readFile14(absolute, "utf8"));
17673
+ inputs[relative12(rootDir, absolute).replaceAll("\\", "/")] = hash4(await readFile14(absolute, "utf8"));
17447
17674
  };
17448
17675
  await addInput(postgrestTypes);
17449
17676
  await addInput(drizzleSchema);
@@ -17482,7 +17709,7 @@ async function generateDatabaseContracts(options, check = false) {
17482
17709
  role: options.role,
17483
17710
  inputs: Object.fromEntries(Object.entries(inputs).sort(([a], [b]) => a.localeCompare(b))),
17484
17711
  migrationOrder: options.migrations.map((path) => relative12(rootDir, resolve24(rootDir, path)).replaceAll("\\", "/")),
17485
- outputs: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)).map(([file, text]) => [file, hash3(text)]))
17712
+ outputs: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)).map(([file, text]) => [file, hash4(text)]))
17486
17713
  };
17487
17714
  files["database.manifest.json"] = JSON.stringify(manifest, null, 2) + `
17488
17715
  `;
@@ -21104,9 +21331,25 @@ import * as ts9 from "@typescript/typescript6";
21104
21331
  var SOURCE_SEMANTIC_DIAGNOSTIC_CODES = {
21105
21332
  "source-unsafe-any": { errorCode: "SC6009", docsUrl: "https://supacloud.dev/errors/SC6009" },
21106
21333
  "source-floating-promise": { errorCode: "SC6010", docsUrl: "https://supacloud.dev/errors/SC6010" },
21107
- "source-non-exhaustive-switch": { errorCode: "SC6011", docsUrl: "https://supacloud.dev/errors/SC6011" }
21334
+ "source-non-exhaustive-switch": { errorCode: "SC6011", docsUrl: "https://supacloud.dev/errors/SC6011" },
21335
+ "source-alternative-library": { errorCode: "SC6012", docsUrl: "https://supacloud.dev/errors/SC6012" }
21108
21336
  };
21109
- function scanSourceSemantics(source, checker, file, rootDir) {
21337
+ var DEFAULT_ALTERNATIVE_LIBRARIES = [
21338
+ "@apollo/client",
21339
+ "@urql/core",
21340
+ "graphql-request",
21341
+ "kefir",
21342
+ "most",
21343
+ "@pgflow",
21344
+ "pgflow",
21345
+ "pg_durable",
21346
+ "react-relay",
21347
+ "redux-observable",
21348
+ "urql",
21349
+ "wonka",
21350
+ "xstream"
21351
+ ];
21352
+ function scanSourceSemantics(source, checker, file, rootDir, options = {}) {
21110
21353
  const diagnostics = [];
21111
21354
  const report = (code, node, message) => {
21112
21355
  diagnostics.push({
@@ -21118,6 +21361,16 @@ function scanSourceSemantics(source, checker, file, rootDir) {
21118
21361
  line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1
21119
21362
  });
21120
21363
  };
21364
+ const allowedLibraries = new Set(options.allowAlternativeLibraries ?? []);
21365
+ for (const statement of source.statements) {
21366
+ if (!ts9.isImportDeclaration(statement) || !ts9.isStringLiteral(statement.moduleSpecifier))
21367
+ continue;
21368
+ const moduleName = statement.moduleSpecifier.text;
21369
+ const alternative = DEFAULT_ALTERNATIVE_LIBRARIES.find((name) => moduleName === name || moduleName.startsWith(`${name}/`));
21370
+ if (alternative && !allowedLibraries.has(alternative) && !allowedLibraries.has(moduleName)) {
21371
+ report("source-alternative-library", statement.moduleSpecifier, `Production source imports alternative library "${moduleName}". Use the governed Supabase client/PostgREST transport and RxJS event composition by default, or allow this package explicitly in typeSafety.allowAlternativeLibraries for a documented boundary.`);
21372
+ }
21373
+ }
21121
21374
  const unsafe = (value, target) => {
21122
21375
  if (isUnknownBoundary(target, checker) || containsAny(target, checker, new Set, rootDir))
21123
21376
  return;
@@ -21398,7 +21651,7 @@ function scanProductionSource(options) {
21398
21651
  }
21399
21652
  for (const sourceFile of sourceFiles) {
21400
21653
  scanSourceFile(sourceFile, checker, rootDir, diagnostics, options.strict ?? false);
21401
- diagnostics.push(...scanSourceSemantics(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), rootDir));
21654
+ diagnostics.push(...scanSourceSemantics(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), rootDir, options.allowAlternativeLibraries === undefined ? {} : { allowAlternativeLibraries: options.allowAlternativeLibraries }));
21402
21655
  diagnostics.push(...scanDrizzleSql(sourceFile, checker, normalizeRelative(rootDir, sourceFile.fileName), options.strict ?? false));
21403
21656
  const scanner = ts10.createScanner(ts10.ScriptTarget.Latest, false, sourceFile.languageVariant, sourceFile.text);
21404
21657
  for (let kind = scanner.scan();kind !== ts10.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
@@ -21660,6 +21913,17 @@ function validateEffectPolicies(graph, options = {}) {
21660
21913
  }
21661
21914
  return diagnostics;
21662
21915
  }
21916
+ function validateJobPolicies(graph) {
21917
+ const diagnostics = [];
21918
+ for (const module of graph.modules) {
21919
+ for (const job of module.jobs ?? []) {
21920
+ if (job.maxAttempts !== undefined && job.maxAttempts > 1 && job.idempotency !== "required") {
21921
+ diagnostics.push(diagnostic("job-retry-idempotency-required", `Job ${job.name} (${job.className}) enables ${job.maxAttempts} attempts without an idempotency contract.`, module.file, 'Use idempotency: "required" with a durable receipt, or set maxAttempts: 1.'));
21922
+ }
21923
+ }
21924
+ }
21925
+ return diagnostics;
21926
+ }
21663
21927
 
21664
21928
  // src/database-governance.ts
21665
21929
  import { execFile } from "node:child_process";
@@ -21709,13 +21973,19 @@ async function checkDatabaseGovernance(rootDir, value) {
21709
21973
 
21710
21974
  // src/compile.ts
21711
21975
  function withDefaultGovernance(options) {
21712
- return options.commandCapabilities === undefined ? { ...options, commandCapabilities: {
21713
- requirePersistentAdapters: true,
21714
- permission: true,
21715
- audit: true,
21716
- idempotency: true,
21717
- transaction: true
21718
- } } : options;
21976
+ return {
21977
+ ...options,
21978
+ requireRouteContracts: options.requireRouteContracts ?? true,
21979
+ disallowControllerDirectDb: options.disallowControllerDirectDb ?? true,
21980
+ detectOrphanModules: options.detectOrphanModules ?? true,
21981
+ ...options.commandCapabilities === undefined ? { commandCapabilities: {
21982
+ requirePersistentAdapters: true,
21983
+ permission: true,
21984
+ audit: true,
21985
+ idempotency: true,
21986
+ transaction: true
21987
+ } } : {}
21988
+ };
21719
21989
  }
21720
21990
  async function renderOptionalGraphql(options) {
21721
21991
  return options.graphql ? (await Promise.resolve().then(() => (init_graphql(), exports_graphql))).renderGraphql(options) : { diagnostics: [], files: {} };
@@ -21727,7 +21997,8 @@ async function compileProject(options) {
21727
21997
  ...graph.diagnostics ?? [],
21728
21998
  ...validateGraph(graph, options),
21729
21999
  ...validateClientSchemaBoundaries(graph, options),
21730
- ...validateEffectPolicies(graph, options.effect)
22000
+ ...validateEffectPolicies(graph, options.effect),
22001
+ ...validateJobPolicies(graph)
21731
22002
  ];
21732
22003
  const databaseDiagnostics = await checkDatabaseGovernance(options.rootDir, options.databaseGovernance);
21733
22004
  diagnostics.push(...databaseDiagnostics);
@@ -21797,7 +22068,8 @@ async function checkProject(options) {
21797
22068
  ...graph.diagnostics ?? [],
21798
22069
  ...validateGraph(graph, options),
21799
22070
  ...validateClientSchemaBoundaries(graph, options),
21800
- ...validateEffectPolicies(graph, options.effect)
22071
+ ...validateEffectPolicies(graph, options.effect),
22072
+ ...validateJobPolicies(graph)
21801
22073
  ];
21802
22074
  const databaseDiagnostics = await checkDatabaseGovernance(options.rootDir, options.databaseGovernance);
21803
22075
  diagnostics.push(...databaseDiagnostics);
@@ -21877,7 +22149,8 @@ function resolveTypeSafety(options) {
21877
22149
  return {
21878
22150
  noAnyInGenerated: true,
21879
22151
  scanProductionSource: true,
21880
- ...options.typeSafety?.exclude ? { exclude: options.typeSafety.exclude } : {}
22152
+ ...options.typeSafety?.exclude ? { exclude: options.typeSafety.exclude } : {},
22153
+ ...options.typeSafety?.allowAlternativeLibraries ? { allowAlternativeLibraries: options.typeSafety.allowAlternativeLibraries } : {}
21881
22154
  };
21882
22155
  }
21883
22156
 
@@ -21932,7 +22205,7 @@ function createDeliveryPlan(graph, input, validation) {
21932
22205
  if (target.name === "api" && target.kind !== "api" || target.name === "jobs" && target.kind !== "jobs") {
21933
22206
  fail("delivery-reserved-target", `"${target.name}" is reserved for its matching workload kind.`, "Rename the target or use the matching kind.");
21934
22207
  }
21935
- for (const name of sorted(target.modules)) {
22208
+ for (const name of sorted(target.modules ?? [])) {
21936
22209
  if (!modules.has(name)) {
21937
22210
  fail("delivery-unknown-module", `Target "${target.name}" refers to unknown module "${name}".`, "Select a module name from the compiler graph.");
21938
22211
  continue;
@@ -21946,6 +22219,23 @@ function createDeliveryPlan(graph, input, validation) {
21946
22219
  }
21947
22220
  }
21948
22221
  const targets = new Map;
22222
+ for (const declaration of declarations.values()) {
22223
+ if (declaration.kind !== "function" || declaration.function === undefined)
22224
+ continue;
22225
+ targets.set(declaration.name, {
22226
+ name: declaration.name,
22227
+ kind: "function",
22228
+ isolation: "shared",
22229
+ roots: [],
22230
+ modules: [],
22231
+ routes: [],
22232
+ jobs: [],
22233
+ externalTokens: [],
22234
+ function: declaration.function,
22235
+ requirements: { processIsolation: false, durableQueue: false, capabilities: sorted(declaration.capabilities ?? []) },
22236
+ runtimeStatus: options.runtime === undefined ? "unchecked" : "declared-compatible"
22237
+ });
22238
+ }
21949
22239
  function getTarget(name, fallback) {
21950
22240
  const existing = targets.get(name);
21951
22241
  if (existing)
@@ -22814,6 +23104,14 @@ async function buildDeliveryProject(options, delivery) {
22814
23104
  const planned = createDeliveryPlan({ ...checked.graph, diagnostics: checked.diagnostics }, settings, options);
22815
23105
  if (!planned.ok)
22816
23106
  return failed(planned.diagnostics);
23107
+ if (planned.plan.targets.some((target) => target.kind === "function")) {
23108
+ return failed([{
23109
+ severity: "error",
23110
+ code: "delivery-function-build-unsupported",
23111
+ message: "Function target rendering is not implemented yet; the delivery build only produces HTTP and Worker application objects.",
23112
+ suggestion: "Declare HTTP/Worker application targets for now; Function and schedule delivery is tracked separately."
23113
+ }]);
23114
+ }
22817
23115
  if (options.graphql && checked.mismatches.some((mismatch) => mismatch.startsWith("graphql"))) {
22818
23116
  throw new Error("Refresh GraphQL artifacts with compile before building independent targets.");
22819
23117
  }
@@ -23767,10 +24065,10 @@ import { readFileSync as readFileSync4 } from "node:fs";
23767
24065
  import { resolve as resolve17 } from "node:path";
23768
24066
 
23769
24067
  // src/migration-app-version.ts
23770
- var MIGRATION_APP_VERSION = "0.26.1";
24068
+ var MIGRATION_APP_VERSION = "0.27.0";
23771
24069
 
23772
24070
  // src/migration-elysia-version.ts
23773
- var MIGRATION_ELYSIA_VERSION = "0.29.2";
24071
+ var MIGRATION_ELYSIA_VERSION = "0.30.0";
23774
24072
 
23775
24073
  // src/migration-policy.ts
23776
24074
  var cachedCompilerVersion;
@@ -24739,7 +25037,7 @@ function isRecord2(value) {
24739
25037
  function arrayLength(value) {
24740
25038
  return Array.isArray(value) ? value.length : undefined;
24741
25039
  }
24742
- async function sha2564(path) {
25040
+ async function sha2566(path) {
24743
25041
  return createHash11("sha256").update(await readFile11(path)).digest("hex");
24744
25042
  }
24745
25043
  function overallStatus(findings) {
@@ -24816,7 +25114,7 @@ async function assessMigration(options) {
24816
25114
  contractsManifest = {
24817
25115
  path: contractsManifestPath,
24818
25116
  present: true,
24819
- sha256: await sha2564(contractsManifestPath),
25117
+ sha256: await sha2566(contractsManifestPath),
24820
25118
  version: 1,
24821
25119
  ...commands === undefined ? {} : { commands },
24822
25120
  ...routes === undefined ? {} : { routes },
@@ -24839,9 +25137,9 @@ async function assessMigration(options) {
24839
25137
  const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
24840
25138
  openApi = {
24841
25139
  baselinePath,
24842
- baselineSha256: await sha2564(baselinePath),
25140
+ baselineSha256: await sha2566(baselinePath),
24843
25141
  currentPath,
24844
- currentSha256: await sha2564(currentPath),
25142
+ currentSha256: await sha2566(currentPath),
24845
25143
  diff
24846
25144
  };
24847
25145
  if (!diff.ok) {
@@ -24932,11 +25230,13 @@ var DEFAULT_SUPACLOUD_CONFIG = {
24932
25230
  outDir: "generated",
24933
25231
  include: ["**/*.module.ts", "**/*.ts"],
24934
25232
  strict: true,
24935
- requireRouteContracts: false,
25233
+ requireRouteContracts: true,
24936
25234
  generateClient: true,
24937
25235
  generateOpenApi: true,
24938
25236
  generatePermissions: true,
24939
25237
  treeShakeUnusedProviders: true,
25238
+ disallowControllerDirectDb: true,
25239
+ detectOrphanModules: true,
24940
25240
  commandCapabilities: {
24941
25241
  requirePersistentAdapters: true,
24942
25242
  permission: true,
@@ -24991,9 +25291,9 @@ function validateGovernanceConfig(config) {
24991
25291
  if (!isRecord(adapters))
24992
25292
  throw new Error("commandCapabilities.rpc must contain named adapters.");
24993
25293
  for (const [name, adapter] of Object.entries(adapters)) {
24994
- if (!name.trim() || !isRecord(adapter) || Object.keys(adapter).some((key) => !["audit", "idempotency", "transaction", "boundary"].includes(key)))
25294
+ if (!name.trim() || !isRecord(adapter) || Object.keys(adapter).some((key) => !["audit", "idempotency", "reconcile", "transaction", "boundary"].includes(key)))
24995
25295
  throw new Error("Invalid command adapter.");
24996
- for (const key of ["audit", "idempotency", "transaction"]) {
25296
+ for (const key of ["audit", "idempotency", "reconcile", "transaction"]) {
24997
25297
  if (adapter[key] !== undefined && typeof adapter[key] !== "boolean")
24998
25298
  throw new Error("Invalid command adapter capability.");
24999
25299
  }
@@ -25018,8 +25318,8 @@ function validateGovernanceConfig(config) {
25018
25318
  }
25019
25319
  if (config.typeSafety !== undefined) {
25020
25320
  const rules = config.typeSafety;
25021
- if (!isRecord(rules) || Object.keys(rules).some((key) => !["scanProductionSource", "noAnyInGenerated", "exclude"].includes(key)) || rules["scanProductionSource"] !== undefined && typeof rules["scanProductionSource"] !== "boolean" || rules["noAnyInGenerated"] !== undefined && typeof rules["noAnyInGenerated"] !== "boolean" || rules["exclude"] !== undefined && !isStrings(rules["exclude"])) {
25022
- throw new Error("typeSafety accepts boolean scanProductionSource/noAnyInGenerated and a string array exclude.");
25321
+ if (!isRecord(rules) || Object.keys(rules).some((key) => !["scanProductionSource", "noAnyInGenerated", "exclude", "allowAlternativeLibraries"].includes(key)) || rules["scanProductionSource"] !== undefined && typeof rules["scanProductionSource"] !== "boolean" || rules["noAnyInGenerated"] !== undefined && typeof rules["noAnyInGenerated"] !== "boolean" || rules["exclude"] !== undefined && !isStrings(rules["exclude"]) || rules["allowAlternativeLibraries"] !== undefined && !isStrings(rules["allowAlternativeLibraries"])) {
25322
+ throw new Error("typeSafety accepts boolean scanProductionSource/noAnyInGenerated and string arrays exclude/allowAlternativeLibraries.");
25023
25323
  }
25024
25324
  }
25025
25325
  for (const key of ["allowRouteCommandBindings", "disallowControllerDirectDb", "detectOrphanModules"]) {
@@ -25078,8 +25378,8 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
25078
25378
  }
25079
25379
  },
25080
25380
  ...resolved.allowRouteCommandBindings === undefined ? {} : { allowRouteCommandBindings: resolved.allowRouteCommandBindings },
25081
- ...resolved.disallowControllerDirectDb === undefined ? {} : { disallowControllerDirectDb: resolved.disallowControllerDirectDb },
25082
- ...resolved.detectOrphanModules === undefined ? {} : { detectOrphanModules: resolved.detectOrphanModules },
25381
+ disallowControllerDirectDb: resolved.disallowControllerDirectDb ?? DEFAULT_SUPACLOUD_CONFIG.disallowControllerDirectDb,
25382
+ detectOrphanModules: resolved.detectOrphanModules ?? DEFAULT_SUPACLOUD_CONFIG.detectOrphanModules,
25083
25383
  effect: resolved.effect === undefined ? { ...DEFAULT_SUPACLOUD_CONFIG.effect } : { ...DEFAULT_SUPACLOUD_CONFIG.effect, ...resolved.effect },
25084
25384
  treeShakeUnusedProviders: resolved.treeShakeUnusedProviders ?? DEFAULT_SUPACLOUD_CONFIG.treeShakeUnusedProviders,
25085
25385
  ...resolved.graphql === undefined || resolved.graphql === false ? {} : { graphql: {
@@ -25494,6 +25794,7 @@ export {
25494
25794
  validateEffectPolicies,
25495
25795
  validateFeatureSpec,
25496
25796
  validateGraph,
25797
+ validateJobPolicies,
25497
25798
  validateRouteContracts,
25498
25799
  watchProject,
25499
25800
  writeOpenApiJson