@supacloud/compiler 0.58.0 → 0.59.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
@@ -1090,7 +1090,13 @@ function validateGraph(graph, options = false) {
1090
1090
  if (command.rpc && command.branches) {
1091
1091
  error("command-rpc-branches-conflict", `Command ${command.name} cannot declare both rpc and branches.`, module.file, module.line);
1092
1092
  }
1093
+ if (command.branchesFallback !== undefined && command.branchesFallback !== "reject" && command.branchesFallback !== "command") {
1094
+ error("command-branches-fallback-invalid", `Command ${command.name} has an invalid branches fallback.`, module.file, module.line);
1095
+ }
1093
1096
  const branchAdapters = command.branches ?? [];
1097
+ if (command.branchesFallback === "command" && branchAdapters.length === 0) {
1098
+ error("command-branches-fallback-without-branches", `Command ${command.name} declares a fallback without branches.`, module.file, module.line);
1099
+ }
1094
1100
  for (const branch of branchAdapters) {
1095
1101
  if (typeof options !== "object" || !Object.hasOwn(options.commandCapabilities?.rpc ?? {}, branch.rpc)) {
1096
1102
  error("command-rpc-unavailable", `Command ${command.name} requires configured RPC adapter '${branch.rpc}'.`, module.file, module.line);
@@ -1120,7 +1126,7 @@ function validateGraph(graph, options = false) {
1120
1126
  error("command-transaction-unsupported", `Command ${command.name} branch '${branch.when}' declares transaction, but transaction support is unavailable.`, module.file, module.line);
1121
1127
  }
1122
1128
  }
1123
- if (hostCaps.requirePersistentAdapters && (command.rpc !== undefined && (!rpcCaps?.boundary || rpcCaps.audit !== true || rpcCaps.idempotency !== true) || branchCaps.length > 0 && branchCaps.some(({ branch, capabilities }) => !capabilities?.boundary || capabilities.audit !== true || capabilities.idempotency !== true || capabilities.boundary === "database" && (capabilities.transaction !== true || branch.transaction !== "required")) || hostCaps.permission !== true || !command.permission || branchCaps.length === 0 && (!command.audit || command.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ branch }) => !branch.audit || branch.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ capabilities }) => capabilities?.boundary === "external" && capabilities.reconcile !== true) || command.rpc !== undefined && rpcCaps?.boundary === "database" && (rpcCaps.transaction !== true || command.transaction !== "required") || command.rpc === undefined && branchCaps.length === 0 && (hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true || command.transaction !== "required") || command.rpc !== undefined && rpcCaps?.boundary === "external" && rpcCaps.reconcile !== true)) {
1129
+ if (hostCaps.requirePersistentAdapters && (command.rpc !== undefined && (!rpcCaps?.boundary || rpcCaps.audit !== true || rpcCaps.idempotency !== true) || branchCaps.length > 0 && branchCaps.some(({ branch, capabilities }) => !capabilities?.boundary || capabilities.audit !== true || capabilities.idempotency !== true || capabilities.boundary === "database" && (capabilities.transaction !== true || branch.transaction !== "required")) || hostCaps.permission !== true || !command.permission || branchCaps.length === 0 && (!command.audit || command.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ branch }) => !branch.audit || branch.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ capabilities }) => capabilities?.boundary === "external" && capabilities.reconcile !== true) || command.branchesFallback === "command" && (!command.audit || command.idempotency !== "required" || command.transaction !== "required" || hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true) || command.rpc !== undefined && rpcCaps?.boundary === "database" && (rpcCaps.transaction !== true || command.transaction !== "required") || command.rpc === undefined && branchCaps.length === 0 && (hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true || command.transaction !== "required") || command.rpc !== undefined && rpcCaps?.boundary === "external" && rpcCaps.reconcile !== true)) {
1124
1130
  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.");
1125
1131
  }
