@supacloud/cli 0.103.3 → 0.103.6

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
@@ -10960,7 +10960,7 @@ function formatDeploymentEvidence(evidence) {
10960
10960
  return [
10961
10961
  `DEPLOYMENT ${evidence.scope.project_ref}/${evidence.scope.application_id}/${evidence.scope.environment_id}`,
10962
10962
  ` status: ${report.status}`,
10963
- ...report.status !== evidence.status ? [` recorded status: ${evidence.status} (additional proof missing)`] : [],
10963
+ ...report.status !== evidence.status ? [` recorded status: ${evidence.status} (customer assessment differs)`] : [],
10964
10964
  ` manifest: ${evidence.source.manifest_sha256.slice(0, 12)}`,
10965
10965
  ` database: ${evidence.database.provider} ${evidence.database.version} (${evidence.database.topology})`,
10966
10966
  ` activation: ${evidence.activation.activation_id}`,
@@ -10988,7 +10988,7 @@ function summarizeDeploymentEvidence(value) {
10988
10988
  for (const component of evidence.components) {
10989
10989
  observe(component.name, component.status, component.checked_at !== null && component.health_check !== null, "Inspect this component's health and logs for the recorded activation before changing or restarting it.");
10990
10990
  }
10991
- observe("database.migration", evidence.database.migration.status, evidence.database.migration.compatibility === "verified" && evidence.database.migration.inventory_sha256 !== null, "Read the migration inventory and compare its digest; do not reapply an unconfirmed migration.");
10991
+ observe("database.migration", evidence.database.migration.compatibility === "failed" ? "failed" : evidence.database.migration.status, evidence.database.migration.compatibility === "verified" && evidence.database.migration.inventory_sha256 !== null, "Read the migration inventory and compare its digest; do not reapply an unconfirmed migration.");
10992
10992
  observe("database.backup", evidence.database.backup.status, evidence.database.backup.latest_success_at !== null && evidence.database.backup.freshness_seconds !== null, "Read backup inventory and freshness for this project; a successful deployment is not a backup.");
10993
10993
  observe("database.recovery", evidence.database.recovery.status, evidence.database.recovery.drill_id !== null && evidence.database.recovery.rpo_seconds !== null && evidence.database.recovery.rto_seconds !== null, "Obtain a separate approved restore drill and verify data, permissions and storage; never restore automatically.");
10994
10994
  observe("health", evidence.health.status, evidence.health.checked_at !== null, "Read back this activation's readiness; process health alone does not prove a business operation.");
@@ -10997,9 +10997,10 @@ function summarizeDeploymentEvidence(value) {
10997
10997
  if (evidence.rollback.result !== null) {
10998
10998
  observe("code-rollback.result", evidence.rollback.result, true, "Read back the rollback activation and authenticated smoke before another mutation.");
10999
10999
  }
11000
+ const assessment = issues.some((issue) => issue.status === "failed") || evidence.status === "failed" ? "failed" : issues.some((issue) => issue.status === "unknown") || evidence.status === "unknown" ? "unknown" : issues.length > 0 || evidence.status === "incomplete" ? "incomplete" : "confirmed";
11000
11001
  return {
11001
11002
  version: 1,
11002
- status: evidence.status === "confirmed" && issues.length > 0 ? "incomplete" : evidence.status,
11003
+ status: assessment,
11003
11004
  recordedStatus: evidence.status,
11004
11005
  scope: evidence.scope,
11005
11006
  recordedAt: evidence.recorded_at,
@@ -15003,7 +15004,7 @@ Actions: status, list_buckets, get_bucket, create_bucket, update_bucket, delete_
15003
15004
  }
15004
15005
 
15005
15006
  // src/shared/tools/advanced-tools.ts
15006
- import { createHash as createHash4, timingSafeEqual } from "node:crypto";
15007
+ import { createHash as createHash5, timingSafeEqual } from "node:crypto";
15007
15008
  import {
15008
15009
  closeSync,
15009
15010
  constants as fsConstants,
@@ -15013,14 +15014,101 @@ import {
15013
15014
  mkdirSync,
15014
15015
  mkdtempSync,
15015
15016
  openSync,
15016
- readFileSync as readFileSync5,
15017
+ readFileSync as readFileSync6,
15017
15018
  readdirSync as readdirSync3,
15018
15019
  rmSync,
15019
15020
  statSync as statSync4,
15020
15021
  writeFileSync
15021
15022
  } from "node:fs";
15022
15023
  import { tmpdir } from "node:os";
15023
- import { basename as basename5, join as join5, relative as relative2, resolve as resolve6, sep as sep2 } from "node:path";
15024
+ import { basename as basename5, join as join5, relative as relative2, resolve as resolve7, sep as sep2 } from "node:path";
15025
+
15026
+ // src/shared/tools/function-aot.ts
15027
+ import { execFile } from "node:child_process";
15028
+ import { createHash as createHash4 } from "node:crypto";
15029
+ import { readFileSync as readFileSync5 } from "node:fs";
15030
+ import { dirname as dirname3, resolve as resolve6 } from "node:path";
15031
+ import { promisify } from "node:util";
15032
+ var execFileAsync = promisify(execFile);
15033
+ var runner = `
15034
+ import { pathToFileURL } from "node:url";
15035
+ import { basename, dirname } from "node:path";
15036
+ const [entry, appEntry, outfile, minify] = Bun.argv.slice(1);
15037
+ const plugin = await import(import.meta.resolve("elysia/plugin/aot/bun", pathToFileURL(appEntry).href));
15038
+ const result = await Bun.build({
15039
+ entrypoints: [entry], outdir: dirname(outfile), naming: { entry: basename(outfile) },
15040
+ target: "bun", format: "esm", splitting: false, metafile: true,
15041
+ minify: minify === "true", env: "disable",
15042
+ plugins: [plugin.aot(appEntry, {
15043
+ strip: false, production: false,
15044
+ registerFrom: Bun.fileURLToPath(import.meta.resolve("elysia", pathToFileURL(appEntry).href)),
15045
+ reconstructFrom: Bun.fileURLToPath(import.meta.resolve("elysia/reconstruct", pathToFileURL(appEntry).href))
15046
+ }), {
15047
+ name: "resolve-aot-manifest-dependencies",
15048
+ setup(build) {
15049
+ build.onResolve({ filter: /^(elysia|typebox)(\\/.*)?$/ }, ({ path }) => ({
15050
+ path: Bun.fileURLToPath(import.meta.resolve(path, pathToFileURL(appEntry).href))
15051
+ }));
15052
+ }
15053
+ }]
15054
+ });
15055
+ if (!result.success) throw new Error(result.logs.map(log => log.message).join("\\n"));
15056
+ if (!Object.keys(result.metafile.inputs).some(input => input.includes("elysia-aot") && input.endsWith("manifest"))) {
15057
+ throw new Error("AOT app entry is not in the bundle graph; compiled manifest was not injected");
15058
+ }
15059
+ if (result.outputs.length !== 1) throw new Error("AOT requires a single JavaScript bundle without sidecar assets");
15060
+ await Bun.write(outfile, await result.outputs[0].text());
15061
+ process.exit(0);
15062
+ `;
15063
+ function validateFunctionAot(args) {
15064
+ if (args.aot !== undefined && args.action !== "deploy") {
15065
+ throw new Error("'--aot' is only supported for 'deploy'");
15066
+ }
15067
+ if (args["aot-entry"] !== undefined && args.aot !== true) {
15068
+ throw new Error("'--aot-entry' requires '--aot'");
15069
+ }
15070
+ if (args.aot !== true)
15071
+ return;
15072
+ if (args.framework !== "elysia")
15073
+ throw new Error("'--aot' requires 'framework=elysia'");
15074
+ if (typeof args.path !== "string" || args.code !== undefined || args["prebundled-path"] !== undefined) {
15075
+ throw new Error("'--aot' requires '--path' without '--code' or '--prebundled-path'");
15076
+ }
15077
+ }
15078
+ async function buildFunctionAot(entrypoint, outfile, options = {}) {
15079
+ const env = {};
15080
+ for (const key of ["PATH", "HOME", "TMPDIR", "TMP", "TEMP", "SystemRoot"]) {
15081
+ if (process.env[key] !== undefined)
15082
+ env[key] = process.env[key];
15083
+ }
15084
+ env.NODE_ENV = "production";
15085
+ try {
15086
+ const { stderr } = await execFileAsync("bun", [
15087
+ "--no-env-file",
15088
+ "--eval",
15089
+ runner,
15090
+ resolve6(entrypoint),
15091
+ resolve6(options.appEntry ?? entrypoint),
15092
+ outfile,
15093
+ String(options.minify === true)
15094
+ ], {
15095
+ cwd: dirname3(entrypoint),
15096
+ env,
15097
+ timeout: 120000,
15098
+ killSignal: "SIGKILL",
15099
+ maxBuffer: 1024 * 1024
15100
+ });
15101
+ if (stderr)
15102
+ process.stderr.write(stderr);
15103
+ } catch (error) {
15104
+ const message = error instanceof Error ? error.message : String(error);
15105
+ throw new Error(`Local Elysia AOT build failed (Bun and the app's Elysia AOT plugin are required): ${message}`);
15106
+ }
15107
+ const code = readFileSync5(outfile, "utf8");
15108
+ if (!code.trim())
15109
+ throw new Error("AOT build produced an empty bundle");
15110
+ return { code, prebundled: true, expectedSha256: createHash4("sha256").update(code).digest("hex") };
15111
+ }
15024
15112
 
15025
15113
  // src/shared/tools/edge-function-response.ts
15026
15114
  var CANONICAL_VERSION_PATTERN = /^(?:0|[1-9][0-9]*)$/;
@@ -15162,6 +15250,8 @@ function projectedFunctionIdentity(payload, expectedProjectRef, expectedSlug) {
15162
15250
  const response = objectRecord(payload);
15163
15251
  if (!response || response.project_ref !== expectedProjectRef || response.slug !== expectedSlug || response.active_version !== "absent" && !canonicalVersion(response.active_version) || !validObservedFunctionActivationId(response.activation_id) || typeof response.verify_jwt !== "boolean" || !stringRoutes(response.background_routes))
15164
15252
  return null;
15253
+ if (response.bytecode !== undefined && !["off", "auto", "required"].includes(response.bytecode))
15254
+ return null;
15165
15255
  const optionalFields = optionalConfigFields(response);
15166
15256
  if (!optionalFields || !coherentFunctionVersion(response.active_version, optionalFields.version))
15167
15257
  return null;
@@ -15177,6 +15267,7 @@ function projectedFunctionIdentity(payload, expectedProjectRef, expectedSlug) {
15177
15267
  slug: expectedSlug,
15178
15268
  active_version: response.active_version,
15179
15269
  verify_jwt: response.verify_jwt,
15270
+ ...response.bytecode === undefined ? {} : { bytecode: response.bytecode },
15180
15271
  background_routes: response.background_routes,
15181
15272
  ...framework === undefined ? {} : { framework },
15182
15273
  ...optionalFields,
@@ -15194,6 +15285,10 @@ function configMatchesExpectation(response, expected) {
15194
15285
  }
15195
15286
  if (response.framework !== undefined && !FUNCTION_FRAMEWORKS.includes(response.framework))
15196
15287
  return false;
15288
+ if (response.bytecode !== undefined && !["off", "auto", "required"].includes(response.bytecode))
15289
+ return false;
15290
+ if (expected.bytecode !== undefined && response.bytecode !== expected.bytecode)
15291
+ return false;
15197
15292
  if (expected.verify_jwt !== undefined && response.verify_jwt !== expected.verify_jwt)
15198
15293
  return false;
15199
15294
  if (expected.framework !== undefined && response.framework !== expected.framework)
@@ -15223,6 +15318,7 @@ function confirmedFunctionConfigMutation(payload, expectation) {
15223
15318
  verify_jwt: response.verify_jwt,
15224
15319
  background_routes: response.background_routes,
15225
15320
  ...response.framework === undefined ? {} : { framework: response.framework },
15321
+ ...response.bytecode === undefined ? {} : { bytecode: response.bytecode },
15226
15322
  ...optionalFields,
15227
15323
  ...capabilities === undefined ? {} : { capabilities },
15228
15324
  ...limits === undefined ? {} : { limits }
@@ -15320,13 +15416,13 @@ function scaffoldFunction(pathArg, slug, framework) {
15320
15416
  if (typeof framework !== "string" || !FUNCTION_FRAMEWORKS2.includes(framework)) {
15321
15417
  throw new Error("'framework' required for 'scaffold'");
15322
15418
  }
15323
- const target = resolve6(typeof pathArg === "string" ? pathArg : join5("supabase", "functions", slug));
15419
+ const target = resolve7(typeof pathArg === "string" ? pathArg : join5("supabase", "functions", slug));
15324
15420
  if (existsSync5(target))
15325
15421
  throw new Error(`Scaffold target already exists: ${target}`);
15326
15422
  const files = scaffoldFiles(framework, slug);
15327
15423
  for (const [relativePath, contents] of Object.entries(files)) {
15328
15424
  const destination = join5(target, relativePath);
15329
- mkdirSync(resolve6(destination, ".."), { recursive: true });
15425
+ mkdirSync(resolve7(destination, ".."), { recursive: true });
15330
15426
  writeFileSync(destination, contents, { flag: "wx" });
15331
15427
  }
15332
15428
  return JSON.stringify({ success: true, framework, path: target, files: Object.keys(files) }, null, 2);
@@ -15364,17 +15460,17 @@ function assertExpectedSha256(bytes, expectedSha256) {
15364
15460
  if (!SHA256_HEX_PATTERN.test(expectedSha256)) {
15365
15461
  throw new Error("'--expected-sha256' must be a lowercase 64-character SHA-256");
15366
15462
  }
15367
- const actualDigest = createHash4("sha256").update(bytes).digest();
15463
+ const actualDigest = createHash5("sha256").update(bytes).digest();
15368
15464
  const expectedDigest = Buffer.from(expectedSha256, "hex");
15369
15465
  if (!timingSafeEqual(actualDigest, expectedDigest)) {
15370
15466
  throw new Error("Prebundled file SHA-256 does not match --expected-sha256");
15371
15467
  }
15372
15468
  }
15373
15469
  function readVerifiedPrebundledCode(pathArg, expectedSha256) {
15374
- const descriptor = openSync(resolve6(pathArg), fsConstants.O_RDONLY | fsConstants.O_NONBLOCK);
15470
+ const descriptor = openSync(resolve7(pathArg), fsConstants.O_RDONLY | fsConstants.O_NONBLOCK);
15375
15471
  try {
15376
15472
  const identityBeforeRead = openFileIdentity(descriptor);
15377
- const bytes = readFileSync5(descriptor);
15473
+ const bytes = readFileSync6(descriptor);
15378
15474
  const identityAfterRead = openFileIdentity(descriptor);
15379
15475
  if (BigInt(bytes.byteLength) !== identityBeforeRead.size || !sameOpenFile(identityBeforeRead, identityAfterRead)) {
15380
15476
  throw new Error("Prebundled file changed while it was being read");
@@ -15408,7 +15504,7 @@ function readBundleDirectory(root, directory = root) {
15408
15504
  }
15409
15505
  if (!entryState.isFile())
15410
15506
  throw new Error(`Bundle directory must contain only regular files: ${bundlePath}`);
15411
- files[bundlePath] = verifiedUtf8Code(readFileSync5(entryPath));
15507
+ files[bundlePath] = verifiedUtf8Code(readFileSync6(entryPath));
15412
15508
  }
15413
15509
  return files;
15414
15510
  }
@@ -15420,7 +15516,7 @@ function preparedBundleFiles(args) {
15420
15516
  }
15421
15517
  if (typeof bundleDirectory !== "string")
15422
15518
  return files;
15423
- const resolvedDirectory = resolve6(bundleDirectory);
15519
+ const resolvedDirectory = resolve7(bundleDirectory);
15424
15520
  const rootState = lstatSync(resolvedDirectory);
15425
15521
  if (rootState.isSymbolicLink() || !rootState.isDirectory()) {
15426
15522
  throw new Error("'--bundle-dir' must be a regular directory and must not be a symlink");
@@ -15501,6 +15597,17 @@ async function preparedDeployCode(args) {
15501
15597
  return { code: codeArg, prebundled: false };
15502
15598
  if (typeof pathArg !== "string")
15503
15599
  throw new Error("Function deploy source is invalid");
15600
+ if (args.aot === true) {
15601
+ const directory = mkdtempSync(join5(tmpdir(), "supacloud-function-aot-"));
15602
+ try {
15603
+ return await buildFunctionAot(resolveEntrypoint(pathArg), join5(directory, "index.js"), {
15604
+ ...typeof args["aot-entry"] === "string" ? { appEntry: args["aot-entry"] } : {},
15605
+ minify: args.minify === true
15606
+ });
15607
+ } finally {
15608
+ rmSync(directory, { recursive: true, force: true });
15609
+ }
15610
+ }
15504
15611
  return bundledDeployCode(pathArg);
15505
15612
  }
15506
15613
  async function bundledDeployCode(pathArg) {
@@ -15522,7 +15629,7 @@ function rejectActionSpecificFlags(action, args) {
15522
15629
  }
15523
15630
  }
15524
15631
  function resolveEntrypoint(pathArg) {
15525
- const resolved = resolve6(pathArg);
15632
+ const resolved = resolve7(pathArg);
15526
15633
  const stat = statSync4(resolved);
15527
15634
  if (!stat.isDirectory())
15528
15635
  return resolved;
@@ -15800,6 +15907,10 @@ function confirmedFunctionConfig(payload, expected) {
15800
15907
  return false;
15801
15908
  if (expected.framework !== undefined && response.framework !== expected.framework)
15802
15909
  return false;
15910
+ if (response.bytecode !== undefined && response.bytecode !== "off" && response.bytecode !== "auto" && response.bytecode !== "required")
15911
+ return false;
15912
+ if (expected.bytecode !== undefined && response.bytecode !== expected.bytecode)
15913
+ return false;
15803
15914
  if (expected.background_routes !== undefined) {
15804
15915
  if (!Array.isArray(response.background_routes))
15805
15916
  return false;
@@ -15830,7 +15941,7 @@ function functionSourceOutput(slug, sourceCode, output) {
15830
15941
  if (!output) {
15831
15942
  return { content: [{ type: "text", text: JSON.stringify({ code: sourceCode }, null, 2) }] };
15832
15943
  }
15833
- const outputPath = resolve6(output);
15944
+ const outputPath = resolve7(output);
15834
15945
  writeFileSync(outputPath, sourceCode, { flag: "wx" });
15835
15946
  return {
15836
15947
  content: [{
@@ -15914,6 +16025,7 @@ function confirmedFunctionMutation(expectation, payload) {
15914
16025
  activeVersion,
15915
16026
  activationId,
15916
16027
  verifyJwt: config.verify_jwt,
16028
+ ...config.bytecode === undefined ? {} : { bytecode: config.bytecode },
15917
16029
  ...framework === undefined ? {} : { framework },
15918
16030
  ...config.capabilities === undefined ? {} : { capabilities: config.capabilities },
15919
16031
  ...config.limits === undefined ? {} : { limits: config.limits }
@@ -15935,6 +16047,7 @@ function functionMutationResponse(expectation, response) {
15935
16047
  active_version: confirmed.activeVersion,
15936
16048
  version: confirmed.activeVersion,
15937
16049
  verify_jwt: confirmed.verifyJwt,
16050
+ ...confirmed.bytecode === undefined ? {} : { bytecode: confirmed.bytecode },
15938
16051
  ...confirmed.framework === undefined ? {} : { framework: confirmed.framework },
15939
16052
  ...confirmed.capabilities === undefined ? {} : { capabilities: confirmed.capabilities },
15940
16053
  ...confirmed.limits === undefined ? {} : { limits: confirmed.limits }
@@ -16013,7 +16126,10 @@ Actions: list, get_config, deploy, deploy_bundle, config, source, activate, dele
16013
16126
  "bundle-dir": optional(String2(), "[deploy_bundle] Local self-contained UTF-8 bundle directory; excludes node_modules, .git, AppleDouble, symlinks, and special files"),
16014
16127
  entrypoint: optional(String2(), "[deploy_bundle] Entrypoint file (default: index.ts)"),
16015
16128
  minify: optional(Boolean2(), "[deploy/deploy_bundle] Minify bundle"),
16129
+ aot: optional(Boolean2(), "[deploy] Experimental: execute trusted local Elysia initialization to precompile before uploading; off by default"),
16130
+ "aot-entry": optional(String2(), "[deploy --aot] Module exporting the Elysia app (defaults to path)"),
16016
16131
  verify_jwt: optional(Boolean2(), "[deploy/deploy_bundle/config] Set JWT verification for this function"),
16132
+ bytecode: optional(withDescription(stringEnum2(["off", "auto", "required"]), "[deploy/deploy_bundle/config] Generate Bun bytecode during Edge Runtime preheat")),
16017
16133
  background_routes: withDescription(backgroundRoutesSchema, "[deploy/deploy_bundle/config] Background route paths; pass comma-separated or JSON array in CLI"),
16018
16134
  framework: optional(withDescription(stringEnum2(["fetch", "elysia", "hono", "sveltekit-function"]), "[deploy/deploy_bundle/config/scaffold] Fetch framework adapter profile")),
16019
16135
  capabilities: optional(functionCapabilitiesSchema, "[deploy/deploy_bundle/config] Host capabilities: secrets, outbound_hosts, bindings, background"),
@@ -16023,6 +16139,13 @@ Actions: list, get_config, deploy, deploy_bundle, config, source, activate, dele
16023
16139
  "expected-active-version": withDescription(expectedActiveVersionSchema, "[deploy/deploy_bundle/activate] Required current active version, or 'absent' when none exists"),
16024
16140
  "expected-activation-id": withDescription(expectedActivationIdSchema, "[deploy/deploy_bundle/config/activate/delete] Required activation ID from list, or 'legacy' for a new or legacy function")
16025
16141
  }, async (args) => {
16142
+ if (args.aot === true && options.readOnly) {
16143
+ return {
16144
+ isError: true,
16145
+ content: [{ type: "text", text: "⚠️ Edge Function AOT deployment blocked in read-only mode." }]
16146
+ };
16147
+ }
16148
+ validateFunctionAot(args);
16026
16149
  if (args.action === "activate")
16027
16150
  return activateFunctionVersion(http, args, options.readOnly);
16028
16151
  if (args.action === "scaffold") {
@@ -16037,6 +16160,7 @@ Actions: list, get_config, deploy, deploy_bundle, config, source, activate, dele
16037
16160
  entrypoint,
16038
16161
  minify,
16039
16162
  verify_jwt,
16163
+ bytecode,
16040
16164
  background_routes,
16041
16165
  framework,
16042
16166
  capabilities,
@@ -16060,6 +16184,7 @@ Actions: list, get_config, deploy, deploy_bundle, config, source, activate, dele
16060
16184
  } : undefined;
16061
16185
  const functionConfig = () => ({
16062
16186
  ...typeof verify_jwt === "boolean" ? { verify_jwt } : {},
16187
+ ...bytecode === undefined ? {} : { bytecode },
16063
16188
  ...Array.isArray(background_routes) ? { background_routes } : {},
16064
16189
  ...framework === undefined ? {} : { framework },
16065
16190
  ...capabilities === undefined ? {} : { capabilities },
@@ -16368,13 +16493,13 @@ ${JSON.stringify(r.data, null, 2)}` : `❌ Failed (${r.status}): ${JSON.stringif
16368
16493
  }
16369
16494
 
16370
16495
  // src/shared/tools/frontend-release-control.ts
16371
- import { createHash as createHash6 } from "node:crypto";
16496
+ import { createHash as createHash7 } from "node:crypto";
16372
16497
  import { constants as fsConstants2 } from "node:fs";
16373
16498
  import { open as open2 } from "node:fs/promises";
16374
- import { resolve as resolve7 } from "node:path";
16499
+ import { resolve as resolve8 } from "node:path";
16375
16500
 
16376
16501
  // src/shared/mutation-protocol.ts
16377
- import { createHash as createHash5 } from "node:crypto";
16502
+ import { createHash as createHash6 } from "node:crypto";
16378
16503
  var MUTATION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
16379
16504
  var FINGERPRINT_PATTERN = /^[0-9a-f]{64}$/;
16380
16505
  var OPERATION_PATTERN = /^[a-z0-9][a-z0-9._:-]{0,127}$/;
@@ -16453,7 +16578,7 @@ function stableStringifyNode(jsonValue) {
16453
16578
  }
16454
16579
  function mutationRequestFingerprint(normalizedRequest) {
16455
16580
  assertCanonicalJsonNode(normalizedRequest, new WeakSet, 0);
16456
- return createHash5("sha256").update(stableStringifyNode(normalizedRequest)).digest("hex");
16581
+ return createHash6("sha256").update(stableStringifyNode(normalizedRequest)).digest("hex");
16457
16582
  }
16458
16583
  function objectRecord3(candidate) {
16459
16584
  return candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : null;
@@ -16742,7 +16867,7 @@ function sameArchiveIdentity(left, right) {
16742
16867
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs;
16743
16868
  }
16744
16869
  async function archiveSha256(handle, sizeBytes) {
16745
- const hash = createHash6("sha256");
16870
+ const hash = createHash7("sha256");
16746
16871
  const chunk = new Uint8Array(Math.min(sizeBytes, ARCHIVE_CHUNK_BYTES));
16747
16872
  for (let offset = 0;offset < sizeBytes; ) {
16748
16873
  const requested = Math.min(chunk.byteLength, sizeBytes - offset);
@@ -16755,7 +16880,7 @@ async function archiveSha256(handle, sizeBytes) {
16755
16880
  return hash.digest("hex");
16756
16881
  }
16757
16882
  async function verifiedArchive(path) {
16758
- const archivePath = resolve7(path);
16883
+ const archivePath = resolve8(path);
16759
16884
  const handle = await open2(archivePath, fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW);
16760
16885
  try {
16761
16886
  const before = await handle.stat({ bigint: true });
@@ -16877,7 +17002,7 @@ function stableJson(candidate) {
16877
17002
  return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
16878
17003
  }
16879
17004
  function activationFingerprint(identity) {
16880
- return createHash6("sha256").update(stableJson({
17005
+ return createHash7("sha256").update(stableJson({
16881
17006
  project_ref: identity.projectRef,
16882
17007
  deployment_id: identity.deploymentId,
16883
17008
  release_id: identity.releaseId,
@@ -20365,7 +20490,7 @@ function registerBranchTools(server, http, options = {}) {
20365
20490
 
20366
20491
  // src/shared/tools/supabase-cli-tools.ts
20367
20492
  import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, statSync as statSync5, writeFileSync as writeFileSync2 } from "node:fs";
20368
- import { dirname as dirname3, isAbsolute as isAbsolute2, join as join6, resolve as resolve8 } from "node:path";
20493
+ import { dirname as dirname4, isAbsolute as isAbsolute2, join as join6, resolve as resolve9 } from "node:path";
20369
20494
  var SENSITIVE_ENV_KEY = /(?:^|_)(?:PASSWORD|PASS|SECRET|TOKEN|KEY|CREDENTIALS?|AUTHORIZATION|AUTH|SESSION|COOKIE|BEARER|DB_URI|DB_URL|DSN|DATABASE_URL|DATABASE_URI|CONNECTION_STRING|CONNECTION_URI)(?:_|$)/i;
20370
20495
  var VALID_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
20371
20496
  var VALID_MIGRATION_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]{0,100}$/;
@@ -20410,12 +20535,12 @@ function schemaArguments(schema) {
20410
20535
  function workdirArguments(workdir) {
20411
20536
  if (!workdir)
20412
20537
  throw new Error("A workdir is required");
20413
- return ["--workdir", resolve8(workdir)];
20538
+ return ["--workdir", resolve9(workdir)];
20414
20539
  }
20415
20540
  function resolveOutputPath(workdir, file, label) {
20416
20541
  if (!file || /[\r\n\0]/.test(file))
20417
20542
  throw new Error(`${label} file is required`);
20418
- return isAbsolute2(file) ? resolve8(file) : resolve8(workdir, file);
20543
+ return isAbsolute2(file) ? resolve9(file) : resolve9(workdir, file);
20419
20544
  }
20420
20545
  function databaseTargetArguments(databaseUrl) {
20421
20546
  return databaseUrl ? ["--db-url", requirePostgresUrl(databaseUrl)] : ["--local"];
@@ -20590,7 +20715,7 @@ function actionArguments(request, workdir) {
20590
20715
  function buildOfficialSupabaseArgs(request) {
20591
20716
  if (request.action === "version")
20592
20717
  return ["--version"];
20593
- const workdir = request.workdir ? resolve8(request.workdir) : undefined;
20718
+ const workdir = request.workdir ? resolve9(request.workdir) : undefined;
20594
20719
  if (!workdir)
20595
20720
  throw new Error("A workdir is required");
20596
20721
  return [...actionArguments(request, workdir), ...workdirArguments(workdir)];
@@ -20667,13 +20792,13 @@ function resolveOfficialSupabaseCommand(workdir, environment = process.env) {
20667
20792
  }
20668
20793
  return ["npx", "--yes", `supabase@${version}`];
20669
20794
  }
20670
- const localPackageEntry = join6(resolve8(workdir), "node_modules", "supabase", "dist", "supabase.js");
20795
+ const localPackageEntry = join6(resolve9(workdir), "node_modules", "supabase", "dist", "supabase.js");
20671
20796
  if (existsSync6(localPackageEntry))
20672
20797
  return [process.execPath, localPackageEntry];
20673
20798
  return ["supabase"];
20674
20799
  }
20675
20800
  function resolveExistingWorkdir(workdirInput, fallback) {
20676
- const workdir = resolve8(workdirInput || fallback);
20801
+ const workdir = resolve9(workdirInput || fallback);
20677
20802
  if (!existsSync6(workdir) || !statSync5(workdir).isDirectory()) {
20678
20803
  throw new Error(`Supabase workdir not found: ${workdir}`);
20679
20804
  }
@@ -20774,7 +20899,7 @@ async function executeMigrationPush(request, runtime) {
20774
20899
  if (!projectRef)
20775
20900
  return missingProjectRefResult();
20776
20901
  const workdir = resolveExistingWorkdir(request.workdir, runtime.fallbackWorkdir);
20777
- const migrationDirectory = resolve8(workdir, request.dir || "supabase/migrations");
20902
+ const migrationDirectory = resolve9(workdir, request.dir || "supabase/migrations");
20778
20903
  const migrationResponse = await pushMigrations({
20779
20904
  action: "push_migrations",
20780
20905
  ref: projectRef,
@@ -20811,7 +20936,7 @@ async function executeOfficialAction(request, runtime) {
20811
20936
  buildOfficialSupabaseArgs(normalizedRequest);
20812
20937
  const outputPath = actionOutputPath(normalizedRequest, workdir);
20813
20938
  if (outputPath)
20814
- mkdirSync2(dirname3(outputPath), { recursive: true });
20939
+ mkdirSync2(dirname4(outputPath), { recursive: true });
20815
20940
  const secrets = sensitiveValues(runtime.environment, request.db_url);
20816
20941
  const execution = await runtime.executeOfficialCli(normalizedRequest);
20817
20942
  if (execution.exitCode === 0 && request.action === "gen_types" && outputPath) {
@@ -20887,11 +21012,11 @@ function registerSupabaseCliTools(server, options = {}) {
20887
21012
 
20888
21013
  // src/shared/tools/lite-cli-tools.ts
20889
21014
  import { existsSync as existsSync8, statSync as statSync7 } from "node:fs";
20890
- import { resolve as resolve10 } from "node:path";
21015
+ import { resolve as resolve11 } from "node:path";
20891
21016
 
20892
21017
  // src/shared/tools/lite-cli-command.ts
20893
- import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync6 } from "node:fs";
20894
- import { isAbsolute as isAbsolute3, join as join7, relative as relative3, resolve as resolve9 } from "node:path";
21018
+ import { existsSync as existsSync7, readFileSync as readFileSync7, statSync as statSync6 } from "node:fs";
21019
+ import { isAbsolute as isAbsolute3, join as join7, relative as relative3, resolve as resolve10 } from "node:path";
20895
21020
  function isRecord5(value) {
20896
21021
  return value !== null && typeof value === "object" && !Array.isArray(value);
20897
21022
  }
@@ -20902,11 +21027,11 @@ function resolveLiteCommand(workdir, environment = process.env) {
20902
21027
  throw new Error("Invalid SUPACLOUD_LITE_CLI_BIN");
20903
21028
  return [explicitBinary];
20904
21029
  }
20905
- const packageRoot = join7(resolve9(workdir), "node_modules", "@supacloud", "lite");
21030
+ const packageRoot = join7(resolve10(workdir), "node_modules", "@supacloud", "lite");
20906
21031
  const manifestPath = join7(packageRoot, "package.json");
20907
21032
  if (!existsSync7(manifestPath))
20908
21033
  return ["supacloud-lite"];
20909
- const manifest = JSON.parse(readFileSync6(manifestPath, "utf8"));
21034
+ const manifest = JSON.parse(readFileSync7(manifestPath, "utf8"));
20910
21035
  if (!isRecord5(manifest) || manifest.name !== "@supacloud/lite" || !isRecord5(manifest.bin)) {
20911
21036
  throw new Error("Invalid installed @supacloud/lite package manifest");
20912
21037
  }
@@ -20914,7 +21039,7 @@ function resolveLiteCommand(workdir, environment = process.env) {
20914
21039
  if (typeof entry !== "string" || !entry.trim() || entry.includes("\x00") || isAbsolute3(entry)) {
20915
21040
  throw new Error("Invalid installed @supacloud/lite bin");
20916
21041
  }
20917
- const executable = resolve9(packageRoot, entry);
21042
+ const executable = resolve10(packageRoot, entry);
20918
21043
  const packageRelative = relative3(packageRoot, executable);
20919
21044
  if (!packageRelative || packageRelative === ".." || packageRelative.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute3(packageRelative)) {
20920
21045
  throw new Error("Installed @supacloud/lite bin must stay inside its package");
@@ -20926,7 +21051,7 @@ function resolveLiteCommand(workdir, environment = process.env) {
20926
21051
  }
20927
21052
  // src/shared/tools/lite-cli-tools.ts
20928
21053
  function requireWorkdir(workdir, fallback) {
20929
- const resolved = resolve10(workdir || fallback);
21054
+ const resolved = resolve11(workdir || fallback);
20930
21055
  if (!existsSync8(resolved) || !statSync7(resolved).isDirectory()) {
20931
21056
  throw new Error(`Lite workdir not found: ${resolved}`);
20932
21057
  }
@@ -21135,12 +21260,12 @@ import {
21135
21260
  mkdirSync as mkdirSync3,
21136
21261
  mkdtempSync as mkdtempSync2,
21137
21262
  readdirSync as readdirSync4,
21138
- readFileSync as readFileSync7,
21263
+ readFileSync as readFileSync8,
21139
21264
  renameSync,
21140
21265
  rmSync as rmSync2
21141
21266
  } from "node:fs";
21142
21267
  import { homedir as homedir2 } from "node:os";
21143
- import { dirname as dirname4, join as join8, relative as relative4, resolve as resolve11, sep as sep3 } from "node:path";
21268
+ import { dirname as dirname5, join as join8, relative as relative4, resolve as resolve12, sep as sep3 } from "node:path";
21144
21269
  import { fileURLToPath } from "node:url";
21145
21270
  var SKILL_NAME = "supacloud";
21146
21271
  function regularFiles(rootDirectory, currentDirectory = rootDirectory) {
@@ -21163,7 +21288,7 @@ function directoriesMatch(sourceDirectory, destinationDirectory) {
21163
21288
  const destinationFiles = regularFiles(destinationDirectory);
21164
21289
  if (sourceFiles.join("\x00") !== destinationFiles.join("\x00"))
21165
21290
  return false;
21166
- return sourceFiles.every((file) => readFileSync7(join8(sourceDirectory, file)).equals(readFileSync7(join8(destinationDirectory, file))));
21291
+ return sourceFiles.every((file) => readFileSync8(join8(sourceDirectory, file)).equals(readFileSync8(join8(destinationDirectory, file))));
21167
21292
  }
21168
21293
  function backupTimestamp(now) {
21169
21294
  return now.toISOString().replace(/[-:.]/g, "");
@@ -21213,8 +21338,8 @@ function replaceSkill(sourceDirectory, targetRoot, destinationDirectory, backupD
21213
21338
  }
21214
21339
  }
21215
21340
  function skillSummary(request, action, files, backupDirectory) {
21216
- const sourceDirectory = resolve11(request.sourceDirectory);
21217
- const targetRoot = resolve11(request.targetRoot);
21341
+ const sourceDirectory = resolve12(request.sourceDirectory);
21342
+ const targetRoot = resolve12(request.targetRoot);
21218
21343
  return {
21219
21344
  name: SKILL_NAME,
21220
21345
  sourceDirectory,
@@ -21228,8 +21353,8 @@ function skillSummary(request, action, files, backupDirectory) {
21228
21353
  };
21229
21354
  }
21230
21355
  function installSkill(request) {
21231
- const sourceDirectory = resolve11(request.sourceDirectory);
21232
- const targetRoot = resolve11(request.targetRoot);
21356
+ const sourceDirectory = resolve12(request.sourceDirectory);
21357
+ const targetRoot = resolve12(request.targetRoot);
21233
21358
  const destinationDirectory = join8(targetRoot, SKILL_NAME);
21234
21359
  if (!existsSync9(join8(sourceDirectory, "SKILL.md"))) {
21235
21360
  throw new Error(`Bundled SupaCloud CLI skill not found: ${sourceDirectory}`);
@@ -21246,16 +21371,16 @@ function installSkill(request) {
21246
21371
  return installReplacementSkill(request, files);
21247
21372
  }
21248
21373
  function installNewSkill(request, files) {
21249
- const sourceDirectory = resolve11(request.sourceDirectory);
21250
- const targetRoot = resolve11(request.targetRoot);
21374
+ const sourceDirectory = resolve12(request.sourceDirectory);
21375
+ const targetRoot = resolve12(request.targetRoot);
21251
21376
  if (request.mode === "write") {
21252
21377
  createSkill(sourceDirectory, targetRoot, join8(targetRoot, SKILL_NAME));
21253
21378
  }
21254
21379
  return skillSummary(request, "create", files, null);
21255
21380
  }
21256
21381
  function installReplacementSkill(request, files) {
21257
- const sourceDirectory = resolve11(request.sourceDirectory);
21258
- const targetRoot = resolve11(request.targetRoot);
21382
+ const sourceDirectory = resolve12(request.sourceDirectory);
21383
+ const targetRoot = resolve12(request.targetRoot);
21259
21384
  const destinationDirectory = join8(targetRoot, SKILL_NAME);
21260
21385
  const backupDirectory = availableBackupDirectory(destinationDirectory, request.now);
21261
21386
  if (request.mode === "write") {
@@ -21265,13 +21390,13 @@ function installReplacementSkill(request, files) {
21265
21390
  }
21266
21391
  function resolveDefaultCodexSkillRoot(environment = process.env, homeDirectory = homedir2()) {
21267
21392
  const codexHome = environment.CODEX_HOME?.trim();
21268
- return join8(resolve11(codexHome || join8(homeDirectory, ".codex")), "skills");
21393
+ return join8(resolve12(codexHome || join8(homeDirectory, ".codex")), "skills");
21269
21394
  }
21270
21395
  function resolveBundledSkillDirectory(moduleUrl = import.meta.url) {
21271
- const moduleDirectory = dirname4(fileURLToPath(moduleUrl));
21396
+ const moduleDirectory = dirname5(fileURLToPath(moduleUrl));
21272
21397
  const candidates = [
21273
- resolve11(moduleDirectory, "../../../skills", SKILL_NAME),
21274
- resolve11(moduleDirectory, "../skills", SKILL_NAME)
21398
+ resolve12(moduleDirectory, "../../../skills", SKILL_NAME),
21399
+ resolve12(moduleDirectory, "../skills", SKILL_NAME)
21275
21400
  ];
21276
21401
  const skillDirectory = candidates.find((candidate) => existsSync9(join8(candidate, "SKILL.md")));
21277
21402
  if (!skillDirectory)
@@ -21309,9 +21434,9 @@ function registerAiTools(server) {
21309
21434
  }
21310
21435
 
21311
21436
  // src/shared/tools/app-tools.ts
21312
- import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
21437
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
21313
21438
  import { mkdir as mkdir5, readFile as readFile4, readdir as readdir5, writeFile as writeFile4 } from "node:fs/promises";
21314
- import { basename as basename7, dirname as dirname8, join as join13, relative as relative7, resolve as resolve17 } from "node:path";
21439
+ import { basename as basename7, dirname as dirname9, join as join13, relative as relative7, resolve as resolve18 } from "node:path";
21315
21440
  import {
21316
21441
  applyDiagnosticFix,
21317
21442
  buildDeliveryProject,
@@ -21319,12 +21444,14 @@ import {
21319
21444
  compileProject,
21320
21445
  compileOptionsFromConfig,
21321
21446
  createContextPack,
21447
+ createExecutionContextPack,
21322
21448
  createDiagnosticRepairPlan,
21323
21449
  doctorProject,
21324
21450
  loadSupacloudConfig,
21325
21451
  formatDeliveryPlan,
21326
21452
  planDeliveryProject,
21327
21453
  resolveSupacloudConfig,
21454
+ readExecutionMetadata,
21328
21455
  watchProject
21329
21456
  } from "@supacloud/compiler";
21330
21457
 
@@ -21447,25 +21574,25 @@ var starter_metadata_default = {
21447
21574
  generatedBy: "supacloud/starter-metadata-v1",
21448
21575
  packages: {
21449
21576
  compiler: {
21450
- version: "0.46.6"
21577
+ version: "0.47.2"
21451
21578
  },
21452
21579
  app: {
21453
- version: "0.27.1",
21580
+ version: "0.28.2",
21454
21581
  dependencies: {
21455
21582
  rxjs: "7.8.2"
21456
21583
  }
21457
21584
  },
21458
21585
  elysia: {
21459
- version: "0.33.1"
21586
+ version: "0.33.4"
21460
21587
  },
21461
21588
  commands: {
21462
- version: "0.9.3"
21589
+ version: "0.9.6"
21463
21590
  },
21464
21591
  contracts: {
21465
- version: "0.11.1"
21592
+ version: "0.11.4"
21466
21593
  },
21467
21594
  db: {
21468
- version: "0.18.0",
21595
+ version: "0.18.3",
21469
21596
  peerDependencies: {
21470
21597
  "drizzle-orm": "1.0.0-rc.5-5935859"
21471
21598
  },
@@ -21474,7 +21601,7 @@ var starter_metadata_default = {
21474
21601
  }
21475
21602
  },
21476
21603
  sdk: {
21477
- version: "0.43.0",
21604
+ version: "0.43.3",
21478
21605
  peerDependencies: {
21479
21606
  "@supabase/supabase-js": "^2.117.3"
21480
21607
  }
@@ -21579,7 +21706,7 @@ test("cancelled stream consumers release their subscription", async () => {
21579
21706
 
21580
21707
  // src/shared/tools/app-starter.ts
21581
21708
  import { lstat as lstat2, mkdir as mkdir3, readdir as readdir3, writeFile as writeFile3 } from "node:fs/promises";
21582
- import { basename as basename6, dirname as dirname5, join as join9, resolve as resolve12 } from "node:path";
21709
+ import { basename as basename6, dirname as dirname6, join as join9, resolve as resolve13 } from "node:path";
21583
21710
 
21584
21711
  // src/shared/tools/app-starter-environment.ts
21585
21712
  var STARTER_ENVIRONMENT = String.raw`import { existsSync, readFileSync } from "node:fs";
@@ -22264,10 +22391,11 @@ var STARTER_REVIEW_JOB = `import { DB_CLIENT, Inject, Injectable, Job } from "@s
22264
22391
  import { ApplicationError } from "@supacloud/elysia";
22265
22392
  import { t } from "elysia";
22266
22393
  import type { Static } from "elysia/type";
22394
+ import { REVIEW_VERSION_MAX } from "./limits";
22267
22395
 
22268
22396
  export const AttachmentInput = t.Object({
22269
22397
  reviewId: t.String({ minLength: 1, maxLength: 100 }),
22270
- version: t.Integer({ minimum: 2 }),
22398
+ version: t.Integer({ minimum: 2, maximum: REVIEW_VERSION_MAX }),
22271
22399
  artifactId: t.String({ format: "uuid" }),
22272
22400
  }, { additionalProperties: false });
22273
22401
 
@@ -23701,11 +23829,19 @@ export function createReviewClient(transport: ReviewTransport, pending?: ReviewP
23701
23829
  try { listener(); } catch {}
23702
23830
  }
23703
23831
  };
23704
- function finish(operation: ReviewOperation, result: ReviewWriteResult) {
23832
+ function outcome(operation: ReviewOperation, result: unknown): ReviewWriteResult["status"] {
23833
+ try {
23834
+ if (result === null || typeof result !== "object" || Array.isArray(result) || !("status" in result)) return "unknown";
23835
+ const status = result.status;
23836
+ if (status === "denied" || status === "conflict") return status;
23837
+ if (status === "confirmed" && "operationId" in result && "reviewId" in result
23838
+ && result.operationId === operation.operationId && result.reviewId === operation.reviewId) return "confirmed";
23839
+ } catch { /* Invalid adapters must not discard recovery evidence. */ }
23840
+ return "unknown";
23841
+ }
23842
+ function finish(operation: ReviewOperation, result: unknown) {
23705
23843
  if (closed) return;
23706
- let status = result.status === "confirmed"
23707
- && (result.operationId !== operation.operationId || result.reviewId !== operation.reviewId)
23708
- ? "unknown" : result.status;
23844
+ let status = outcome(operation, result);
23709
23845
  if (status !== "unknown") {
23710
23846
  try {
23711
23847
  if (pending) {
@@ -23722,6 +23858,7 @@ export function createReviewClient(transport: ReviewTransport, pending?: ReviewP
23722
23858
  const request = ++generation;
23723
23859
  state = { ...state, list: { status: "loading", rows: [] } };
23724
23860
  notify();
23861
+ if (closed || request !== generation) return;
23725
23862
  try {
23726
23863
  const rows = await transport.list();
23727
23864
  if (closed || request !== generation) return;
@@ -23786,7 +23923,10 @@ export function createReviewClient(transport: ReviewTransport, pending?: ReviewP
23786
23923
  try {
23787
23924
  const result = await transport.lookup(structuredClone(operation));
23788
23925
  // Denial or conflict during lookup does not prove the original write did not commit.
23789
- finish(operation, result.status === "confirmed" ? result : { status: "unknown" });
23926
+ // Normalize once: custom adapter accessors may change between reads.
23927
+ finish(operation, outcome(operation, result) === "confirmed"
23928
+ ? { status: "confirmed", operationId: operation.operationId, reviewId: operation.reviewId }
23929
+ : { status: "unknown" });
23790
23930
  if (snapshot().mutation.status === "confirmed") await load();
23791
23931
  } catch {
23792
23932
  finish(operation, { status: "unknown" });
@@ -23959,6 +24099,34 @@ test("list has loading, empty, permission and failure states; old results cannot
23959
24099
  expect(JSON.stringify(failed.snapshot())).not.toContain("private");
23960
24100
  }
23961
24101
  });
24102
+ test("disposing from a loading subscriber prevents read dispatch", async () => {
24103
+ let reads = 0;
24104
+ const client = createReviewClient(transport({ list: async () => { reads++; return [draft]; } }));
24105
+ client.subscribe(() => {
24106
+ if (client.snapshot().list.status === "loading") client.dispose();
24107
+ });
24108
+ await client.load();
24109
+ expect(reads).toBe(0);
24110
+ await client.load();
24111
+ expect(reads).toBe(0);
24112
+ });
24113
+
24114
+ test("a reentrant newer load supersedes the outer read before dispatch", async () => {
24115
+ let reads = 0, replaced = false;
24116
+ let replacement: Promise<void> | undefined;
24117
+ const client = createReviewClient(transport({ list: async () => { reads++; return [draft]; } }));
24118
+ client.subscribe(() => {
24119
+ if (!replaced && client.snapshot().list.status === "loading") {
24120
+ replaced = true;
24121
+ replacement = client.load();
24122
+ }
24123
+ });
24124
+ await client.load();
24125
+ await replacement;
24126
+ expect(reads).toBe(1);
24127
+ expect(client.snapshot().list).toEqual({ status: "ready", rows: [draft] });
24128
+ });
24129
+
23962
24130
  test("double submit sends one write; unknown retains its identity and only a lookup can confirm it", async () => {
23963
24131
  let sends = 0, lookups = 0, resolve: (result: ReviewWriteResult) => void = () => {};
23964
24132
  const client = createReviewClient(transport({
@@ -23991,6 +24159,72 @@ test("conflict refreshes but does not retry the write; wrong receipt remains unk
23991
24159
  await wrong.approve(draft);
23992
24160
  expect(wrong.snapshot().mutation.status).toBe("unknown");
23993
24161
  });
24162
+
24163
+ test("malformed adapter outcomes preserve pending evidence across writes and recovery", async () => {
24164
+ const malformed: unknown[] = [
24165
+ null, undefined, false, [], "confirmed", {}, { status: "complete" }, { status: 200 },
24166
+ { status: "confirmed" }, { status: "confirmed", operationId: "foreign", reviewId: draft.id },
24167
+ { get status() { throw new Error("private adapter detail"); } },
24168
+ ];
24169
+ for (const kind of ["approve", "upload"] as const) {
24170
+ for (const value of malformed) {
24171
+ let saved: ReviewOperation | null = null, sends = 0, clears = 0, reads = 0, recovered = false;
24172
+ const readSaved = (): ReviewOperation | null => saved;
24173
+ // Simulate an untyped/custom adapter crossing the public TypeScript boundary.
24174
+ const invalid = value as ReviewWriteResult;
24175
+ const send = async () => { sends++; return invalid; };
24176
+ const client = createReviewClient(transport({
24177
+ approve: send, upload: send,
24178
+ list: async () => { reads++; return []; },
24179
+ lookup: async op => recovered
24180
+ ? { status: "confirmed", operationId: op.operationId, reviewId: op.reviewId } : invalid,
24181
+ }), {
24182
+ load: () => saved, save: op => { saved = op; },
24183
+ clear: () => { clears++; saved = null; },
24184
+ });
24185
+ const submit = () => kind === "approve" ? client.approve(draft)
24186
+ : client.upload(uploadDraft, new Blob(["hello"], { type: "text/plain" }));
24187
+ await submit();
24188
+ const original = client.snapshot().mutation.operation;
24189
+ expect(original).not.toBeNull();
24190
+ expect(readSaved()).toEqual(original);
24191
+ expect(client.snapshot().mutation).toEqual({ status: "unknown", operation: original });
24192
+ await client.reconcile();
24193
+ await submit();
24194
+ expect(client.snapshot().mutation).toEqual({ status: "unknown", operation: original });
24195
+ expect(readSaved()).toEqual(original);
24196
+ expect(sends).toBe(1); expect(clears).toBe(0); expect(reads).toBe(0);
24197
+ expect(JSON.stringify(client.snapshot())).not.toContain("private adapter detail");
24198
+ recovered = true;
24199
+ await client.reconcile();
24200
+ expect(client.snapshot().mutation.status).toBe("confirmed");
24201
+ expect(readSaved()).toBeNull();
24202
+ expect(sends).toBe(1); expect(clears).toBe(1); expect(reads).toBe(1);
24203
+ }
24204
+ }
24205
+ });
24206
+ test("recovery validates adapter accessors once before clearing pending evidence", async () => {
24207
+ let saved: ReviewOperation | null = null, reads = 0, sends = 0, clears = 0;
24208
+ const client = createReviewClient(transport({
24209
+ approve: async () => { sends++; return { status: "unknown" }; },
24210
+ lookup: async operation => ({
24211
+ get status() { return ++reads === 1 ? "confirmed" as const : "denied" as const; },
24212
+ operationId: operation.operationId, reviewId: operation.reviewId,
24213
+ }),
24214
+ }), {
24215
+ load: () => saved, save: operation => { saved = operation; },
24216
+ clear: () => { clears++; saved = null; },
24217
+ });
24218
+ await client.approve(draft);
24219
+ expect(client.snapshot().mutation.status).toBe("unknown");
24220
+ await client.reconcile();
24221
+ expect(reads).toBe(1);
24222
+ expect(client.snapshot().mutation.status).toBe("confirmed");
24223
+ expect(saved).toBeNull();
24224
+ expect(clears).toBe(1);
24225
+ expect(sends).toBe(1);
24226
+ });
24227
+
23994
24228
  test("upload validates size/type, retains failure identity, and disposal drops late results", async () => {
23995
24229
  let uploads = 0;
23996
24230
  const client = createReviewClient(transport({ upload: async () => { uploads++; throw new Error("private"); } }));
@@ -24483,6 +24717,12 @@ export async function listReviews(
24483
24717
  const { data, error, count } = await (signal ? query.abortSignal(signal) : query);
24484
24718
  if (error) throw error;
24485
24719
  if (data === null || count === null) throw new Error("Incomplete review page response");
24720
+ if (!Array.isArray(data)
24721
+ || !Number.isSafeInteger(count) || count < 0
24722
+ || data.length > pageSize
24723
+ || (data.length > 0 && start + data.length > count)) {
24724
+ throw new Error("Invalid review page response");
24725
+ }
24486
24726
  return { data, total: count, page, pageSize, hasNextPage: start + data.length < count };
24487
24727
  }
24488
24728
  `;
@@ -25706,6 +25946,7 @@ handler contract, not production Storage, queue delivery or external identity.
25706
25946
  ## Inspection And Repair
25707
25947
 
25708
25948
  \`\`\`sh
25949
+ supacloud app context --root . --target review --events execution.ndjson --request-id request-123 --format json
25709
25950
  bunx supacloud-compiler context review --root src --json
25710
25951
  bunx supacloud-compiler context review --root src --events execution-events.json --request-id request-123 --json
25711
25952
  bunx supacloud-compiler explain review --root src
@@ -25715,6 +25956,11 @@ bunx supacloud-compiler fix ./fix.json --dry-run
25715
25956
 
25716
25957
  Context packs include directional dependencies, relevant aspect files, diagnostics
25717
25958
  and static execution plans, without provider values or source expressions.
25959
+ The app context entry point retains its module workflow and adds a separate
25960
+ execution evidence block when --events and --request-id are provided together.
25961
+ It requires an explicit --target and --format json, rejects --write, and
25962
+ resolves relative event paths from --root. The top-level context alias supports
25963
+ the same flags. Omit both execution flags for the unchanged authoring context.
25718
25964
  The optional --events example expects a trusted host
25719
25965
  to capture approved onExecution metadata in { "version": 1, "events": [...] }.
25720
25966
  It also accepts a bounded JSON-lines export containing only the generated
@@ -25746,7 +25992,7 @@ and governance; TypeScript checks both application and generated source.
25746
25992
  };
25747
25993
  }
25748
25994
  async function initializeAppProject(options) {
25749
- const root = resolve12(options.root ?? process.cwd());
25995
+ const root = resolve13(options.root ?? process.cwd());
25750
25996
  const name = options.name ?? basename6(root);
25751
25997
  if (!/^[a-z][a-z0-9-]*$/.test(name) || name.length > 100) {
25752
25998
  throw new Error("Project name must be lowercase kebab-case (1-100 characters)");
@@ -25765,7 +26011,7 @@ async function initializeAppProject(options) {
25765
26011
  });
25766
26012
  for (const [relativePath, content] of Object.entries(files)) {
25767
26013
  const path = join9(root, relativePath);
25768
- await mkdir3(dirname5(path), { recursive: true });
26014
+ await mkdir3(dirname6(path), { recursive: true });
25769
26015
  await writeFile3(path, content, { encoding: "utf8", flag: "wx" });
25770
26016
  }
25771
26017
  return { root, name, files: Object.keys(files) };
@@ -25773,7 +26019,7 @@ async function initializeAppProject(options) {
25773
26019
 
25774
26020
  // src/shared/tools/app-database-check.ts
25775
26021
  import { existsSync as existsSync10 } from "node:fs";
25776
- import { join as join10, resolve as resolve13 } from "node:path";
26022
+ import { join as join10, resolve as resolve14 } from "node:path";
25777
26023
  var CHECK_ENTRY = `
25778
26024
  import { createRequire } from "node:module";
25779
26025
  import { join } from "node:path";
@@ -25784,7 +26030,7 @@ process.argv = [process.execPath, cli, "check", "--root", root];
25784
26030
  await import(pathToFileURL(cli).href);
25785
26031
  `;
25786
26032
  function checkAppDatabaseSources(projectRoot) {
25787
- const root = resolve13(projectRoot);
26033
+ const root = resolve14(projectRoot);
25788
26034
  if (!existsSync10(join10(root, "database.sources.json")))
25789
26035
  return;
25790
26036
  const name = "database-source-contracts";
@@ -26024,6 +26270,7 @@ import type { StaticDecode } from "typebox";
26024
26270
 
26025
26271
  export type ${className}ListInput = StaticDecode<typeof ${className}ListQuery>;
26026
26272
  export type ${className}ApproveInput = StaticDecode<typeof ${className}ApproveBody>;
26273
+ export type ${className}ApproveCommand = ${className}ApproveInput & { id: string };
26027
26274
  export type ${className}Result = StaticDecode<typeof ${className}Row>;
26028
26275
 
26029
26276
  export interface ${className}ReadPort {
@@ -26032,11 +26279,7 @@ export interface ${className}ReadPort {
26032
26279
  }
26033
26280
 
26034
26281
  export interface ${className}WritePort {
26035
- approve(input: {
26036
- id: string;
26037
- expectedVersion: number;
26038
- reason?: string;
26039
- }): Promise<${className}Result>;
26282
+ approve(input: ${className}ApproveCommand): Promise<${className}Result>;
26040
26283
  }
26041
26284
 
26042
26285
  export const ${className}Reader = new InjectionToken<${className}ReadPort>(
@@ -26244,6 +26487,10 @@ The scaffold does not create migrations, infer permissions, or provide an in-mem
26244
26487
  production fallback. Database migrations remain the database source of truth.
26245
26488
  The HTTP schemas describe the boundary, not a second database model. Bind their
26246
26489
  fields to the existing database-source contract checker before delivery.
26490
+ The Writer input is derived from the approval body contract plus the route ID.
26491
+ Add request fields in the contract, not a second handwritten Writer interface.
26492
+ Typecheck application adapters after changing a field type; the derived Port
26493
+ must expose incompatible assumptions in business code.
26247
26494
 
26248
26495
  The named RPC adapter must invoke the continuation in the same database transaction
26249
26496
  used by the request-scoped Writer, or own the complete command instead; never execute
@@ -26289,7 +26536,7 @@ Scenario: Delivery
26289
26536
  // src/shared/tools/app-local-dev.ts
26290
26537
  import { spawn } from "node:child_process";
26291
26538
  import { readFile as readFile2 } from "node:fs/promises";
26292
- import { join as join11, resolve as resolve14 } from "node:path";
26539
+ import { join as join11, resolve as resolve15 } from "node:path";
26293
26540
  function localDatabaseUrl(value) {
26294
26541
  try {
26295
26542
  if (!value || /[\x00-\x20\x7f]/.test(value))
@@ -26336,7 +26583,7 @@ async function probeDatabase(url, signal) {
26336
26583
  }
26337
26584
  }
26338
26585
  async function runLocalDevelopment(options) {
26339
- const root = resolve14(options.root);
26586
+ const root = resolve15(options.root);
26340
26587
  const profile = options.profile ?? "fast";
26341
26588
  if (profile !== "fast" && profile !== "integration")
26342
26589
  throw new Error("Unknown development profile");
@@ -26437,7 +26684,7 @@ async function runLocalDevelopment(options) {
26437
26684
 
26438
26685
  // src/shared/tools/app-verification-plan.ts
26439
26686
  import { readdir as readdir4, realpath as realpath3 } from "node:fs/promises";
26440
- import { dirname as dirname6, isAbsolute as isAbsolute4, relative as relative5, resolve as resolve15 } from "node:path";
26687
+ import { dirname as dirname7, isAbsolute as isAbsolute4, relative as relative5, resolve as resolve16 } from "node:path";
26441
26688
  function inside2(root, file) {
26442
26689
  const path = relative5(root, file).replaceAll("\\", "/");
26443
26690
  return path !== ".." && !path.startsWith("../") && !isAbsolute4(path);
@@ -26448,9 +26695,10 @@ async function createVerificationPlan(root, graph, target, sourceRoot = root) {
26448
26695
  throw new Error("Select one unambiguous module or owned symbol for verification");
26449
26696
  const owner = owners[0];
26450
26697
  const project = await realpath3(root);
26451
- const requestedRoot = resolve15(root);
26698
+ const requestedRoot = resolve16(root);
26452
26699
  const sources = [
26453
26700
  owner.file,
26701
+ owner.featureSpec?.file,
26454
26702
  ...owner.providers.map((item) => item.file),
26455
26703
  ...owner.controllers.map((item) => item.file),
26456
26704
  ...graph.moduleHandlerFiles?.[owner.name] ?? [],
@@ -26459,7 +26707,7 @@ async function createVerificationPlan(root, graph, target, sourceRoot = root) {
26459
26707
  ...(owner.jobs ?? []).flatMap((item) => (item.aspects ?? []).flatMap((aspect) => aspect.file ? [aspect.file] : [])),
26460
26708
  ...owner.controllers.flatMap((item) => item.routes.flatMap((route) => (route.aspects ?? []).flatMap((aspect) => aspect.file ? [aspect.file] : [])))
26461
26709
  ].filter((file) => typeof file === "string");
26462
- const directories = [...new Set(sources.map((file) => dirname6(resolve15(sourceRoot, file))))].sort();
26710
+ const directories = [...new Set(sources.map((file) => dirname7(resolve16(sourceRoot, file))))].sort();
26463
26711
  const tests = new Set;
26464
26712
  const manual = [];
26465
26713
  const coverage = [];
@@ -26484,7 +26732,7 @@ async function createVerificationPlan(root, graph, target, sourceRoot = root) {
26484
26732
  const local = [];
26485
26733
  for (const entry of await readdir4(actual, { withFileTypes: true })) {
26486
26734
  if (entry.isFile() && /\.(test|spec)\.[cm]?[jt]sx?$/.test(entry.name)) {
26487
- const file = relative5(project, resolve15(actual, entry.name)).replaceAll("\\", "/");
26735
+ const file = relative5(project, resolve16(actual, entry.name)).replaceAll("\\", "/");
26488
26736
  tests.add(file);
26489
26737
  local.push(file);
26490
26738
  }
@@ -26504,7 +26752,7 @@ async function createVerificationPlan(root, graph, target, sourceRoot = root) {
26504
26752
  source: "declaration",
26505
26753
  target: owner.name,
26506
26754
  ready: manual.length === 0,
26507
- files: [...new Set(sources.map((file) => relative5(requestedRoot, resolve15(sourceRoot, file)).replaceAll("\\", "/")))].sort(),
26755
+ files: [...new Set(sources.map((file) => relative5(requestedRoot, resolve16(sourceRoot, file)).replaceAll("\\", "/")))].sort(),
26508
26756
  tests: selected.slice(0, 32),
26509
26757
  commands: selected.length <= 32 ? [
26510
26758
  ...selected.map((file) => ["bun", "test", `./${file}`]),
@@ -26525,7 +26773,7 @@ async function createVerificationPlan(root, graph, target, sourceRoot = root) {
26525
26773
  // src/shared/tools/app-scaffold-writes.ts
26526
26774
  import { randomUUID as randomUUID2 } from "node:crypto";
26527
26775
  import { link, lstat as lstat3, mkdir as mkdir4, open as open3, readFile as readFile3, realpath as realpath4, rename as rename2, rmdir, unlink } from "node:fs/promises";
26528
- import { dirname as dirname7, isAbsolute as isAbsolute5, join as join12, relative as relative6, resolve as resolve16, sep as sep4, win32 } from "node:path";
26776
+ import { dirname as dirname8, isAbsolute as isAbsolute5, join as join12, relative as relative6, resolve as resolve17, sep as sep4, win32 } from "node:path";
26529
26777
 
26530
26778
  class ScaffoldError extends Error {
26531
26779
  code;
@@ -26546,7 +26794,7 @@ function scaffoldPath(root, path) {
26546
26794
  if (parts.some((part) => /[<>:"|?*\u0000-\u001f]/.test(part) || /[ .]$/.test(part) && part !== "." && part !== ".." || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part) || part.toLowerCase() === ".git" || part.toLowerCase() === ".supacloud-generate.lock")) {
26547
26795
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is reserved or not portable");
26548
26796
  }
26549
- const target = resolve16(root, path);
26797
+ const target = resolve17(root, path);
26550
26798
  const local = relative6(root, target);
26551
26799
  if (!local || local === ".." || local.startsWith(`..${sep4}`) || isAbsolute5(local)) {
26552
26800
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is outside the project root");
@@ -26585,7 +26833,7 @@ function sameFile(a, b) {
26585
26833
  return a === null ? b === null : b !== null && a.content === b.content && a.dev === b.dev && a.ino === b.ino && a.mode === b.mode;
26586
26834
  }
26587
26835
  async function planScaffoldWrites(root, writes) {
26588
- const canonical = await realpath4(resolve16(root));
26836
+ const canonical = await realpath4(resolve17(root));
26589
26837
  const targets = new Set;
26590
26838
  const planned = [];
26591
26839
  for (const write of writes) {
@@ -26628,7 +26876,7 @@ async function applyScaffoldWrites(plan) {
26628
26876
  for (const write of plan.writes) {
26629
26877
  const target = scaffoldPath(plan.root, write.path);
26630
26878
  let current = plan.root;
26631
- for (const part of relative6(plan.root, dirname7(target)).split(sep4).filter(Boolean)) {
26879
+ for (const part of relative6(plan.root, dirname8(target)).split(sep4).filter(Boolean)) {
26632
26880
  current = join12(current, part);
26633
26881
  try {
26634
26882
  await mkdir4(current);
@@ -26894,7 +27142,7 @@ async function generateScaffold(args) {
26894
27142
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", `--${flag.replaceAll("_", "-")} must be boolean`);
26895
27143
  }
26896
27144
  }
26897
- const root = resolve17(args.root || process.cwd());
27145
+ const root = resolve18(args.root || process.cwd());
26898
27146
  const dir = args.dir ?? "src/features";
26899
27147
  if (dir !== ".")
26900
27148
  scaffoldPath(root, dir);
@@ -26948,7 +27196,7 @@ async function generateScaffold(args) {
26948
27196
  if (new RegExp(`\\b${moduleSymbol}\\b`).test(original)) {
26949
27197
  throw new ScaffoldError("SCAFFOLD_REGISTRATION_CONFLICT", `Registration target already references ${moduleSymbol}; review the import manually`);
26950
27198
  }
26951
- let importPath = relative7(dirname8(target), resolve17(root, modulePath)).replaceAll("\\", "/").replace(/\.ts$/, "");
27199
+ let importPath = relative7(dirname9(target), resolve18(root, modulePath)).replaceAll("\\", "/").replace(/\.ts$/, "");
26952
27200
  if (!importPath.startsWith("."))
26953
27201
  importPath = `./${importPath}`;
26954
27202
  const edit = await applyDiagnosticFix({
@@ -27021,13 +27269,13 @@ function sourceRoot(args, root, configured) {
27021
27269
  return args.root && !hasConfig ? "." : configured;
27022
27270
  }
27023
27271
  async function projectCompileConfig(args) {
27024
- const root = resolve17(args.root || process.cwd());
27272
+ const root = resolve18(args.root || process.cwd());
27025
27273
  const configFile = ["ts", "mts", "js", "mjs"].map((extension) => join13(root, `supacloud.config.${extension}`)).find((candidate) => existsSync11(candidate)) ?? null;
27026
27274
  const loadedConfig = await loadSupacloudConfig(root);
27027
27275
  const defaults = resolveSupacloudConfig(loadedConfig, root);
27028
27276
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
27029
27277
  const include = parseInclude(args.include) ?? loadedConfig.include;
27030
- const outDir = args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir;
27278
+ const outDir = args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir;
27031
27279
  const compileOptions = compileOptionsFromConfig({
27032
27280
  ...loadedConfig,
27033
27281
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
@@ -27074,6 +27322,7 @@ async function runContext(args) {
27074
27322
  const subject = args.target?.trim();
27075
27323
  if (subject) {
27076
27324
  const pack = createContextPack({ ...result.graph, diagnostics: result.diagnostics }, subject);
27325
+ const execution = args.events === undefined ? undefined : createExecutionContextPack({ ...result.graph, diagnostics: result.diagnostics }, subject, await readExecutionMetadata(resolve18(root, args.events)), args.request_id);
27077
27326
  const verification = await createVerificationPlan(root, result.graph, pack.subject, sourceDir);
27078
27327
  const repairs = createDiagnosticRepairPlan(pack.diagnostics);
27079
27328
  const workflow = {
@@ -27104,7 +27353,7 @@ async function runContext(args) {
27104
27353
  },
27105
27354
  executed: false
27106
27355
  };
27107
- return textResult(args.format === "json" ? JSON.stringify({ ...pack, workflow }, null, 2) : [
27356
+ return textResult(args.format === "json" ? JSON.stringify({ ...pack, ...execution ? { execution } : {}, workflow }, null, 2) : [
27108
27357
  formatModuleContextPack(pack),
27109
27358
  ` edit files (project-relative): ${workflow.editFiles.join(", ") || "-"}`,
27110
27359
  ` focused tests: ${verification.tests.join(", ") || "-"}`,
@@ -27256,11 +27505,11 @@ async function runDoctor(args) {
27256
27505
  `), doctor.errors > 0);
27257
27506
  }
27258
27507
  async function runFix(args) {
27259
- const root = resolve17(args.root || process.cwd());
27508
+ const root = resolve18(args.root || process.cwd());
27260
27509
  const fixPath = args.fix?.trim();
27261
27510
  if (!fixPath)
27262
27511
  throw new Error("app fix requires --fix <path-to-diagnostic-fix.json>");
27263
- const parsed = JSON.parse(await readFile4(resolve17(root, fixPath), "utf8"));
27512
+ const parsed = JSON.parse(await readFile4(resolve18(root, fixPath), "utf8"));
27264
27513
  const write = args.write === true;
27265
27514
  const applied = await applyDiagnosticFix(parsed, { rootDir: root, dryRun: !write });
27266
27515
  return textResult(JSON.stringify({
@@ -27303,7 +27552,7 @@ function devDatabase(profile, explicit) {
27303
27552
  }
27304
27553
  function readManifestModules(outDir) {
27305
27554
  try {
27306
- const parsed = JSON.parse(readFileSync8(join13(outDir, "app.manifest.json"), "utf8"));
27555
+ const parsed = JSON.parse(readFileSync9(join13(outDir, "app.manifest.json"), "utf8"));
27307
27556
  return Array.isArray(parsed.modules) ? parsed.modules.map((module) => module.name) : [];
27308
27557
  } catch {
27309
27558
  return [];
@@ -27346,12 +27595,12 @@ async function runAppDev(args, options) {
27346
27595
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "app dev --profile must be fast or integration");
27347
27596
  }
27348
27597
  const database = devDatabase(profile, args.database_url);
27349
- const root = resolve17(args.root || process.cwd());
27598
+ const root = resolve18(args.root || process.cwd());
27350
27599
  const loadedConfig = await loadSupacloudConfig(root);
27351
27600
  const defaults = resolveSupacloudConfig(loadedConfig, root);
27352
27601
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
27353
27602
  const include = parseInclude(args.include) ?? loadedConfig.include;
27354
- const outDir = args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir;
27603
+ const outDir = args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir;
27355
27604
  const watch = args.once !== true && args.watch !== false;
27356
27605
  const compileOptions = compileOptionsFromConfig({
27357
27606
  ...loadedConfig,
@@ -27437,7 +27686,7 @@ async function runAppDev(args, options) {
27437
27686
  return report(lastEvent, "stopped");
27438
27687
  }
27439
27688
  async function runCompile(args) {
27440
- const root = resolve17(args.root || process.cwd());
27689
+ const root = resolve18(args.root || process.cwd());
27441
27690
  const loadedConfig = await loadSupacloudConfig(root);
27442
27691
  const defaults = resolveSupacloudConfig(loadedConfig, root);
27443
27692
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
@@ -27446,7 +27695,7 @@ async function runCompile(args) {
27446
27695
  ...compileOptionsFromConfig({
27447
27696
  ...loadedConfig,
27448
27697
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
27449
- outDir: args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir,
27698
+ outDir: args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir,
27450
27699
  ...include === undefined ? {} : { include },
27451
27700
  strict: args.strict ?? loadedConfig.strict ?? false
27452
27701
  }, root),
@@ -27470,7 +27719,7 @@ async function runCompile(args) {
27470
27719
  return textResult(text, hasError);
27471
27720
  }
27472
27721
  async function runCheck(args) {
27473
- const root = resolve17(args.root || process.cwd());
27722
+ const root = resolve18(args.root || process.cwd());
27474
27723
  const database = checkAppDatabaseSources(root);
27475
27724
  const loadedConfig = await loadSupacloudConfig(root);
27476
27725
  const defaults = resolveSupacloudConfig(loadedConfig, root);
@@ -27479,7 +27728,7 @@ async function runCheck(args) {
27479
27728
  const config = compileOptionsFromConfig({
27480
27729
  ...loadedConfig,
27481
27730
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
27482
- outDir: args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir,
27731
+ outDir: args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir,
27483
27732
  ...include === undefined ? {} : { include },
27484
27733
  strict: args.strict ?? loadedConfig.strict ?? false
27485
27734
  }, root);
@@ -27509,7 +27758,7 @@ async function runCheck(args) {
27509
27758
  }
27510
27759
  async function readManifest(root, args) {
27511
27760
  const config = await loadSupacloudConfig(root);
27512
- const outDir = args.out_dir ? resolve17(root, args.out_dir) : resolveSupacloudConfig(config, root).outDir;
27761
+ const outDir = args.out_dir ? resolve18(root, args.out_dir) : resolveSupacloudConfig(config, root).outDir;
27513
27762
  const manifestPath = join13(outDir, "app.manifest.json");
27514
27763
  if (!existsSync11(manifestPath)) {
27515
27764
  throw new Error(`Manifest not found: ${manifestPath}(先运行 app compile 生成)`);
@@ -27554,7 +27803,7 @@ function formatGraphText(manifest) {
27554
27803
  `);
27555
27804
  }
27556
27805
  async function runGraph(args) {
27557
- const root = resolve17(args.root || process.cwd());
27806
+ const root = resolve18(args.root || process.cwd());
27558
27807
  const manifest = await readManifest(root, args);
27559
27808
  if (args.format === "json")
27560
27809
  return textResult(JSON.stringify(manifest, null, 2));
@@ -27622,7 +27871,7 @@ async function runExplain(args) {
27622
27871
  const target = args.target?.trim();
27623
27872
  if (!target)
27624
27873
  throw new Error("app explain requires --target(provider 类名 / token 名 / command 名 / job 名)");
27625
- const root = resolve17(args.root || process.cwd());
27874
+ const root = resolve18(args.root || process.cwd());
27626
27875
  const manifest = await readManifest(root, args);
27627
27876
  for (const module of manifest.modules) {
27628
27877
  const job = module.jobs?.find((entry) => entry.name === target || entry.className === target);
@@ -27697,10 +27946,10 @@ async function runExplain(args) {
27697
27946
  return textResult(`未找到对象: ${target}`, true);
27698
27947
  }
27699
27948
  async function runExportTools(args) {
27700
- const root = resolve17(args.root || process.cwd());
27949
+ const root = resolve18(args.root || process.cwd());
27701
27950
  const manifest = await readManifest(root, { ...args, out_dir: undefined });
27702
27951
  const definitions = buildToolDefinitions(manifest);
27703
- const outDir = resolve17(args.out_dir || join13(root, "generated"));
27952
+ const outDir = resolve18(args.out_dir || join13(root, "generated"));
27704
27953
  if (args.format === "json") {
27705
27954
  return textResult(JSON.stringify(definitions, null, 2));
27706
27955
  }
@@ -27721,7 +27970,7 @@ async function runExportTools(args) {
27721
27970
  return textResult(summary);
27722
27971
  }
27723
27972
  async function runDelivery(args) {
27724
- const root = resolve17(args.root || process.cwd());
27973
+ const root = resolve18(args.root || process.cwd());
27725
27974
  if (args.action === "build") {
27726
27975
  const database = checkAppDatabaseSources(root);
27727
27976
  if (database && !database.ok) {
@@ -27731,7 +27980,7 @@ async function runDelivery(args) {
27731
27980
  const loaded = await loadSupacloudConfig(root);
27732
27981
  const options = compileOptionsFromConfig({
27733
27982
  ...loaded,
27734
- ...args.out_dir === undefined ? {} : { outDir: resolve17(root, args.out_dir) },
27983
+ ...args.out_dir === undefined ? {} : { outDir: resolve18(root, args.out_dir) },
27735
27984
  ...args.include === undefined ? {} : { include: parseInclude(args.include) },
27736
27985
  ...args.strict === undefined ? {} : { strict: args.strict }
27737
27986
  }, root);
@@ -27808,7 +28057,7 @@ async function runAppRelease(request, options, delegate) {
27808
28057
  if (request.activation_id !== undefined || request.expected_activation_id !== undefined) {
27809
28058
  throw new Error("app release generates one activation identity; use app deploy for an exact retry");
27810
28059
  }
27811
- const root = resolve17(request.root || process.cwd());
28060
+ const root = resolve18(request.root || process.cwd());
27812
28061
  const completed = {};
27813
28062
  let manifestPath;
27814
28063
  let buildReceipt;
@@ -27816,7 +28065,7 @@ async function runAppRelease(request, options, delegate) {
27816
28065
  if (request.manifest_path === undefined) {
27817
28066
  throw new Error("app release --skip_build requires --manifest_path");
27818
28067
  }
27819
- manifestPath = resolve17(root, request.manifest_path);
28068
+ manifestPath = resolve18(root, request.manifest_path);
27820
28069
  completed.build = { skipped: true, manifest_path: manifestPath };
27821
28070
  } else {
27822
28071
  const built = await runDelivery({ ...request, action: "build", root, format: "json" });
@@ -27853,7 +28102,7 @@ async function runAppRelease(request, options, delegate) {
27853
28102
  let configurationWrite;
27854
28103
  const activationId = crypto.randomUUID();
27855
28104
  if (request.configuration_path !== undefined) {
27856
- const configurationPath = resolve17(root, request.configuration_path);
28105
+ const configurationPath = resolve18(root, request.configuration_path);
27857
28106
  try {
27858
28107
  configurationWrite = parseApplicationConfigurationWrite(await Bun.file(configurationPath).json());
27859
28108
  configurationId = configurationWrite.configuration_id;
@@ -28180,15 +28429,21 @@ Execution: skipped`);
28180
28429
  return format === "json" || json ? result : formatPromotionExecution(result);
28181
28430
  }
28182
28431
  async function runAppTool(request, options = {}) {
28183
- if (request.dry_run !== undefined && request["dry-run"] !== undefined || request.register_in !== undefined && request["register-in"] !== undefined || request.database_url !== undefined && request["database-url"] !== undefined) {
28432
+ if (request.dry_run !== undefined && request["dry-run"] !== undefined || request.register_in !== undefined && request["register-in"] !== undefined || request.database_url !== undefined && request["database-url"] !== undefined || request.request_id !== undefined && request["request-id"] !== undefined) {
28184
28433
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "Do not combine hyphenated and underscored aliases of the same flag");
28185
28434
  }
28186
28435
  request = {
28187
28436
  ...request,
28188
28437
  ...request["dry-run"] === undefined ? {} : { dry_run: request["dry-run"] },
28189
28438
  ...request["register-in"] === undefined ? {} : { register_in: request["register-in"] },
28190
- ...request["database-url"] === undefined ? {} : { database_url: request["database-url"] }
28439
+ ...request["database-url"] === undefined ? {} : { database_url: request["database-url"] },
28440
+ ...request["request-id"] === undefined ? {} : { request_id: request["request-id"] }
28191
28441
  };
28442
+ if (request.events !== undefined || request.request_id !== undefined) {
28443
+ if (request.action !== "context" || !request.events?.trim() || !request.target?.trim() || !request.request_id || !/^[A-Za-z0-9._:-]{1,256}$/.test(request.request_id) || request.format !== "json" || request.write !== undefined) {
28444
+ throw new Error("Execution context requires app context, --target, --events, --request-id and --format json; --write is not supported");
28445
+ }
28446
+ }
28192
28447
  if ((request.dry_run !== undefined || request.register_in !== undefined) && request.action !== "generate") {
28193
28448
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "--dry-run and --register-in apply only to app generate");
28194
28449
  }
@@ -28375,6 +28630,9 @@ function registerAppTools(server, options = {}) {
28375
28630
  database_url: optional(String2(), "[dev] Explicit loopback integration URL; watch/once only inspect its shape"),
28376
28631
  "database-url": optional(String2(), "[dev] CLI alias of database_url"),
28377
28632
  target: optional(String2(), "[explain/context/verify-plan] Provider class name / token name / command name / job name / module name"),
28633
+ events: optional(String2(), "[context] Project-relative execution metadata JSON or generated JSON-lines file"),
28634
+ request_id: optional(String2(), "[context] Opaque request ID or Workflow run ID selected from --events"),
28635
+ "request-id": optional(String2(), "[context] CLI alias of request_id"),
28378
28636
  fix: optional(String2(), "[fix] Path to a DiagnosticFix JSON file produced by `doctor --format json`"),
28379
28637
  write: optional(Boolean2(), "[fix] Write the fix to disk (default: preview only)"),
28380
28638
  skip_build: optional(Boolean2(), "[release] Reuse --manifest_path instead of running the local delivery build")
@@ -28400,6 +28658,9 @@ function registerAppAliases(server) {
28400
28658
  strict: optional(Boolean2(), "[compile/check] Promote warnings to errors"),
28401
28659
  format: optional(stringEnum2(["text", "json"]), "Output format (default: text)"),
28402
28660
  target: optional(String2(), "[explain/context] Provider class name / token name / command name / job name / module name"),
28661
+ events: optional(String2(), "[context] Project-relative execution metadata JSON or generated JSON-lines file"),
28662
+ request_id: optional(String2(), "[context] Opaque request ID or Workflow run ID selected from --events"),
28663
+ "request-id": optional(String2(), "[context] CLI alias of request_id"),
28403
28664
  fix: optional(String2(), "[fix] Path to a DiagnosticFix JSON file produced by `doctor --format json`"),
28404
28665
  write: optional(Boolean2(), "[fix] Write the fix to disk (default: preview only)")
28405
28666
  };
@@ -28410,7 +28671,7 @@ function registerAppAliases(server) {
28410
28671
 
28411
28672
  // src/shared/tools/db-governance-tools.ts
28412
28673
  import { existsSync as existsSync13 } from "node:fs";
28413
- import { join as join16, resolve as resolve20 } from "node:path";
28674
+ import { join as join16, resolve as resolve21 } from "node:path";
28414
28675
  import {
28415
28676
  buildDatabaseManifest,
28416
28677
  explainObject,
@@ -28420,10 +28681,10 @@ import {
28420
28681
  } from "@supacloud/db";
28421
28682
 
28422
28683
  // src/shared/tools/db-workflow.ts
28423
- import { createHash as createHash7 } from "node:crypto";
28684
+ import { createHash as createHash8 } from "node:crypto";
28424
28685
  import { lstat as lstat4, mkdir as mkdir6, mkdtemp, readFile as readFile5, readdir as readdir6, rename as rename3, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
28425
28686
  import { tmpdir as tmpdir2 } from "node:os";
28426
- import { dirname as dirname10, isAbsolute as isAbsolute7, join as join15, relative as relative8, resolve as resolve19 } from "node:path";
28687
+ import { dirname as dirname11, isAbsolute as isAbsolute7, join as join15, relative as relative8, resolve as resolve20 } from "node:path";
28427
28688
  import {
28428
28689
  assertApplicationRoleRestricted,
28429
28690
  readDatabaseRole,
@@ -28435,7 +28696,7 @@ import { parseDatabaseSourcesConfig } from "@supacloud/db/source-contracts";
28435
28696
 
28436
28697
  // src/shared/tools/supabase-cli-tools.ts
28437
28698
  import { chmodSync as chmodSync2, existsSync as existsSync12, mkdirSync as mkdirSync4, statSync as statSync8, writeFileSync as writeFileSync3 } from "node:fs";
28438
- import { dirname as dirname9, isAbsolute as isAbsolute6, join as join14, resolve as resolve18 } from "node:path";
28699
+ import { dirname as dirname10, isAbsolute as isAbsolute6, join as join14, resolve as resolve19 } from "node:path";
28439
28700
  var SENSITIVE_ENV_KEY2 = /(?:^|_)(?:PASSWORD|PASS|SECRET|TOKEN|KEY|CREDENTIALS?|AUTHORIZATION|AUTH|SESSION|COOKIE|BEARER|DB_URI|DB_URL|DSN|DATABASE_URL|DATABASE_URI|CONNECTION_STRING|CONNECTION_URI)(?:_|$)/i;
28440
28701
  var VALID_VERSION2 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
28441
28702
  var VALID_MIGRATION_NAME2 = /^[A-Za-z0-9][A-Za-z0-9_-]{0,100}$/;
@@ -28480,12 +28741,12 @@ function schemaArguments2(schema) {
28480
28741
  function workdirArguments2(workdir) {
28481
28742
  if (!workdir)
28482
28743
  throw new Error("A workdir is required");
28483
- return ["--workdir", resolve18(workdir)];
28744
+ return ["--workdir", resolve19(workdir)];
28484
28745
  }
28485
28746
  function resolveOutputPath2(workdir, file, label) {
28486
28747
  if (!file || /[\r\n\0]/.test(file))
28487
28748
  throw new Error(`${label} file is required`);
28488
- return isAbsolute6(file) ? resolve18(file) : resolve18(workdir, file);
28749
+ return isAbsolute6(file) ? resolve19(file) : resolve19(workdir, file);
28489
28750
  }
28490
28751
  function databaseTargetArguments2(databaseUrl) {
28491
28752
  return databaseUrl ? ["--db-url", requirePostgresUrl2(databaseUrl)] : ["--local"];
@@ -28660,7 +28921,7 @@ function actionArguments2(request, workdir) {
28660
28921
  function buildOfficialSupabaseArgs2(request) {
28661
28922
  if (request.action === "version")
28662
28923
  return ["--version"];
28663
- const workdir = request.workdir ? resolve18(request.workdir) : undefined;
28924
+ const workdir = request.workdir ? resolve19(request.workdir) : undefined;
28664
28925
  if (!workdir)
28665
28926
  throw new Error("A workdir is required");
28666
28927
  return [...actionArguments2(request, workdir), ...workdirArguments2(workdir)];
@@ -28702,14 +28963,14 @@ function resolveOfficialSupabaseCommand2(workdir, environment = process.env) {
28702
28963
  }
28703
28964
  return ["npx", "--yes", `supabase@${version}`];
28704
28965
  }
28705
- const localPackageEntry = join14(resolve18(workdir), "node_modules", "supabase", "dist", "supabase.js");
28966
+ const localPackageEntry = join14(resolve19(workdir), "node_modules", "supabase", "dist", "supabase.js");
28706
28967
  if (existsSync12(localPackageEntry))
28707
28968
  return [process.execPath, localPackageEntry];
28708
28969
  return ["supabase"];
28709
28970
  }
28710
28971
 
28711
28972
  // src/shared/tools/db-workflow.ts
28712
- var hash4 = (content) => createHash7("sha256").update(content).digest("hex");
28973
+ var hash4 = (content) => createHash8("sha256").update(content).digest("hex");
28713
28974
  var result = (value, isError = false) => ({
28714
28975
  isError,
28715
28976
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
@@ -28873,8 +29134,8 @@ async function reverse(args, root, options) {
28873
29134
  if (!selectedSchemas.length || selectedSchemas.some((schema) => !/^[a-z_][a-z0-9_$]*$/i.test(schema))) {
28874
29135
  throw new Error("Select valid PostgreSQL schemas");
28875
29136
  }
28876
- await mkdir6(dirname10(out), { recursive: true });
28877
- const stage = await mkdtemp(join15(dirname10(out), ".reverse-"));
29137
+ await mkdir6(dirname11(out), { recursive: true });
29138
+ const stage = await mkdtemp(join15(dirname11(out), ".reverse-"));
28878
29139
  try {
28879
29140
  const snapshot = await withDatabase(args, options, async (executor, url) => {
28880
29141
  const snapshot = await reverseDatabase(executor, selectedSchemas);
@@ -28918,8 +29179,8 @@ async function diff2(args, root, options) {
28918
29179
  const input = await migrations(root, args.dir ?? (await boundary(root))?.migrations ?? "supabase/migrations");
28919
29180
  if (overlaps(input.dir, out))
28920
29181
  throw new Error("Candidate output overlaps reviewed migration history");
28921
- await mkdir6(dirname10(out), { recursive: true });
28922
- const stage = await mkdtemp(join15(dirname10(out), ".diff-"));
29182
+ await mkdir6(dirname11(out), { recursive: true });
29183
+ const stage = await mkdtemp(join15(dirname11(out), ".diff-"));
28923
29184
  try {
28924
29185
  await initializeCandidate(stage, args.db_major_version);
28925
29186
  if (!await copySqlSources(root, sourcePath, join15(stage, "supabase/schemas")))
@@ -29011,7 +29272,7 @@ async function migrationAction(args, root, options) {
29011
29272
  }
29012
29273
  }
29013
29274
  async function runDbWorkflow(args, projectRoot, options = {}) {
29014
- const root = resolve19(projectRoot);
29275
+ const root = resolve20(projectRoot);
29015
29276
  if ((await lstat4(root)).isSymbolicLink())
29016
29277
  throw new Error("Workflow root must not be a symlink");
29017
29278
  switch (args.action) {
@@ -29072,7 +29333,7 @@ function normalizeModule(candidate, sourcePath) {
29072
29333
  };
29073
29334
  }
29074
29335
  async function loadDatabaseModules(root, moduleFile) {
29075
- const filePath = moduleFile ? resolve20(root, moduleFile) : join16(root, "db", "modules.ts");
29336
+ const filePath = moduleFile ? resolve21(root, moduleFile) : join16(root, "db", "modules.ts");
29076
29337
  if (!existsSync13(filePath)) {
29077
29338
  throw new Error(moduleFile ? `Module file not found: ${filePath}` : `Module file not found: ${filePath}(用 --module_file 指定一个导出 defineDatabaseModule(...) 的文件)`);
29078
29339
  }
@@ -29208,7 +29469,7 @@ async function runLint(args, root) {
29208
29469
  const issues = [];
29209
29470
  for (const module of selected) {
29210
29471
  const readSqlFile = async (path) => {
29211
- const absolute = resolve20(root, path);
29472
+ const absolute = resolve21(root, path);
29212
29473
  try {
29213
29474
  return await Bun.file(absolute).text();
29214
29475
  } catch (error) {
@@ -29248,14 +29509,14 @@ var defaultLiteSpawn = async (command, cwd) => {
29248
29509
  return { exitCode, stdout, stderr };
29249
29510
  };
29250
29511
  async function runModuleCheckLite(args, root, spawn, liteBinary) {
29251
- const projectDir = resolve20(args.project_dir?.trim() || root);
29512
+ const projectDir = resolve21(args.project_dir?.trim() || root);
29252
29513
  const binary = liteBinary === undefined ? Bun.which("supacloud-lite") : liteBinary;
29253
29514
  if (!binary) {
29254
29515
  throw new Error("db module_check --lite 需要本机可用的 supacloud-lite(npm i -g @supacloud/lite,或加入 PATH)");
29255
29516
  }
29256
29517
  const command = [binary, "db", "check", "--project-dir", projectDir];
29257
29518
  if (args.module_file?.trim())
29258
- command.push("--module-file", resolve20(root, args.module_file.trim()));
29519
+ command.push("--module-file", resolve21(root, args.module_file.trim()));
29259
29520
  const result = await spawn(command, projectDir);
29260
29521
  const output = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(`
29261
29522
  `);
@@ -29315,7 +29576,7 @@ function registerDbGovernanceTools(server, options = {}) {
29315
29576
  migration_role: optional(String2(), "[role_sql] Privileged migration role"),
29316
29577
  database: optional(String2(), "[role_sql] PostgreSQL database name")
29317
29578
  }, async (request) => {
29318
- const root = resolve20(request.root || fallbackRoot);
29579
+ const root = resolve21(request.root || fallbackRoot);
29319
29580
  switch (request.action) {
29320
29581
  case "context":
29321
29582
  return runContext2(request, root);
@@ -29345,8 +29606,8 @@ function registerDbGovernanceTools(server, options = {}) {
29345
29606
 
29346
29607
  // src/shared/tools/scheduled-function-tools.ts
29347
29608
  import { randomUUID as randomUUID3 } from "node:crypto";
29348
- import { readFileSync as readFileSync9, statSync as statSync9 } from "node:fs";
29349
- import { resolve as resolve21 } from "node:path";
29609
+ import { readFileSync as readFileSync10, statSync as statSync9 } from "node:fs";
29610
+ import { resolve as resolve22 } from "node:path";
29350
29611
  import { isDeepStrictEqual } from "node:util";
29351
29612
  var HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$/;
29352
29613
  var ENVIRONMENT_NAME_PATTERN3 = /^[A-Za-z_][A-Za-z0-9_]{0,255}$/;
@@ -29430,14 +29691,14 @@ function validScheduledFunctionCron(expression) {
29430
29691
  function readScheduleBodyFile(bodyPathInput) {
29431
29692
  if (!bodyPathInput.trim())
29432
29693
  throw new Error("'body_file' must be a path");
29433
- const bodyPath = resolve21(bodyPathInput);
29694
+ const bodyPath = resolve22(bodyPathInput);
29434
29695
  const bodyStat = statSync9(bodyPath);
29435
29696
  if (!bodyStat.isFile() || bodyStat.size > MAX_BODY_FILE_BYTES) {
29436
29697
  throw new Error("Scheduled Function body file must be a regular file no larger than 1 MiB");
29437
29698
  }
29438
29699
  let payload;
29439
29700
  try {
29440
- payload = JSON.parse(readFileSync9(bodyPath, "utf8"));
29701
+ payload = JSON.parse(readFileSync10(bodyPath, "utf8"));
29441
29702
  } catch (error) {
29442
29703
  if (!(error instanceof SyntaxError))
29443
29704
  throw error;
@@ -29813,9 +30074,9 @@ var MUTATION_TOOL_SCHEMA = {
29813
30074
  };
29814
30075
 
29815
30076
  // src/shared/tools/release-tools.ts
29816
- import { createHash as createHash8 } from "node:crypto";
29817
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, readdirSync as readdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "node:fs";
29818
- import { dirname as dirname11, join as join17, relative as relative9, resolve as resolve22 } from "node:path";
30077
+ import { createHash as createHash9 } from "node:crypto";
30078
+ import { existsSync as existsSync14, mkdirSync as mkdirSync5, readdirSync as readdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "node:fs";
30079
+ import { dirname as dirname12, join as join17, relative as relative9, resolve as resolve23 } from "node:path";
29819
30080
  var SAFE_PROJECT_REF = /^[A-Za-z0-9_-]{1,64}$/;
29820
30081
  var SAFE_ENVIRONMENT_ID = /^[A-Za-z0-9_-]{1,64}$/;
29821
30082
  var BACKUP_ID = /^logical-full_[A-Za-z0-9_-]{1,64}_[a-f0-9]{32}$/;
@@ -30056,7 +30317,7 @@ function genericScopedReleaseScopeJson(scope) {
30056
30317
  return JSON.stringify(canonicalValue(scope));
30057
30318
  }
30058
30319
  function genericScopedReleaseScopeSha256(scope) {
30059
- return createHash8("sha256").update(genericScopedReleaseScopeJson(scope)).digest("hex");
30320
+ return createHash9("sha256").update(genericScopedReleaseScopeJson(scope)).digest("hex");
30060
30321
  }
30061
30322
  function scopeEnvironmentId(scope, action) {
30062
30323
  const environmentId = isRecord6(scope) ? scope.targetEnvironmentId : undefined;
@@ -30137,13 +30398,13 @@ function collectScopeFiles(cwd, file, files, dir, task) {
30137
30398
  const results = [];
30138
30399
  const resolvePathWithFallbacks = (filePath) => {
30139
30400
  const trimmed = filePath.trim();
30140
- const resolved = resolve22(cwd, trimmed);
30401
+ const resolved = resolve23(cwd, trimmed);
30141
30402
  if (existsSync14(resolved))
30142
30403
  return resolved;
30143
30404
  const candidates = [
30144
- resolve22(cwd, "supacloud/fa/release-scopes", trimmed),
30145
- resolve22(cwd, "release-scopes", trimmed),
30146
- resolve22(cwd, "scopes", trimmed)
30405
+ resolve23(cwd, "supacloud/fa/release-scopes", trimmed),
30406
+ resolve23(cwd, "release-scopes", trimmed),
30407
+ resolve23(cwd, "scopes", trimmed)
30147
30408
  ];
30148
30409
  const found = candidates.find(existsSync14);
30149
30410
  if (found)
@@ -30166,10 +30427,10 @@ function collectScopeFiles(cwd, file, files, dir, task) {
30166
30427
  if (!taskFilter && (!dir || typeof dir !== "string" || !dir.trim())) {
30167
30428
  throw new Error("At least one of --file, --files, or --task is required for scope_rebind");
30168
30429
  }
30169
- const candidates = typeof dir === "string" && dir.trim() ? [resolve22(cwd, dir.trim())] : [
30170
- resolve22(cwd, "supacloud/fa/release-scopes"),
30171
- resolve22(cwd, "release-scopes"),
30172
- resolve22(cwd, "scopes")
30430
+ const candidates = typeof dir === "string" && dir.trim() ? [resolve23(cwd, dir.trim())] : [
30431
+ resolve23(cwd, "supacloud/fa/release-scopes"),
30432
+ resolve23(cwd, "release-scopes"),
30433
+ resolve23(cwd, "scopes")
30173
30434
  ];
30174
30435
  for (const directory of candidates) {
30175
30436
  if (existsSync14(directory)) {
@@ -30184,7 +30445,7 @@ function collectScopeFiles(cwd, file, files, dir, task) {
30184
30445
  results.push(fullPath);
30185
30446
  } else {
30186
30447
  try {
30187
- const parsed = JSON.parse(readFileSync10(fullPath, "utf8"));
30448
+ const parsed = JSON.parse(readFileSync11(fullPath, "utf8"));
30188
30449
  if (typeof parsed?.taskId === "string" && parsed.taskId.toLowerCase() === taskFilter) {
30189
30450
  results.push(fullPath);
30190
30451
  }
@@ -30203,7 +30464,7 @@ function collectScopeFiles(cwd, file, files, dir, task) {
30203
30464
  return [...new Set(results)];
30204
30465
  }
30205
30466
  function handleScopeRebind(args) {
30206
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve22(args.cwd.trim()) : process.cwd();
30467
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
30207
30468
  const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
30208
30469
  const requestedEnvironmentId = requestedScopeEnvironment(args, "scope_rebind");
30209
30470
  const scopeFiles = collectScopeFiles(cwd, args.file, args.files, args.dir, args.task);
@@ -30211,7 +30472,7 @@ function handleScopeRebind(args) {
30211
30472
  const parsedScopes = scopeFiles.map((filePath) => {
30212
30473
  let content;
30213
30474
  try {
30214
- content = readFileSync10(filePath, "utf8");
30475
+ content = readFileSync11(filePath, "utf8");
30215
30476
  } catch (cause) {
30216
30477
  throw new Error(`Failed to read scope file '${filePath}': ${cause instanceof Error ? cause.message : String(cause)}`);
30217
30478
  }
@@ -30261,18 +30522,18 @@ function handleScopeRebind(args) {
30261
30522
  });
30262
30523
  }
30263
30524
  function handleScopeInspect(args) {
30264
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve22(args.cwd.trim()) : process.cwd();
30525
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
30265
30526
  const requestedEnvironmentId = requestedScopeEnvironment(args, "scope_inspect");
30266
30527
  if (typeof args.file !== "string" || !args.file.trim()) {
30267
30528
  throw new Error("'file' is required for scope_inspect");
30268
30529
  }
30269
30530
  const trimmed = args.file.trim();
30270
- let filePath = resolve22(cwd, trimmed);
30531
+ let filePath = resolve23(cwd, trimmed);
30271
30532
  if (!existsSync14(filePath)) {
30272
30533
  const candidates = [
30273
- resolve22(cwd, "supacloud/fa/release-scopes", trimmed),
30274
- resolve22(cwd, "release-scopes", trimmed),
30275
- resolve22(cwd, "scopes", trimmed)
30534
+ resolve23(cwd, "supacloud/fa/release-scopes", trimmed),
30535
+ resolve23(cwd, "release-scopes", trimmed),
30536
+ resolve23(cwd, "scopes", trimmed)
30276
30537
  ];
30277
30538
  const found = candidates.find(existsSync14);
30278
30539
  if (found)
@@ -30282,7 +30543,7 @@ function handleScopeInspect(args) {
30282
30543
  }
30283
30544
  let content;
30284
30545
  try {
30285
- content = readFileSync10(filePath, "utf8");
30546
+ content = readFileSync11(filePath, "utf8");
30286
30547
  } catch (cause) {
30287
30548
  throw new Error(`Failed to read scope file '${args.file}': ${cause instanceof Error ? cause.message : String(cause)}`);
30288
30549
  }
@@ -30337,7 +30598,7 @@ function parseCommaList(value) {
30337
30598
  return [];
30338
30599
  }
30339
30600
  function handleScopeCreate(args, fallbackRef) {
30340
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve22(args.cwd.trim()) : process.cwd();
30601
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
30341
30602
  if (typeof args.file !== "string" || !args.file.trim()) {
30342
30603
  throw new Error("'file' is required for scope_create");
30343
30604
  }
@@ -30353,8 +30614,8 @@ function handleScopeCreate(args, fallbackRef) {
30353
30614
  throw new Error("'ref' is invalid for release controls");
30354
30615
  }
30355
30616
  const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
30356
- const filePath = resolve22(cwd, args.file.trim());
30357
- mkdirSync5(dirname11(filePath), { recursive: true });
30617
+ const filePath = resolve23(cwd, args.file.trim());
30618
+ mkdirSync5(dirname12(filePath), { recursive: true });
30358
30619
  const scope = {
30359
30620
  baseCommit: targetBaseCommit,
30360
30621
  excludedFunctions: parseCommaList(args.excluded_functions),
@@ -30600,9 +30861,9 @@ function registerReleaseTools(server, http, options = {}) {
30600
30861
  // src/shared/tools/deploy-tools.ts
30601
30862
  import { access, lstat as lstat5, mkdtemp as mkdtemp2, opendir, readFile as readFile6, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
30602
30863
  import { spawn as spawn2 } from "node:child_process";
30603
- import { createHash as createHash9 } from "node:crypto";
30864
+ import { createHash as createHash10 } from "node:crypto";
30604
30865
  import { tmpdir as tmpdir3 } from "node:os";
30605
- import { basename as basename8, dirname as dirname12, join as join18, relative as relative10, resolve as resolve23, sep as sep5 } from "node:path";
30866
+ import { basename as basename8, dirname as dirname13, join as join18, relative as relative10, resolve as resolve24, sep as sep5 } from "node:path";
30606
30867
 
30607
30868
  // src/shared/tools/project-deployment.ts
30608
30869
  async function requireProjectDeploymentProtocol(http, projectRef, environmentId) {
@@ -30728,15 +30989,15 @@ async function readJson(path) {
30728
30989
  }
30729
30990
  }
30730
30991
  async function findDeployConfigRoot(startDirectory, environmentName) {
30731
- let directory = resolve23(startDirectory);
30992
+ let directory = resolve24(startDirectory);
30732
30993
  while (true) {
30733
30994
  const environmentFile = environmentName ? `.env.supacloud.${environmentName}` : null;
30734
30995
  if (await pathExists(join18(directory, "supacloud.json")) || await pathExists(join18(directory, "supacloud.config.ts")) || environmentFile !== null && await pathExists(join18(directory, environmentFile))) {
30735
30996
  return directory;
30736
30997
  }
30737
- const parent = dirname12(directory);
30998
+ const parent = dirname13(directory);
30738
30999
  if (parent === directory)
30739
- return resolve23(startDirectory);
31000
+ return resolve24(startDirectory);
30740
31001
  directory = parent;
30741
31002
  }
30742
31003
  }
@@ -30889,7 +31150,7 @@ async function defaultBuildCommand(projectDirectory, configRoot) {
30889
31150
  return "yarn build";
30890
31151
  if (directory === configRoot)
30891
31152
  break;
30892
- const parent = dirname12(directory);
31153
+ const parent = dirname13(directory);
30893
31154
  if (parent === directory || !directory.startsWith(`${configRoot}${sep5}`))
30894
31155
  break;
30895
31156
  directory = parent;
@@ -30957,9 +31218,9 @@ function selectFrontendTarget(configRoot, config) {
30957
31218
  throw new Error(`Multiple frontend deploy targets found (${targets.map(([name]) => name).sort().join(", ")}). Set defaultTarget to the Web target`);
30958
31219
  }
30959
31220
  function targetRoot(configRoot, target, name) {
30960
- const root = resolve23(configRoot, target.root || (name === "frontend" ? "." : name));
30961
- const prefix = `${resolve23(configRoot)}${sep5}`;
30962
- if (root !== resolve23(configRoot) && !root.startsWith(prefix)) {
31221
+ const root = resolve24(configRoot, target.root || (name === "frontend" ? "." : name));
31222
+ const prefix = `${resolve24(configRoot)}${sep5}`;
31223
+ if (root !== resolve24(configRoot) && !root.startsWith(prefix)) {
30963
31224
  throw new Error(`Deploy target '${name}' root must stay inside the repository root`);
30964
31225
  }
30965
31226
  return root;
@@ -30977,8 +31238,8 @@ function defaultOutputDirectory(framework) {
30977
31238
  }
30978
31239
  }
30979
31240
  function resolveInsideProject(projectDirectory, candidate, allowRoot = false) {
30980
- const resolved = resolve23(projectDirectory, candidate);
30981
- const projectRoot = resolve23(projectDirectory);
31241
+ const resolved = resolve24(projectDirectory, candidate);
31242
+ const projectRoot = resolve24(projectDirectory);
30982
31243
  const projectPrefix = `${projectRoot}${sep5}`;
30983
31244
  if (!allowRoot && resolved === projectRoot || resolved !== projectRoot && !resolved.startsWith(projectPrefix)) {
30984
31245
  throw new Error("Frontend output directory must stay inside the project directory");
@@ -31057,9 +31318,9 @@ async function collectArchiveFiles(root) {
31057
31318
  throw new Error(`Frontend output exceeds ${MAX_SOURCE_BYTES} bytes`);
31058
31319
  const archivePath = relative10(root, path).split(sep5).join("/");
31059
31320
  files.set(archivePath, data);
31060
- digests.push({ path: archivePath, size: data.byteLength, sha256: createHash9("sha256").update(data).digest("hex") });
31321
+ digests.push({ path: archivePath, size: data.byteLength, sha256: createHash10("sha256").update(data).digest("hex") });
31061
31322
  }
31062
- const tree = createHash9("sha256");
31323
+ const tree = createHash10("sha256");
31063
31324
  for (const file of digests.sort((left, right) => left.path.localeCompare(right.path))) {
31064
31325
  const pathBytes = Buffer.from(file.path, "utf8");
31065
31326
  const frame = Buffer.alloc(12);
@@ -31075,7 +31336,7 @@ async function createCollectedFrontendArchive(outputDirectory, collected) {
31075
31336
  try {
31076
31337
  const archiveBytes = await createFrontendTarZstd(collected.files);
31077
31338
  await writeFile6(archivePath, archiveBytes);
31078
- const sha256 = createHash9("sha256").update(archiveBytes).digest("hex");
31339
+ const sha256 = createHash10("sha256").update(archiveBytes).digest("hex");
31079
31340
  return {
31080
31341
  archivePath,
31081
31342
  sha256,
@@ -31119,7 +31380,7 @@ async function publishConfiguredFrontend(http, projectRef, configRoot, skipBuild
31119
31380
  }
31120
31381
  function registerDeployTools(server, http, options = {}) {
31121
31382
  registerTool(server, "deploy", "Build and publish the linked project with one command", deployToolSchema, async (args) => {
31122
- const invocationDirectory = resolve23(String(args.cwd || options.cwd || process.cwd()));
31383
+ const invocationDirectory = resolve24(String(args.cwd || options.cwd || process.cwd()));
31123
31384
  const projectRef = String(args.ref || options.projectRef || "").trim();
31124
31385
  if (!projectRef)
31125
31386
  throw new Error("A linked project ref is required. Set SUPACLOUD_PROJECT_REF or pass --ref");
@@ -31197,8 +31458,8 @@ function registerDeployTools(server, http, options = {}) {
31197
31458
  import { existsSync as existsSync15 } from "node:fs";
31198
31459
  import { readFile as readFile7 } from "node:fs/promises";
31199
31460
  import { readdir as readdir7 } from "node:fs/promises";
31200
- import { createHash as createHash10 } from "node:crypto";
31201
- import { join as join19, resolve as resolve24 } from "node:path";
31461
+ import { createHash as createHash11 } from "node:crypto";
31462
+ import { join as join19, resolve as resolve25 } from "node:path";
31202
31463
  import { compileProject as compileProject2 } from "@supacloud/compiler";
31203
31464
  var SAFE_TOKEN = /^[A-Za-z0-9._:@/+,-]+$/;
31204
31465
  var SAFE_REMOTE_ROOT = /^\/(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+\/?$/;
@@ -31244,12 +31505,12 @@ function toolFailed(value) {
31244
31505
  return result.isError === true || content.some((chunk) => chunk !== null && typeof chunk === "object" && ("text" in chunk) && typeof chunk.text === "string" && chunk.text.trimStart().startsWith("❌"));
31245
31506
  }
31246
31507
  async function migrateDatabase(args, options) {
31247
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
31508
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
31248
31509
  const projectConfig = await readProjectConfig(root);
31249
31510
  const config = projectConfig.dev || {};
31250
31511
  const database = config.database || {};
31251
31512
  const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
31252
- const drizzleConfig = resolve24(root, String(args.drizzle_config || database.drizzleConfig || "drizzle.config.ts"));
31513
+ const drizzleConfig = resolve25(root, String(args.drizzle_config || database.drizzleConfig || "drizzle.config.ts"));
31253
31514
  const migrationsDir = String(args.migrations_dir || database.migrationsDir || "supabase/migrations");
31254
31515
  if (!existsSync15(drizzleConfig))
31255
31516
  throw new Error(`Drizzle config not found: ${drizzleConfig}`);
@@ -31296,7 +31557,7 @@ async function sourceFingerprint(root) {
31296
31557
  }
31297
31558
  };
31298
31559
  await visit(root);
31299
- const hash = createHash10("sha256");
31560
+ const hash = createHash11("sha256");
31300
31561
  for (const file of files) {
31301
31562
  hash.update(file.slice(root.length).replace(/\\/g, "/"));
31302
31563
  hash.update(await readFile7(file));
@@ -31321,14 +31582,14 @@ function targetDirectory(root, target, functionSlug, config = {}) {
31321
31582
  const targets = config["targets"];
31322
31583
  const entries = targets && typeof targets === "object" ? Object.values(targets) : [];
31323
31584
  const match = entries.find((entry) => entry !== null && typeof entry === "object" && ("type" in entry) && entry.type === "edge_function" && (!("root" in entry) || typeof entry.root === "string") && (!("slug" in entry) || typeof entry.slug === "string") && (!functionSlug || ("slug" in entry) && entry.slug === functionSlug));
31324
- const base = match?.root ? resolve24(root, match.root) : join19(root, "supabase", "functions");
31585
+ const base = match?.root ? resolve25(root, match.root) : join19(root, "supabase", "functions");
31325
31586
  return match?.root ? base : functionSlug ? join19(base, safeToken(functionSlug, "function")) : base;
31326
31587
  }
31327
31588
  if (target === "frontend") {
31328
31589
  const targets = config["targets"];
31329
31590
  const entries = targets && typeof targets === "object" ? Object.values(targets) : [];
31330
31591
  const match = entries.find((entry) => entry !== null && typeof entry === "object" && ("type" in entry) && entry.type === "frontend" && (!("root" in entry) || typeof entry.root === "string"));
31331
- return match?.root ? resolve24(root, match.root) : join19(root, "apps", "web");
31592
+ return match?.root ? resolve25(root, match.root) : join19(root, "apps", "web");
31332
31593
  }
31333
31594
  return root;
31334
31595
  }
@@ -31367,10 +31628,10 @@ function reloadCommand(config, target, projectRef, functionSlug) {
31367
31628
  return [...command.split(" "), "--project-ref", safeToken(projectRef || "test", "project_ref"), "--target", targetConfigPath(target), ...functionSlug ? ["--function", safeToken(functionSlug, "function")] : []];
31368
31629
  }
31369
31630
  function sshArgs(connection, remoteCommand) {
31370
- return ["-p", String(connection.port), "-i", resolve24(connection.key), "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", `${connection.user}@${connection.host}`, ...remoteCommand];
31631
+ return ["-p", String(connection.port), "-i", resolve25(connection.key), "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", `${connection.user}@${connection.host}`, ...remoteCommand];
31371
31632
  }
31372
31633
  function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
31373
- const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${resolve24(connection.key)} -o BatchMode=yes -o StrictHostKeyChecking=yes`];
31634
+ const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${resolve25(connection.key)} -o BatchMode=yes -o StrictHostKeyChecking=yes`];
31374
31635
  if (deleteRemote)
31375
31636
  args.push("--delete-delay");
31376
31637
  for (const exclude of excludes) {
@@ -31382,7 +31643,7 @@ function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
31382
31643
  return args;
31383
31644
  }
31384
31645
  async function syncOnce(args, options) {
31385
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
31646
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
31386
31647
  const projectConfig = await readProjectConfig(root);
31387
31648
  const config = projectConfig.dev || {};
31388
31649
  const target = String(args.target || "project");
@@ -31391,8 +31652,8 @@ async function syncOnce(args, options) {
31391
31652
  throw new Error(`Dev source directory not found: ${source}`);
31392
31653
  let compiled = false;
31393
31654
  if (config.compile === true && target !== "db") {
31394
- const compileRoot = resolve24(root, config.compileRoot || ".");
31395
- const compileOutDir = resolve24(root, config.compileOutDir || "generated");
31655
+ const compileRoot = resolve25(root, config.compileRoot || ".");
31656
+ const compileOutDir = resolve25(root, config.compileOutDir || "generated");
31396
31657
  const compilation = await compileProject2({
31397
31658
  rootDir: compileRoot,
31398
31659
  outDir: compileOutDir,
@@ -31430,7 +31691,7 @@ function registerRemoteDevTools(server, options = {}) {
31430
31691
  if (["production", "prod"].includes((options.environment || "").toLowerCase()))
31431
31692
  throw new Error("Remote dev mode is forbidden for production environments");
31432
31693
  if (args.action === "status") {
31433
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
31694
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
31434
31695
  const config = await readDevConfig(root);
31435
31696
  const connection = connectionArgs(options, config, args);
31436
31697
  const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
@@ -31444,7 +31705,7 @@ function registerRemoteDevTools(server, options = {}) {
31444
31705
  return { content: [{ type: "text", text: JSON.stringify(await migrateDatabase(args, options), null, 2) }] };
31445
31706
  }
31446
31707
  if (args.action === "watch") {
31447
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
31708
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
31448
31709
  const interval = Math.max(100, Math.min(1e4, Number(args.interval_ms || 300)));
31449
31710
  let fingerprint = "";
31450
31711
  let lastSync = null;
@@ -31466,12 +31727,12 @@ function registerRemoteDevTools(server, options = {}) {
31466
31727
  // src/shared/tools/developer-experience-tools.ts
31467
31728
  import { existsSync as existsSync17 } from "node:fs";
31468
31729
  import { mkdir as mkdir7, readdir as readdir8, readFile as readFile8, writeFile as writeFile7 } from "node:fs/promises";
31469
- import { dirname as dirname13, join as join20, resolve as resolve26 } from "node:path";
31730
+ import { dirname as dirname14, join as join20, resolve as resolve27 } from "node:path";
31470
31731
 
31471
31732
  // src/shared/context.ts
31472
- import { existsSync as existsSync16, readFileSync as readFileSync11 } from "node:fs";
31733
+ import { existsSync as existsSync16, readFileSync as readFileSync12 } from "node:fs";
31473
31734
  import { homedir as homedir3 } from "node:os";
31474
- import { resolve as resolve25 } from "node:path";
31735
+ import { resolve as resolve26 } from "node:path";
31475
31736
  var CORE_CONTEXT_KEYS2 = [
31476
31737
  "SUPABASE_URL",
31477
31738
  "SUPABASE_SERVICE_ROLE_KEY",
@@ -31513,7 +31774,7 @@ function readEnvFile2(path, required) {
31513
31774
  return {};
31514
31775
  }
31515
31776
  try {
31516
- return parseEnvFile2(readFileSync11(path, "utf8"));
31777
+ return parseEnvFile2(readFileSync12(path, "utf8"));
31517
31778
  } catch (error) {
31518
31779
  const message = error instanceof Error ? error.message : String(error);
31519
31780
  throw new Error(`Failed to read SupaCloud environment file ${path}: ${message}`);
@@ -31587,7 +31848,7 @@ function parseInsecureTls2(values) {
31587
31848
  }
31588
31849
  function namedEnvironmentSource2(cwd, selector) {
31589
31850
  const environment = normalizeEnvironmentName(selector);
31590
- const path = resolve25(cwd, `.env.supacloud.${selector}`);
31851
+ const path = resolve26(cwd, `.env.supacloud.${selector}`);
31591
31852
  const values = readEnvFile2(path, true);
31592
31853
  if (values.SUPACLOUD_ENV && normalizeEnvironmentName(values.SUPACLOUD_ENV) !== environment) {
31593
31854
  throw new Error(`SUPACLOUD_ENV in ${path} does not match selector ${selector}`);
@@ -31595,7 +31856,7 @@ function namedEnvironmentSource2(cwd, selector) {
31595
31856
  return { values, kind: "named_env_file", path, environment };
31596
31857
  }
31597
31858
  function explicitEnvironmentSource2(cwd, envFile) {
31598
- const path = resolve25(cwd, envFile);
31859
+ const path = resolve26(cwd, envFile);
31599
31860
  const values = readEnvFile2(path, true);
31600
31861
  if (!values.SUPACLOUD_ENV)
31601
31862
  throw new Error(`SUPACLOUD_ENV is required in ${path}`);
@@ -31624,7 +31885,7 @@ function contextSource2(env, cwd, selection) {
31624
31885
  if (hasProcessContext2(env)) {
31625
31886
  return { values: processValues2(env), kind: "process_env", path: null, environment: "" };
31626
31887
  }
31627
- const path = resolve25(cwd, ".env");
31888
+ const path = resolve26(cwd, ".env");
31628
31889
  const values = readEnvFile2(path, false);
31629
31890
  const environment = values.SUPACLOUD_ENV ? normalizeEnvironmentName(values.SUPACLOUD_ENV) : "";
31630
31891
  return { values, kind: Object.keys(values).length ? "legacy_dotenv" : "none", path: existsSync16(path) ? path : null, environment };
@@ -31639,7 +31900,7 @@ function resolveSupaCloudContext2(env = process.env, cwd = process.cwd(), select
31639
31900
  host,
31640
31901
  sshUser: env.SUPACLOUD_SSH_USER ?? "root",
31641
31902
  sshPort: parseInt(env.SUPACLOUD_SSH_PORT ?? "22", 10),
31642
- sshKey: env.SUPACLOUD_SSH_KEY ?? resolve25(homedir3(), ".ssh", "id_rsa"),
31903
+ sshKey: env.SUPACLOUD_SSH_KEY ?? resolve26(homedir3(), ".ssh", "id_rsa"),
31643
31904
  sshPass: env.SUPACLOUD_SSH_PASS ?? "",
31644
31905
  apiUrl: core.apiUrl,
31645
31906
  apiToken: core.apiToken,
@@ -31760,7 +32021,7 @@ async function ensureGitignore(root) {
31760
32021
  return true;
31761
32022
  }
31762
32023
  async function initializeProject(request, options) {
31763
- const root = resolve26(request.root || options.cwd || process.cwd());
32024
+ const root = resolve27(request.root || options.cwd || process.cwd());
31764
32025
  await mkdir7(root, { recursive: true });
31765
32026
  const configPath = join20(root, "supacloud.json");
31766
32027
  if (existsSync17(configPath)) {
@@ -31873,11 +32134,11 @@ function deployMissing(context, application, hasFrontend = false) {
31873
32134
  }
31874
32135
  async function inspectProfile(profile) {
31875
32136
  try {
31876
- const context = resolveSupaCloudContext2({}, dirname13(profile.path), {
32137
+ const context = resolveSupaCloudContext2({}, dirname14(profile.path), {
31877
32138
  environmentName: profile.name
31878
32139
  });
31879
32140
  const status = statusMissing(context);
31880
- const configText = await readFile8(join20(dirname13(profile.path), "supacloud.json"), "utf8").catch((error) => {
32141
+ const configText = await readFile8(join20(dirname14(profile.path), "supacloud.json"), "utf8").catch((error) => {
31881
32142
  if (error instanceof Error && "code" in error && error.code === "ENOENT")
31882
32143
  return "{}";
31883
32144
  throw error;
@@ -31921,7 +32182,7 @@ async function inspectProfile(profile) {
31921
32182
  }
31922
32183
  }
31923
32184
  async function inspectEnvironment(request, options) {
31924
- const root = resolve26(request.root || options.cwd || process.cwd());
32185
+ const root = resolve27(request.root || options.cwd || process.cwd());
31925
32186
  const profiles = await environmentProfiles(root);
31926
32187
  if (request.action === "list") {
31927
32188
  const active = options.activeContext?.environment || null;
@@ -32103,7 +32364,7 @@ async function runProjectDeployment(http, args) {
32103
32364
  // package.json
32104
32365
  var package_default = {
32105
32366
  name: "@supacloud/cli",
32106
- version: "0.103.3",
32367
+ version: "0.103.6",
32107
32368
  description: "Project-scoped CLI for SupaCloud users",
32108
32369
  type: "module",
32109
32370
  main: "./dist/index.js",
@@ -32155,19 +32416,19 @@ var package_default = {
32155
32416
  directory: "packages/cli"
32156
32417
  },
32157
32418
  dependencies: {
32158
- "@supacloud/compiler": "^0.46.6",
32159
- "@supacloud/delivery": "0.19.0",
32160
- "@supacloud/db": "0.18.0",
32419
+ "@supacloud/compiler": "^0.47.2",
32420
+ "@supacloud/delivery": "0.19.3",
32421
+ "@supacloud/db": "0.18.3",
32161
32422
  typebox: "1.3.37"
32162
32423
  },
32163
32424
  overrides: {
32164
- "@supacloud/contracts": "0.11.1",
32165
- "@supacloud/delivery": "0.19.0",
32425
+ "@supacloud/contracts": "0.11.4",
32426
+ "@supacloud/delivery": "0.19.3",
32166
32427
  "@graphql-tools/utils": "^12.0.4"
32167
32428
  },
32168
32429
  devDependencies: {
32169
32430
  "@supabase/supabase-js": "2.117.3",
32170
- "@supacloud/elysia": "0.33.1",
32431
+ "@supacloud/elysia": "0.33.4",
32171
32432
  "@types/bun": "^1.4.3",
32172
32433
  effect: "4.0.5",
32173
32434
  elysia: "2.0.0-beta.32",
@@ -32456,6 +32717,7 @@ EXAMPLES
32456
32717
  ${preferredCommand} app explain --target CaseService
32457
32718
  ${preferredCommand} app context --root . --format json
32458
32719
  ${preferredCommand} app context --root . --target CaseModule --format json
32720
+ ${preferredCommand} app context --root . --target CaseModule --events execution.ndjson --request-id request-123 --format json
32459
32721
  ${preferredCommand} app doctor --root .
32460
32722
  ${preferredCommand} app fix --root . --fix fix.json --write
32461
32723
  ${preferredCommand} generate --kind module --name billing