1126
1132
  if (rpcCaps?.boundary === "external" && (command.transaction === "required" || rpcCaps.transaction === true)) {
@@ -1673,6 +1679,7 @@ function buildContractManifest(graph, artifacts) {
1673
1679
  module: module.name,
1674
1680
  ...command.permission === undefined ? {} : { permission: command.permission },
1675
1681
  ...command.rpc === undefined ? {} : { rpc: command.rpc },
1682
+ ...command.branchesFallback === undefined ? {} : { branchesFallback: command.branchesFallback },
1676
1683
  ...command.branches === undefined ? {} : {
1677
1684
  branches: command.branches.map((branch) => ({
1678
1685
  when: branch.when,
@@ -2404,6 +2411,7 @@ function renderApplication(graph, options) {
2404
2411
  permission: command.permission ?? null,
2405
2412
  rpc: command.rpc ?? null,
2406
2413
  branches: command.branches ?? [],
2414
+ branchesFallback: command.branchesFallback ?? "reject",
2407
2415
  transaction: command.transaction ?? null,
2408
2416
  audit: command.audit ?? null,
2409
2417
  idempotency: command.idempotency ?? null
@@ -2482,6 +2490,7 @@ function renderApplication(graph, options) {
2482
2490
  transaction: command.transaction,
2483
2491
  idempotency: command.idempotency,
2484
2492
  branches: command.branches ?? [],
2493
+ branchesFallback: command.branchesFallback ?? "reject",
2485
2494
  ...command.tenantScope === undefined ? {} : { tenantScope: command.tenantScope },
2486
2495
  requiredCapabilities: {
2487
2496
  permission: true,
@@ -2974,6 +2983,7 @@ ${indent(item, 2)}`).join(",")}
2974
2983
  `idempotency: ${JSON.stringify(command.idempotency)}`,
2975
2984
  ...command.tenantScope ? [`tenantScope: ${JSON.stringify(command.tenantScope)}`] : [],
2976
2985
  ...command.rpc ? [`rpc: ${JSON.stringify(command.rpc)}`] : [],
2986
+ ...command.branchesFallback ? [`branchesFallback: ${JSON.stringify(command.branchesFallback)}`] : [],
2977
2987
  ...command.branches && command.branches.length > 0 ? [`branches: ${JSON.stringify(command.branches)}`] : [],
2978
2988
  ...command.standalone ? ["standalone: true"] : [],
2979
2989
  ...command.aspects && command.aspects.length > 0 ? [`aspects: ${this.renderAspects(command.aspects)}`, `aspectPipeline: ${this.renderAspectPipeline(command.aspects)}`] : []
@@ -4733,6 +4743,7 @@ var HEADER = "// GENERATED BY @supacloud/compiler — do not edit", INTERFACES =
4733
4743
  export interface CompiledCommand {
4734
4744
  rpc?: string;
4735
4745
  branches?: readonly CompiledCommandBranch[];
4746
+ branchesFallback?: "reject" | "command";
4736
4747
  className: string;
4737
4748
  name: string;
4738
4749
  permission: string;
@@ -4865,7 +4876,7 @@ async function compiledAspectStep(context: CompiledAspectContext, handler: () =>
4865
4876
  }
4866
4877
  called = true;
4867
4878
  pending = Promise.resolve().then(handler).then(result => {
4868
- if (strict) freezeCompiledAspectData(result);
4879
+ if (strict && !(result instanceof Response)) freezeCompiledAspectData(result);
4869
4880
  value = result;
4870
4881
  return result;
4871
4882
  });
@@ -16494,23 +16505,49 @@ var init_application_development2 = __esm(() => {
16494
16505
  });
16495
16506
 
16496
16507
  // node_modules/@supacloud/delivery/src/worker-execution.ts
16508
+ function workerShardCount(group) {
16509
+ return group.shardCount ?? 1;
16510
+ }
16511
+ function shardSuffix(shard) {
16512
+ if (!Number.isSafeInteger(shard) || shard < 0 || shard >= 64) {
16513
+ throw new Error("WORKER_SHARD_INVALID");
16514
+ }
16515
+ return `s${shard.toString(36).padStart(2, "0")}`;
16516
+ }
16517
+ function workerShardQueue(group, shard) {
16518
+ const count = workerShardCount(group);
16519
+ if (!Number.isSafeInteger(shard) || shard < 0 || shard >= count) {
16520
+ throw new Error("WORKER_SHARD_INVALID");
16521
+ }
16522
+ if (count === 1)
16523
+ return group.queue;
16524
+ const queue = `${group.queue}_${shardSuffix(shard)}`;
16525
+ if (!/^scw_[a-z0-9_]{1,40}$/.test(queue))
16526
+ throw new Error("WORKER_QUEUE_INVALID");
16527
+ return queue;
16528
+ }
16497
16529
  function parseWorkerExecutionGroup(value) {
16498
16530
  if (!Check2(WorkerExecutionGroupSchema, value) || value.replicas > value.maxReplicas || !value.queue.endsWith(`_v${value.definitionVersion}`) || value.lifecycle.visibilityTimeoutSeconds < value.lifecycle.executionTimeoutSeconds + value.lifecycle.shutdownGraceSeconds + 30) {
16499
16531
  throw new Error("WORKER_EXECUTION_INVALID");
16500
16532
  }
16501
- return structuredClone(value);
16533
+ const group = structuredClone(value);
16534
+ for (let shard = 0;shard < workerShardCount(group); shard += 1)
16535
+ workerShardQueue(group, shard);
16536
+ return group;
16502
16537
  }
16503
16538
  function validateWorkerExecution(groups) {
16504
16539
  const names = new Set, targets = new Set, queues = new Set, routes = new Set;
16505
16540
  for (const candidate of groups) {
16506
16541
  const group = parseWorkerExecutionGroup(candidate);
16507
16542
  const route = `${group.taskKey}:${group.definitionVersion}`;
16508
- if (names.has(group.name) || targets.has(group.target) || queues.has(group.queue) || routes.has(route)) {
16543
+ const physicalQueues = Array.from({ length: workerShardCount(group) }, (_, shard) => workerShardQueue(group, shard));
16544
+ if (names.has(group.name) || targets.has(group.target) || queues.has(group.queue) || physicalQueues.some((queue) => queues.has(queue)) || routes.has(route)) {
16509
16545
  throw new Error("WORKER_EXECUTION_CONFLICT");
16510
16546
  }
16511
16547
  names.add(group.name);
16512
16548
  targets.add(group.target);
16513
16549
  queues.add(group.queue);
16550
+ physicalQueues.forEach((queue) => queues.add(queue));
16514
16551
  routes.add(route);
16515
16552
  }
16516
16553
  }
@@ -16534,6 +16571,7 @@ var init_worker_execution = __esm(() => {
16534
16571
  definitionVersion: String2({ pattern: "^[1-9][0-9]{0,8}$" }),
16535
16572
  replicas: positive(16),
16536
16573
  maxReplicas: positive(16),
16574
+ shardCount: Optional(positive(64)),
16537
16575
  concurrencyPerReplica: positive(32),
16538
16576
  resources: ComputeResourcesSchema,
16539
16577
  database: _Object_({
@@ -16943,7 +16981,7 @@ function parseDeliveryBuildManifest(value) {
16943
16981
  if (!Check2(DeliveryBuildManifestSchema, value))
16944
16982
  throw new Error("Invalid delivery build manifest.");
16945
16983
  validateWorkerExecution(value.plan.targets.flatMap((target) => target.execution ? [target.execution] : []));
16946
- if (value.plan.targets.reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
16984
+ if (value.plan.targets.reduce((count, target) => count + (target.execution ? (target.execution.replicas ?? 1) * workerShardCount(target.execution) : 1), 0) > 256) {
16947
16985
  throw new Error("Invalid delivery replica count.");
16948
16986
  }
16949
16987
  for (const target of value.plan.targets) {
@@ -19879,6 +19917,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths, effectOptio
19879
19917
  const permission = stringLiteralProp(meta, "permission");
19880
19918
  const rpc = checkedRpc(meta, ctx);
19881
19919
  const branches = checkedBranches(meta, ctx);
19920
+ const branchesFallback = checkedBranchesFallback(meta, ctx);
19882
19921
  const audit = stringLiteralProp(meta, "audit");
19883
19922
  const standaloneName = stringLiteralProp(meta, "name") ?? classInfo.decl.name?.text ?? name;
19884
19923
  const standaloneUses = await parseInfraResourceUseRefs(infraResourceProp(meta, "uses", ctx), ctx, `command ${standaloneName}`, sourcePath(ctx.rootDir, classInfo.file), lineOf(classInfo.decl));
@@ -19889,6 +19928,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths, effectOptio
19889
19928
  ...permission === undefined ? {} : { permission },
19890
19929
  ...rpc === undefined ? {} : { rpc },
19891
19930
  ...branches === undefined ? {} : { branches },
19931
+ ...branchesFallback === undefined ? {} : { branchesFallback },
19892
19932
  transaction: checkedCommandMode(meta, "transaction", ctx, classInfo.decl.name?.text ?? name) ?? "none",
19893
19933
  ...audit === undefined ? {} : { audit },
19894
19934
  idempotency: checkedCommandMode(meta, "idempotency", ctx, classInfo.decl.name?.text ?? name) ?? "none",
@@ -20263,6 +20303,7 @@ async function parseModule(candidate, nameByNode, ctx) {
20263
20303
  const permission = stringLiteralProp(meta, "permission");
20264
20304
  const rpc = checkedRpc(meta, ctx);
20265
20305
  const branches = checkedBranches(meta, ctx);
20306
+ const branchesFallback = checkedBranchesFallback(meta, ctx);
20266
20307
  const audit = stringLiteralProp(meta, "audit");
20267
20308
  const commandName = stringLiteralProp(meta, "name") ?? cls.name?.text ?? "<anonymous>";
20268
20309
  const uses = await parseInfraResourceUseRefs(infraResourceProp(meta, "uses", ctx), ctx, `command ${commandName}`, sourcePath(ctx.rootDir, cls.getSourceFile().fileName), lineOf(cls));
@@ -20274,6 +20315,7 @@ async function parseModule(candidate, nameByNode, ctx) {
20274
20315
  ...permission === undefined ? {} : { permission },
20275
20316
  ...rpc === undefined ? {} : { rpc },
20276
20317
  ...branches === undefined ? {} : { branches },
20318
+ ...branchesFallback === undefined ? {} : { branchesFallback },
20277
20319
  transaction: checkedCommandMode(meta, "transaction", ctx, cls.name?.text ?? "<anonymous>") ?? "none",
20278
20320
  ...audit === undefined ? {} : { audit },
20279
20321
  idempotency: checkedCommandMode(meta, "idempotency", ctx, cls.name?.text ?? "<anonymous>") ?? "none",
@@ -22112,6 +22154,23 @@ function checkedBranches(meta, ctx) {
22112
22154
  }
22113
22155
  return branches;
22114
22156
  }
22157
+ function checkedBranchesFallback(meta, ctx) {
22158
+ const expression = getProp(meta, "branchesFallback");
22159
+ if (!expression)
22160
+ return;
22161
+ const value = stringLiteralProp(meta, "branchesFallback");
22162
+ if (value === "reject" || value === "command")
22163
+ return value;
22164
+ ctx.diagnostics.push({
22165
+ severity: "error",
22166
+ code: "invalid-command-branches-fallback",
22167
+ file: sourcePath(ctx.rootDir, expression.getSourceFile().fileName),
22168
+ line: lineOf(expression),
22169
+ message: "Command branchesFallback must be 'reject' or 'command'.",
22170
+ suggestion: "Use branchesFallback: 'command' only when the command handler owns the unmatched-input boundary."
22171
+ });
22172
+ return;
22173
+ }
22115
22174
  async function classDeps(cls, ctx) {
22116
22175
  const injectable = await parseInjectableOptions(cls, ctx);
22117
22176
  const ctor = cls.members.find(ts8.isConstructorDeclaration);
@@ -25292,8 +25351,8 @@ function createDeliveryPlan(graph, input, validation) {
25292
25351
  target.execution = group;
25293
25352
  }
25294
25353
  }
25295
- if ([...targets.values()].reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
25296
- fail("delivery-execution-replica-limit", "A release supports at most 32 runtime targets including replicas.", "Reduce the replica count or split independent applications.");
25354
+ if ([...targets.values()].reduce((count, target) => count + (target.execution ? (target.execution.replicas ?? 1) * (target.execution.shardCount ?? 1) : 1), 0) > 256) {
25355
+ fail("delivery-execution-replica-limit", "A release supports at most 256 runtime targets including replicas and queue shards.", "Reduce the replica or shard count, or split independent applications.");
25297
25356
  }
25298
25357
  const canonicalDiagnostics = [...new Map(diagnostics.map((item) => [JSON.stringify(item), item])).values()].sort((a, b) => compare2(JSON.stringify(a), JSON.stringify(b)));
25299
25358
  if (canonicalDiagnostics.some((item) => item.severity === "error")) {
@@ -25384,6 +25443,7 @@ function validateExecutionManifest(plan, capabilities = {}) {
25384
25443
  ...command.adapter === null ? {} : { rpc: command.adapter },
25385
25444
  ...command.audit === null ? {} : { audit: command.audit },
25386
25445
  ...command.branches.length === 0 ? {} : { branches: command.branches },
25446
+ ...command.branchesFallback === undefined ? {} : { branchesFallback: command.branchesFallback },
25387
25447
  transaction: command.transaction,
25388
25448
  idempotency: command.idempotency
25389
25449
  }))
@@ -26450,10 +26510,10 @@ import { readFileSync as readFileSync4 } from "node:fs";
26450
26510
  import { resolve as resolve19 } from "node:path";
26451
26511
 
26452
26512
  // src/migration-app-version.ts
26453
- var MIGRATION_APP_VERSION = "0.39.0";
26513
+ var MIGRATION_APP_VERSION = "0.39.1";
26454
26514
 
26455
26515
  // src/migration-elysia-version.ts
26456
- var MIGRATION_ELYSIA_VERSION = "0.41.0";
26516
+ var MIGRATION_ELYSIA_VERSION = "0.42.0";
26457
26517
 
26458
26518
  // src/migration-policy.ts
26459
26519
  var cachedCompilerVersion;
@@ -7,6 +7,7 @@ export interface ContractManifest {
7
7
  module: string;
8
8
  permission?: string;
9
9
  rpc?: string;
10
+ branchesFallback?: "reject" | "command";
10
11
  branches?: Array<{
11
12
  when: string;
12
13
  adapter: string;
@@ -19,6 +19,7 @@ declare const requestSchema: Type.TObject<{
19
19
  definitionVersion: Type.TString;
20
20
  replicas: Type.TInteger;
21
21
  maxReplicas: Type.TInteger;
22
+ shardCount: Type.TOptional<Type.TInteger>;
22
23
  concurrencyPerReplica: Type.TInteger;
23
24
  resources: Type.TObject<{
24
25
  cpuLimit: Type.TNumber;
@@ -10103,23 +10103,49 @@ var init_build2 = __esm(() => {
10103
10103
  });
10104
10104
 
10105
10105
  // node_modules/@supacloud/delivery/src/worker-execution.ts
10106
+ function workerShardCount(group) {
10107
+ return group.shardCount ?? 1;
10108
+ }
10109
+ function shardSuffix(shard) {
10110
+ if (!Number.isSafeInteger(shard) || shard < 0 || shard >= 64) {
10111
+ throw new Error("WORKER_SHARD_INVALID");
10112
+ }
10113
+ return `s${shard.toString(36).padStart(2, "0")}`;
10114
+ }
10115
+ function workerShardQueue(group, shard) {
10116
+ const count = workerShardCount(group);
10117
+ if (!Number.isSafeInteger(shard) || shard < 0 || shard >= count) {
10118
+ throw new Error("WORKER_SHARD_INVALID");
10119
+ }
10120
+ if (count === 1)
10121
+ return group.queue;
10122
+ const queue = `${group.queue}_${shardSuffix(shard)}`;
10123
+ if (!/^scw_[a-z0-9_]{1,40}$/.test(queue))
10124
+ throw new Error("WORKER_QUEUE_INVALID");
10125
+ return queue;
10126
+ }
10106
10127
  function parseWorkerExecutionGroup(value) {
10107
10128
  if (!Check2(WorkerExecutionGroupSchema, value) || value.replicas > value.maxReplicas || !value.queue.endsWith(`_v${value.definitionVersion}`) || value.lifecycle.visibilityTimeoutSeconds < value.lifecycle.executionTimeoutSeconds + value.lifecycle.shutdownGraceSeconds + 30) {
10108
10129
  throw new Error("WORKER_EXECUTION_INVALID");
10109
10130
  }
10110
- return structuredClone(value);
10131
+ const group = structuredClone(value);
10132
+ for (let shard = 0;shard < workerShardCount(group); shard += 1)
10133
+ workerShardQueue(group, shard);
10134
+ return group;
10111
10135
  }
10112
10136
  function validateWorkerExecution(groups) {
10113
10137
  const names = new Set, targets = new Set, queues = new Set, routes = new Set;
10114
10138
  for (const candidate of groups) {
10115
10139
  const group = parseWorkerExecutionGroup(candidate);
10116
10140
  const route = `${group.taskKey}:${group.definitionVersion}`;
10117
- if (names.has(group.name) || targets.has(group.target) || queues.has(group.queue) || routes.has(route)) {
10141
+ const physicalQueues = Array.from({ length: workerShardCount(group) }, (_, shard) => workerShardQueue(group, shard));
10142
+ if (names.has(group.name) || targets.has(group.target) || queues.has(group.queue) || physicalQueues.some((queue) => queues.has(queue)) || routes.has(route)) {
10118
10143
  throw new Error("WORKER_EXECUTION_CONFLICT");
10119
10144
  }
10120
10145
  names.add(group.name);
10121
10146
  targets.add(group.target);
10122
10147
  queues.add(group.queue);
10148
+ physicalQueues.forEach((queue) => queues.add(queue));
10123
10149
  routes.add(route);
10124
10150
  }
10125
10151
  }
@@ -10143,6 +10169,7 @@ var init_worker_execution = __esm(() => {
10143
10169
  definitionVersion: String2({ pattern: "^[1-9][0-9]{0,8}$" }),
10144
10170
  replicas: positive(16),
10145
10171
  maxReplicas: positive(16),
10172
+ shardCount: Optional(positive(64)),
10146
10173
  concurrencyPerReplica: positive(32),
10147
10174
  resources: ComputeResourcesSchema,
10148
10175
  database: _Object_({
package/dist/index.js CHANGED
@@ -1089,7 +1089,13 @@ function validateGraph(graph, options = false) {
1089
1089
  if (command.rpc && command.branches) {
1090
1090
  error("command-rpc-branches-conflict", `Command ${command.name} cannot declare both rpc and branches.`, module.file, module.line);
1091
1091
  }
1092
+ if (command.branchesFallback !== undefined && command.branchesFallback !== "reject" && command.branchesFallback !== "command") {
1093
+ error("command-branches-fallback-invalid", `Command ${command.name} has an invalid branches fallback.`, module.file, module.line);
1094
+ }
1092
1095
  const branchAdapters = command.branches ?? [];
1096
+ if (command.branchesFallback === "command" && branchAdapters.length === 0) {
1097
+ error("command-branches-fallback-without-branches", `Command ${command.name} declares a fallback without branches.`, module.file, module.line);
1098
+ }
1093
1099
  for (const branch of branchAdapters) {
1094
1100
  if (typeof options !== "object" || !Object.hasOwn(options.commandCapabilities?.rpc ?? {}, branch.rpc)) {
1095
1101
  error("command-rpc-unavailable", `Command ${command.name} requires configured RPC adapter '${branch.rpc}'.`, module.file, module.line);
@@ -1119,7 +1125,7 @@ function validateGraph(graph, options = false) {
1119
1125
  error("command-transaction-unsupported", `Command ${command.name} branch '${branch.when}' declares transaction, but transaction support is unavailable.`, module.file, module.line);
1120
1126
  }
1121
1127
  }
1122
- if (hostCaps.requirePersistentAdapters && (command.rpc !== undefined && (!rpcCaps?.boundary || rpcCaps.audit !== true || rpcCaps.idempotency !== true) || branchCaps.length > 0 && branchCaps.some(({ branch, capabilities }) => !capabilities?.boundary || capabilities.audit !== true || capabilities.idempotency !== true || capabilities.boundary === "database" && (capabilities.transaction !== true || branch.transaction !== "required")) || hostCaps.permission !== true || !command.permission || branchCaps.length === 0 && (!command.audit || command.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ branch }) => !branch.audit || branch.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ capabilities }) => capabilities?.boundary === "external" && capabilities.reconcile !== true) || command.rpc !== undefined && rpcCaps?.boundary === "database" && (rpcCaps.transaction !== true || command.transaction !== "required") || command.rpc === undefined && branchCaps.length === 0 && (hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true || command.transaction !== "required") || command.rpc !== undefined && rpcCaps?.boundary === "external" && rpcCaps.reconcile !== true)) {
1128
+ if (hostCaps.requirePersistentAdapters && (command.rpc !== undefined && (!rpcCaps?.boundary || rpcCaps.audit !== true || rpcCaps.idempotency !== true) || branchCaps.length > 0 && branchCaps.some(({ branch, capabilities }) => !capabilities?.boundary || capabilities.audit !== true || capabilities.idempotency !== true || capabilities.boundary === "database" && (capabilities.transaction !== true || branch.transaction !== "required")) || hostCaps.permission !== true || !command.permission || branchCaps.length === 0 && (!command.audit || command.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ branch }) => !branch.audit || branch.idempotency !== "required") || branchCaps.length > 0 && branchCaps.some(({ capabilities }) => capabilities?.boundary === "external" && capabilities.reconcile !== true) || command.branchesFallback === "command" && (!command.audit || command.idempotency !== "required" || command.transaction !== "required" || hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true) || command.rpc !== undefined && rpcCaps?.boundary === "database" && (rpcCaps.transaction !== true || command.transaction !== "required") || command.rpc === undefined && branchCaps.length === 0 && (hostCaps.audit !== true || hostCaps.idempotency !== true || hostCaps.transaction !== true || command.transaction !== "required") || command.rpc !== undefined && rpcCaps?.boundary === "external" && rpcCaps.reconcile !== true)) {
1123
1129
  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.");
1124
1130
  }
1125
1131
  if (rpcCaps?.boundary === "external" && (command.transaction === "required" || rpcCaps.transaction === true)) {
@@ -1672,6 +1678,7 @@ function buildContractManifest(graph, artifacts) {
1672
1678
  module: module.name,
1673
1679
  ...command.permission === undefined ? {} : { permission: command.permission },
1674
1680
  ...command.rpc === undefined ? {} : { rpc: command.rpc },
1681
+ ...command.branchesFallback === undefined ? {} : { branchesFallback: command.branchesFallback },
1675
1682
  ...command.branches === undefined ? {} : {
1676
1683
  branches: command.branches.map((branch) => ({
1677
1684
  when: branch.when,
@@ -2403,6 +2410,7 @@ function renderApplication(graph, options) {
2403
2410
  permission: command.permission ?? null,
2404
2411
  rpc: command.rpc ?? null,
2405
2412
  branches: command.branches ?? [],
2413
+ branchesFallback: command.branchesFallback ?? "reject",
2406
2414
  transaction: command.transaction ?? null,
2407
2415
  audit: command.audit ?? null,
2408
2416
  idempotency: command.idempotency ?? null
@@ -2481,6 +2489,7 @@ function renderApplication(graph, options) {
2481
2489
  transaction: command.transaction,
2482
2490
  idempotency: command.idempotency,
2483
2491
  branches: command.branches ?? [],
2492
+ branchesFallback: command.branchesFallback ?? "reject",
2484
2493
  ...command.tenantScope === undefined ? {} : { tenantScope: command.tenantScope },
2485
2494
  requiredCapabilities: {
2486
2495
  permission: true,
@@ -2973,6 +2982,7 @@ ${indent(item, 2)}`).join(",")}
2973
2982
  `idempotency: ${JSON.stringify(command.idempotency)}`,
2974
2983
  ...command.tenantScope ? [`tenantScope: ${JSON.stringify(command.tenantScope)}`] : [],
2975
2984
  ...command.rpc ? [`rpc: ${JSON.stringify(command.rpc)}`] : [],
2985
+ ...command.branchesFallback ? [`branchesFallback: ${JSON.stringify(command.branchesFallback)}`] : [],
2976
2986
  ...command.branches && command.branches.length > 0 ? [`branches: ${JSON.stringify(command.branches)}`] : [],
2977
2987
  ...command.standalone ? ["standalone: true"] : [],
2978
2988
  ...command.aspects && command.aspects.length > 0 ? [`aspects: ${this.renderAspects(command.aspects)}`, `aspectPipeline: ${this.renderAspectPipeline(command.aspects)}`] : []
@@ -4732,6 +4742,7 @@ var HEADER = "// GENERATED BY @supacloud/compiler — do not edit", INTERFACES =
4732
4742
  export interface CompiledCommand {
4733
4743
  rpc?: string;
4734
4744
  branches?: readonly CompiledCommandBranch[];
4745
+ branchesFallback?: "reject" | "command";
4735
4746
  className: string;
4736
4747
  name: string;
4737
4748
  permission: string;
@@ -4864,7 +4875,7 @@ async function compiledAspectStep(context: CompiledAspectContext, handler: () =>
4864
4875
  }
4865
4876
  called = true;
4866
4877
  pending = Promise.resolve().then(handler).then(result => {
4867
- if (strict) freezeCompiledAspectData(result);
4878
+ if (strict && !(result instanceof Response)) freezeCompiledAspectData(result);
4868
4879
  value = result;
4869
4880
  return result;
4870
4881
  });
@@ -15630,23 +15641,49 @@ var init_value2 = __esm(() => {
15630
15641
  });
15631
15642
 
15632
15643
  // node_modules/@supacloud/delivery/src/worker-execution.ts
15644
+ function workerShardCount(group) {
15645
+ return group.shardCount ?? 1;
15646
+ }
15647
+ function shardSuffix(shard) {
15648
+ if (!Number.isSafeInteger(shard) || shard < 0 || shard >= 64) {
15649
+ throw new Error("WORKER_SHARD_INVALID");
15650
+ }
15651
+ return `s${shard.toString(36).padStart(2, "0")}`;
15652
+ }
15653
+ function workerShardQueue(group, shard) {
15654
+ const count = workerShardCount(group);
15655
+ if (!Number.isSafeInteger(shard) || shard < 0 || shard >= count) {
15656
+ throw new Error("WORKER_SHARD_INVALID");
15657
+ }
15658
+ if (count === 1)
15659
+ return group.queue;
15660
+ const queue = `${group.queue}_${shardSuffix(shard)}`;
15661
+ if (!/^scw_[a-z0-9_]{1,40}$/.test(queue))
15662
+ throw new Error("WORKER_QUEUE_INVALID");
15663
+ return queue;
15664
+ }
15633
15665
  function parseWorkerExecutionGroup(value) {
15634
15666
  if (!Check2(WorkerExecutionGroupSchema, value) || value.replicas > value.maxReplicas || !value.queue.endsWith(`_v${value.definitionVersion}`) || value.lifecycle.visibilityTimeoutSeconds < value.lifecycle.executionTimeoutSeconds + value.lifecycle.shutdownGraceSeconds + 30) {
15635
15667
  throw new Error("WORKER_EXECUTION_INVALID");
15636
15668
  }
15637
- return structuredClone(value);
15669
+ const group = structuredClone(value);
15670
+ for (let shard = 0;shard < workerShardCount(group); shard += 1)
15671
+ workerShardQueue(group, shard);
15672
+ return group;
15638
15673
  }
15639
15674
  function validateWorkerExecution(groups) {
15640
15675
  const names = new Set, targets = new Set, queues = new Set, routes = new Set;
15641
15676
  for (const candidate of groups) {
15642
15677
  const group = parseWorkerExecutionGroup(candidate);
15643
15678
  const route = `${group.taskKey}:${group.definitionVersion}`;
15644
- if (names.has(group.name) || targets.has(group.target) || queues.has(group.queue) || routes.has(route)) {
15679
+ const physicalQueues = Array.from({ length: workerShardCount(group) }, (_, shard) => workerShardQueue(group, shard));
15680
+ if (names.has(group.name) || targets.has(group.target) || queues.has(group.queue) || physicalQueues.some((queue) => queues.has(queue)) || routes.has(route)) {
15645
15681
  throw new Error("WORKER_EXECUTION_CONFLICT");
15646
15682
  }
15647
15683
  names.add(group.name);
15648
15684
  targets.add(group.target);
15649
15685
  queues.add(group.queue);
15686
+ physicalQueues.forEach((queue) => queues.add(queue));
15650
15687
  routes.add(route);
15651
15688
  }
15652
15689
  }
@@ -15670,6 +15707,7 @@ var init_worker_execution = __esm(() => {
15670
15707
  definitionVersion: String2({ pattern: "^[1-9][0-9]{0,8}$" }),
15671
15708
  replicas: positive(16),
15672
15709
  maxReplicas: positive(16),
15710
+ shardCount: Optional(positive(64)),
15673
15711
  concurrencyPerReplica: positive(32),
15674
15712
  resources: ComputeResourcesSchema,
15675
15713
  database: _Object_({
@@ -16079,7 +16117,7 @@ function parseDeliveryBuildManifest(value) {
16079
16117
  if (!Check2(DeliveryBuildManifestSchema, value))
16080
16118
  throw new Error("Invalid delivery build manifest.");
16081
16119
  validateWorkerExecution(value.plan.targets.flatMap((target) => target.execution ? [target.execution] : []));
16082
- if (value.plan.targets.reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
16120
+ if (value.plan.targets.reduce((count, target) => count + (target.execution ? (target.execution.replicas ?? 1) * workerShardCount(target.execution) : 1), 0) > 256) {
16083
16121
  throw new Error("Invalid delivery replica count.");
16084
16122
  }
16085
16123
  for (const target of value.plan.targets) {
@@ -19838,6 +19876,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths, effectOptio
19838
19876
  const permission = stringLiteralProp(meta, "permission");
19839
19877
  const rpc = checkedRpc(meta, ctx);
19840
19878
  const branches = checkedBranches(meta, ctx);
19879
+ const branchesFallback = checkedBranchesFallback(meta, ctx);
19841
19880
  const audit = stringLiteralProp(meta, "audit");
19842
19881
  const standaloneName = stringLiteralProp(meta, "name") ?? classInfo.decl.name?.text ?? name;
19843
19882
  const standaloneUses = await parseInfraResourceUseRefs(infraResourceProp(meta, "uses", ctx), ctx, `command ${standaloneName}`, sourcePath(ctx.rootDir, classInfo.file), lineOf(classInfo.decl));
@@ -19848,6 +19887,7 @@ async function analyzeProject(rootDir, include, cache, changedPaths, effectOptio
19848
19887
  ...permission === undefined ? {} : { permission },
19849
19888
  ...rpc === undefined ? {} : { rpc },
19850
19889
  ...branches === undefined ? {} : { branches },
19890
+ ...branchesFallback === undefined ? {} : { branchesFallback },
19851
19891
  transaction: checkedCommandMode(meta, "transaction", ctx, classInfo.decl.name?.text ?? name) ?? "none",
19852
19892
  ...audit === undefined ? {} : { audit },
19853
19893
  idempotency: checkedCommandMode(meta, "idempotency", ctx, classInfo.decl.name?.text ?? name) ?? "none",
@@ -20222,6 +20262,7 @@ async function parseModule(candidate, nameByNode, ctx) {
20222
20262
  const permission = stringLiteralProp(meta, "permission");
20223
20263
  const rpc = checkedRpc(meta, ctx);
20224
20264
  const branches = checkedBranches(meta, ctx);
20265
+ const branchesFallback = checkedBranchesFallback(meta, ctx);
20225
20266
  const audit = stringLiteralProp(meta, "audit");
20226
20267
  const commandName = stringLiteralProp(meta, "name") ?? cls.name?.text ?? "<anonymous>";
20227
20268
  const uses = await parseInfraResourceUseRefs(infraResourceProp(meta, "uses", ctx), ctx, `command ${commandName}`, sourcePath(ctx.rootDir, cls.getSourceFile().fileName), lineOf(cls));
@@ -20233,6 +20274,7 @@ async function parseModule(candidate, nameByNode, ctx) {
20233
20274
  ...permission === undefined ? {} : { permission },
20234
20275
  ...rpc === undefined ? {} : { rpc },
20235
20276
  ...branches === undefined ? {} : { branches },
20277
+ ...branchesFallback === undefined ? {} : { branchesFallback },
20236
20278
  transaction: checkedCommandMode(meta, "transaction", ctx, cls.name?.text ?? "<anonymous>") ?? "none",
20237
20279
  ...audit === undefined ? {} : { audit },
20238
20280
  idempotency: checkedCommandMode(meta, "idempotency", ctx, cls.name?.text ?? "<anonymous>") ?? "none",
@@ -22071,6 +22113,23 @@ function checkedBranches(meta, ctx) {
22071
22113
  }
22072
22114
  return branches;
22073
22115
  }
22116
+ function checkedBranchesFallback(meta, ctx) {
22117
+ const expression = getProp(meta, "branchesFallback");
22118
+ if (!expression)
22119
+ return;
22120
+ const value = stringLiteralProp(meta, "branchesFallback");
22121
+ if (value === "reject" || value === "command")
22122
+ return value;
22123
+ ctx.diagnostics.push({
22124
+ severity: "error",
22125
+ code: "invalid-command-branches-fallback",
22126
+ file: sourcePath(ctx.rootDir, expression.getSourceFile().fileName),
22127
+ line: lineOf(expression),
22128
+ message: "Command branchesFallback must be 'reject' or 'command'.",
22129
+ suggestion: "Use branchesFallback: 'command' only when the command handler owns the unmatched-input boundary."
22130
+ });
22131
+ return;
22132
+ }
22074
22133
  async function classDeps(cls, ctx) {
22075
22134
  const injectable = await parseInjectableOptions(cls, ctx);
22076
22135
  const ctor = cls.members.find(ts8.isConstructorDeclaration);
@@ -23860,8 +23919,8 @@ function createDeliveryPlan(graph, input, validation) {
23860
23919
  target.execution = group;
23861
23920
  }
23862
23921
  }
23863
- if ([...targets.values()].reduce((count, target) => count + (target.execution?.replicas ?? 1), 0) > 32) {
23864
- fail("delivery-execution-replica-limit", "A release supports at most 32 runtime targets including replicas.", "Reduce the replica count or split independent applications.");
23922
+ if ([...targets.values()].reduce((count, target) => count + (target.execution ? (target.execution.replicas ?? 1) * (target.execution.shardCount ?? 1) : 1), 0) > 256) {
23923
+ fail("delivery-execution-replica-limit", "A release supports at most 256 runtime targets including replicas and queue shards.", "Reduce the replica or shard count, or split independent applications.");
23865
23924
  }
23866
23925
  const canonicalDiagnostics = [...new Map(diagnostics.map((item) => [JSON.stringify(item), item])).values()].sort((a, b) => compare2(JSON.stringify(a), JSON.stringify(b)));
23867
23926
  if (canonicalDiagnostics.some((item) => item.severity === "error")) {
@@ -23951,6 +24010,7 @@ function validateExecutionManifest(plan, capabilities = {}) {
23951
24010
  ...command.adapter === null ? {} : { rpc: command.adapter },
23952
24011
  ...command.audit === null ? {} : { audit: command.audit },
23953
24012
  ...command.branches.length === 0 ? {} : { branches: command.branches },
24013
+ ...command.branchesFallback === undefined ? {} : { branchesFallback: command.branchesFallback },
23954
24014
  transaction: command.transaction,
23955
24015
  idempotency: command.idempotency
23956
24016
  }))
@@ -25702,10 +25762,10 @@ import { readFileSync as readFileSync4 } from "node:fs";
25702
25762
  import { resolve as resolve17 } from "node:path";
25703
25763
 
25704
25764
  // src/migration-app-version.ts
25705
- var MIGRATION_APP_VERSION = "0.39.0";
25765
+ var MIGRATION_APP_VERSION = "0.39.1";
25706
25766
 
25707
25767
  // src/migration-elysia-version.ts
25708
- var MIGRATION_ELYSIA_VERSION = "0.41.0";
25768
+ var MIGRATION_ELYSIA_VERSION = "0.42.0";
25709
25769
 
25710
25770
  // src/migration-policy.ts
25711
25771
  var cachedCompilerVersion;
@@ -1 +1 @@
1
- export declare const MIGRATION_APP_VERSION = "0.39.0";
1
+ export declare const MIGRATION_APP_VERSION = "0.39.1";
@@ -1 +1 @@
1
- export declare const MIGRATION_ELYSIA_VERSION = "0.41.0";
1
+ export declare const MIGRATION_ELYSIA_VERSION = "0.42.0";
package/dist/types.d.ts CHANGED
@@ -324,6 +324,7 @@ export interface ControllerNode {
324
324
  export interface CommandNode {
325
325
  rpc?: string;
326
326
  branches?: CommandBranchNode[];
327
+ branchesFallback?: "reject" | "command";
327
328
  className: string;
328
329
  name: string;
329
330
  permission?: string;
@@ -432,6 +433,7 @@ export interface ExecutionPlanCommand {
432
433
  transaction: CommandNode["transaction"];
433
434
  idempotency: CommandNode["idempotency"];
434
435
  branches: CommandBranchNode[];
436
+ branchesFallback: "reject" | "command";
435
437
  tenantScope?: CommandNode["tenantScope"];
436
438
  requiredCapabilities: {
437
439
  permission: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/compiler",
3
- "version": "0.58.0",
3
+ "version": "0.59.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",
@@ -57,8 +57,8 @@
57
57
  "directory": "packages/compiler"
58
58
  },
59
59
  "dependencies": {
60
- "@supacloud/db": "0.22.0",
61
- "@supacloud/delivery": "0.25.0",
60
+ "@supacloud/db": "0.23.1",
61
+ "@supacloud/delivery": "0.26.0",
62
62
  "typebox": "1.4.3",
63
63
  "@graphql-codegen/core": "^6.2.2",
64
64
  "@graphql-codegen/typed-document-node": "^7.2.0",