@supacloud/cli 0.62.1 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +370 -140
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -217356,6 +217356,7 @@ function confirmedFunctionDeletion(payload, expectation) {
217356
217356
  var execFileAsync = promisify(execFile);
217357
217357
  var SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
217358
217358
  var FORBIDDEN_BUNDLE_SEGMENTS = new Set(["node_modules", ".git"]);
217359
+ var EDGE_FUNCTION_DEPLOY_TIMEOUT_MS = 5 * 60000;
217359
217360
  var FUNCTION_FRAMEWORKS2 = ["fetch", "elysia", "hono", "sveltekit-function"];
217360
217361
  function scaffoldFiles(framework, slug) {
217361
217362
  if (framework === "elysia") {
@@ -218217,7 +218218,7 @@ ${deployCheck.err}`;
218217
218218
  expected_active_version: expectedActiveVersion,
218218
218219
  expected_activation_id: expectedActivationId,
218219
218220
  ...functionConfig()
218220
- });
218221
+ }, { timeoutMs: EDGE_FUNCTION_DEPLOY_TIMEOUT_MS });
218221
218222
  return functionMutationResponse({
218222
218223
  operation: "edge_functions.deploy",
218223
218224
  projectRef: ref,
@@ -218236,7 +218237,7 @@ ${deployCheck.err}`;
218236
218237
  expected_active_version: expectedActiveVersion,
218237
218238
  expected_activation_id: expectedActivationId,
218238
218239
  ...functionConfig()
218239
- });
218240
+ }, { timeoutMs: EDGE_FUNCTION_DEPLOY_TIMEOUT_MS });
218240
218241
  return functionMutationResponse({
218241
218242
  operation: "edge_functions.deploy_bundle",
218242
218243
  projectRef: ref,
@@ -221518,9 +221519,9 @@ function registerAiTools(server2) {
221518
221519
  }
221519
221520
 
221520
221521
  // src/shared/tools/app-tools.ts
221521
- import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
221522
+ import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
221522
221523
  import { mkdir as mkdir6, readFile as readFile8, readdir as readdir5, writeFile as writeFile5 } from "node:fs/promises";
221523
- import { basename as basename8, dirname as dirname12, join as join15, relative as relative12, resolve as resolve17 } from "node:path";
221524
+ import { basename as basename8, dirname as dirname12, join as join16, relative as relative12, resolve as resolve18 } from "node:path";
221524
221525
 
221525
221526
  // node_modules/@supacloud/compiler/dist/index.js
221526
221527
  import { dirname as dirname22, relative as relative6, sep as sep4 } from "node:path";
@@ -229355,7 +229356,7 @@ function renderClient(graph, options) {
229355
229356
  "",
229356
229357
  "export interface ApiClientConfig {",
229357
229358
  " baseUrl?: string;",
229358
- " fetch?: typeof fetch;",
229359
+ " fetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;",
229359
229360
  " headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);",
229360
229361
  " interceptors?: HttpInterceptorFn[];",
229361
229362
  " /** Normalize response objects like Elysia's default schema validator. */",
@@ -246887,7 +246888,7 @@ test("partial and untagged inherited remote profiles cannot mix with selected fi
246887
246888
  // ../compiler/package.json
246888
246889
  var package_default = {
246889
246890
  name: "@supacloud/compiler",
246890
- version: "0.31.0",
246891
+ version: "0.31.1",
246891
246892
  description: "Static compiler for @supacloud/app metadata: builds the application graph from AST, validates it, and generates reflection-free factory code",
246892
246893
  type: "module",
246893
246894
  main: "./dist/index.js",
@@ -247048,7 +247049,7 @@ var package_default2 = {
247048
247049
  },
247049
247050
  dependencies: {
247050
247051
  "@angular/core": "^22.1.5",
247051
- "@supacloud/contracts": "0.8.0",
247052
+ "@supacloud/contracts": "file:../contracts",
247052
247053
  rxjs: "7.8.2",
247053
247054
  typebox: "1.3.34"
247054
247055
  },
@@ -248650,16 +248651,22 @@ var package_default5 = {
248650
248651
  // ../db/package.json
248651
248652
  var package_default6 = {
248652
248653
  name: "@supacloud/db",
248653
- version: "0.11.0",
248654
+ version: "0.12.0",
248654
248655
  description: "Database governance layer for SupaCloud: RLS policies, RPC functions and grants as first-class resources, with manifest/catalog reconciliation",
248655
248656
  type: "module",
248656
248657
  main: "./dist/index.js",
248657
248658
  module: "./dist/index.js",
248658
248659
  types: "./dist/index.d.ts",
248659
248660
  bin: {
248660
- "supacloud-sql-impact": "./dist/sql-impact-cli.js"
248661
+ "supacloud-sql-impact": "./dist/sql-impact-cli.js",
248662
+ "supacloud-db": "./dist/source-contracts-cli.js"
248661
248663
  },
248662
248664
  exports: {
248665
+ "./source-contracts": {
248666
+ types: "./dist/source-contracts.d.ts",
248667
+ import: "./dist/source-contracts.js"
248668
+ },
248669
+ "./source-contracts-cli": "./dist/source-contracts-cli.js",
248663
248670
  "./sql-analysis": {
248664
248671
  types: "./dist/sql-analysis.d.ts",
248665
248672
  import: "./dist/sql-analysis.js"
@@ -248691,7 +248698,7 @@ var package_default6 = {
248691
248698
  ],
248692
248699
  scripts: {
248693
248700
  build: "bun run clean && bun run build:js && bun run build:types",
248694
- "build:js": "bun build src/index.ts src/command-bun.ts src/drizzle.ts src/drizzle-bun.ts src/sql-analysis.ts src/sql-impact-cli.ts --outdir dist --target node --external bun --external @supacloud/contracts --external drizzle-orm --external libpg-query",
248701
+ "build:js": "bun build src/index.ts src/command-bun.ts src/drizzle.ts src/drizzle-bun.ts src/sql-analysis.ts src/sql-impact-cli.ts src/source-contracts.ts src/source-contracts-cli.ts --outdir dist --target node --external bun --external @supacloud/contracts --external drizzle-orm --external libpg-query --external @typescript/typescript6",
248695
248702
  "build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
248696
248703
  clean: "rm -rf dist",
248697
248704
  prepublishOnly: "bun run build",
@@ -248715,14 +248722,15 @@ var package_default6 = {
248715
248722
  },
248716
248723
  devDependencies: {
248717
248724
  "@sinclair/typebox": "0.34.52",
248718
- "@typescript/typescript6": "^6.0.2",
248719
248725
  "drizzle-orm": "1.0.0-rc.4",
248726
+ "drizzle-kit": "1.0.0-rc.4",
248720
248727
  "@types/bun": "^1.4.2",
248721
248728
  typescript: "^7.0.2"
248722
248729
  },
248723
248730
  dependencies: {
248731
+ "@typescript/typescript6": "^6.0.2",
248724
248732
  "libpg-query": "18.1.4",
248725
- "@supacloud/contracts": "file:../contracts"
248733
+ "@supacloud/contracts": "0.8.0"
248726
248734
  },
248727
248735
  peerDependencies: {
248728
248736
  "drizzle-orm": "1.0.0-rc.4"
@@ -248733,13 +248741,13 @@ var package_default6 = {
248733
248741
  }
248734
248742
  },
248735
248743
  overrides: {
248736
- "@supacloud/contracts": "file:../contracts"
248744
+ "@supacloud/contracts": "0.8.0"
248737
248745
  }
248738
248746
  };
248739
248747
  // ../supacloud-js/package.json
248740
248748
  var package_default7 = {
248741
248749
  name: "@supacloud/js",
248742
- version: "0.36.0",
248750
+ version: "0.36.1",
248743
248751
  description: "Platform SDK for SupaCloud, built on top of supabase-js",
248744
248752
  type: "module",
248745
248753
  main: "./dist/index.cjs",
@@ -248826,7 +248834,7 @@ var package_default7 = {
248826
248834
  "@supabase/supabase-js": "^2.115.0"
248827
248835
  },
248828
248836
  dependencies: {
248829
- "@supacloud/contracts": "file:../contracts",
248837
+ "@supacloud/contracts": "0.8.0",
248830
248838
  rxjs: "7.8.2"
248831
248839
  },
248832
248840
  devDependencies: {
@@ -248839,11 +248847,133 @@ var package_default7 = {
248839
248847
  }
248840
248848
  };
248841
248849
 
248850
+ // src/shared/tools/app-starter-database.ts
248851
+ var STARTER_DATABASE_CONFIG = {
248852
+ version: 1,
248853
+ schema: ["db/schema.ts"],
248854
+ functions: "db/functions",
248855
+ migrations: "migrations",
248856
+ contracts: "db/contracts",
248857
+ audit: "output/database-audit",
248858
+ consumers: ["src", "scripts", "tests"],
248859
+ auditConsumers: [],
248860
+ role: "starter_review_http"
248861
+ };
248862
+ var STARTER_DATABASE_SCHEMA = `import { sql } from "drizzle-orm";
248863
+ import { boolean, check, integer, jsonb, pgTable, primaryKey, text, uuid } from "drizzle-orm/pg-core";
248864
+
248865
+ // Structure for the reviewed starter migrations. Grants/policies stay in those migrations.
248866
+ export const application = pgTable.withRLS("starter_application", {
248867
+ singleton: boolean().default(true).primaryKey(),
248868
+ projectId: text("project_id").notNull(),
248869
+ tenantId: text("tenant_id").notNull(),
248870
+ }, table => [
248871
+ check("starter_application_singleton_check", sql\`\${table.singleton}\`),
248872
+ check("starter_application_project_id_check", sql\`length(\${table.projectId}) > 0\`),
248873
+ check("starter_application_tenant_id_check", sql\`length(\${table.tenantId}) > 0\`),
248874
+ ]);
248875
+
248876
+ export const reviews = pgTable.withRLS("starter_reviews", {
248877
+ id: text().primaryKey(),
248878
+ ownerId: text("owner_id").notNull(),
248879
+ state: text({ enum: ["draft", "approved"] }).notNull(),
248880
+ version: integer().notNull(),
248881
+ }, table => [
248882
+ check("starter_reviews_state_check", sql\`\${table.state} IN ('draft', 'approved')\`),
248883
+ check("starter_reviews_version_check", sql\`\${table.version} > 0\`),
248884
+ ]);
248885
+
248886
+ export const members = pgTable.withRLS("starter_members", {
248887
+ subject: text().primaryKey(),
248888
+ enabled: boolean().default(true).notNull(),
248889
+ canApprove: boolean("can_approve").default(false).notNull(),
248890
+ storageSubject: uuid("storage_subject").unique(),
248891
+ });
248892
+
248893
+ export const attachments = pgTable.withRLS("starter_attachments", {
248894
+ reviewId: text("review_id").primaryKey().references(() => reviews.id),
248895
+ artifactId: uuid("artifact_id").notNull().unique(),
248896
+ ownerId: text("owner_id").notNull(),
248897
+ runId: uuid("run_id").notNull().unique(),
248898
+ objectPath: text("object_path").notNull().unique(),
248899
+ });
248900
+
248901
+ export const attachmentResults = pgTable.withRLS("starter_attachment_results", {
248902
+ reviewId: text("review_id").notNull().references(() => reviews.id),
248903
+ version: integer().notNull(),
248904
+ artifactId: uuid("artifact_id").notNull(),
248905
+ result: jsonb().$type<unknown>().notNull(),
248906
+ }, table => [
248907
+ primaryKey({ columns: [table.reviewId, table.version, table.artifactId] }),
248908
+ check("starter_attachment_results_version_check", sql\`\${table.version} >= 2\`),
248909
+ ]);
248910
+
248911
+ export type ReviewRow = typeof reviews.$inferSelect;
248912
+ export type NewReview = typeof reviews.$inferInsert;
248913
+ `;
248914
+ var STARTER_DATABASE_GUIDE = `
248915
+ ## Database Source Workflow
248916
+
248917
+ Drizzle owns table declarations and inferred row types in db/schema.ts.
248918
+ Use the existing @supacloud/db/drizzle-bun adapters for typed queries and governed
248919
+ transactions; never replace permission, idempotency or audit checks with plain CRUD.
248920
+ Opaque JSON still needs runtime decoding.
248921
+
248922
+ After installing dependencies, run \`bun run db:generate\` once and commit db/contracts/.
248923
+ The default \`bun run check\` and build fail on stale database contracts before any
248924
+ compiler regeneration. After an intentional source change, run db:generate again,
248925
+ review the diff, then run check. Ordinary checks are offline.
248926
+
248927
+ - Maintain one schema-qualified function with explicit grants per db/functions/*.sql.
248928
+ - Preserve migrations/ and its existing executor/ledger. Add forward migrations only.
248929
+ - \`bun run db:diff\` generates Drizzle drafts under db/migration-candidates/, never
248930
+ into the deployment directory. The starter has existing SQL history, so establish
248931
+ and review a matching Drizzle baseline before promoting any draft; the first
248932
+ draft is not automatically an incremental production migration.
248933
+ - \`bun run db:pull\` requires an explicitly selected DATABASE_URL and writes only
248934
+ output/database-audit/drizzle-candidate/. Review candidates; never overwrite source blindly.
248935
+ - Full SQL dumps belong under the ignored output/database-audit/ directory. They are
248936
+ audit/recovery artifacts, never ordinary type, application or test inputs.
248937
+ - \`bun run db:assess\` explains adoption/findings without writing or connecting.
248938
+ - GraphQL/PostgREST exports remain legitimate protocol contracts. This check is not
248939
+ proof of deployed schema, effective role permissions or complete RLS equivalence.
248940
+
248941
+ Do not introduce any/@ts-ignore to bypass a contract. Use Drizzle-inferred types,
248942
+ preserve bigint/numeric precision and decode unknown results at the boundary.
248943
+ `;
248944
+ function starterDatabaseFiles() {
248945
+ return {
248946
+ "database.sources.json": JSON.stringify(STARTER_DATABASE_CONFIG, null, 2) + `
248947
+ `,
248948
+ "db/schema.ts": STARTER_DATABASE_SCHEMA,
248949
+ "db/functions/README.md": `Maintain one schema-qualified function and its explicit EXECUTE ACL per SQL file. No RPC functions are needed by the initial transactional starter.
248950
+ `,
248951
+ "drizzle.config.ts": `import { defineConfig } from "drizzle-kit";
248952
+ export default defineConfig({
248953
+ dialect: "postgresql",
248954
+ schema: "./db/schema.ts",
248955
+ out: "./db/migration-candidates",
248956
+ });
248957
+ `,
248958
+ "drizzle.pull.config.ts": `import { defineConfig } from "drizzle-kit";
248959
+ const url = process.env.DATABASE_URL;
248960
+ if (!url) throw new Error("Select an explicit DATABASE_URL for introspection");
248961
+ export default defineConfig({
248962
+ dialect: "postgresql",
248963
+ schema: "./db/schema.ts",
248964
+ out: "./output/database-audit/drizzle-candidate",
248965
+ dbCredentials: { url },
248966
+ });
248967
+ `
248968
+ };
248969
+ }
248970
+
248842
248971
  // src/shared/tools/app-starter.ts
248843
248972
  var json2 = (value) => `${JSON.stringify(value, null, 2)}
248844
248973
  `;
248845
248974
  function appStarterFiles(name) {
248846
248975
  return {
248976
+ ...starterDatabaseFiles(),
248847
248977
  "package.json": json2({
248848
248978
  name,
248849
248979
  version: "0.0.0",
@@ -248854,10 +248984,15 @@ function appStarterFiles(name) {
248854
248984
  compile: "bun --no-env-file node_modules/@supacloud/compiler/dist/cli.js compile",
248855
248985
  "check:generated": "bun --no-env-file node_modules/@supacloud/compiler/dist/cli.js check",
248856
248986
  typecheck: "tsc --noEmit",
248857
- check: "bun run compile && bun run check:generated && bun run typecheck && bun run test",
248987
+ "db:generate": "supacloud-db generate",
248988
+ "db:check": "supacloud-db check",
248989
+ "db:assess": "supacloud-db assess",
248990
+ "db:diff": "drizzle-kit generate --config drizzle.config.ts",
248991
+ "db:pull": "drizzle-kit pull --config drizzle.pull.config.ts",
248992
+ check: "bun run db:check && bun run compile && bun run check:generated && bun run typecheck && bun run test",
248858
248993
  test: "bun run compile && bun --no-env-file scripts/environment.ts test bun test",
248859
248994
  dev: "bun --no-env-file scripts/environment.ts development bun scripts/dev.ts",
248860
- build: "bun run compile && bun run typecheck && bun build src/application.ts --target bun --minify --outdir dist",
248995
+ build: "bun run db:check && bun run compile && bun run typecheck && bun build src/application.ts --target bun --minify --outdir dist",
248861
248996
  "env:development": "bun --no-env-file scripts/environment.ts development",
248862
248997
  "env:test": "bun --no-env-file scripts/environment.ts test",
248863
248998
  "env:staging": "bun --no-env-file scripts/environment.ts staging",
@@ -248869,6 +249004,7 @@ function appStarterFiles(name) {
248869
249004
  "@supacloud/commands": `^${package_default4.version}`,
248870
249005
  "@supacloud/contracts": `^${package_default5.version}`,
248871
249006
  "@supacloud/db": `^${package_default6.version}`,
249007
+ "drizzle-orm": package_default6.peerDependencies["drizzle-orm"],
248872
249008
  "@supacloud/js": `^${package_default7.version}`,
248873
249009
  "@supabase/supabase-js": package_default7.peerDependencies["@supabase/supabase-js"],
248874
249010
  elysia: "2.0.0-beta.19",
@@ -248876,6 +249012,7 @@ function appStarterFiles(name) {
248876
249012
  },
248877
249013
  devDependencies: {
248878
249014
  "@supacloud/compiler": `^${package_default.version}`,
249015
+ "drizzle-kit": package_default6.devDependencies["drizzle-kit"],
248879
249016
  "@types/bun": "^1.4.2",
248880
249017
  typescript: "^7.0.2"
248881
249018
  }
@@ -248891,13 +249028,15 @@ function appStarterFiles(name) {
248891
249028
  noEmit: true,
248892
249029
  types: ["bun"]
248893
249030
  },
248894
- include: ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts", "generated/**/*.ts", "supacloud.config.ts"]
249031
+ include: ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts", "generated/**/*.ts", "db/schema.ts", "db/contracts/**/*.ts", "supacloud.config.ts", "drizzle*.config.ts"]
248895
249032
  }),
248896
249033
  "bunfig.toml": `env = false
248897
249034
  `,
248898
249035
  ".gitignore": [
248899
249036
  "node_modules/",
248900
249037
  "dist/",
249038
+ "output/database-audit/",
249039
+ "db/migration-candidates/",
248901
249040
  ".env",
248902
249041
  ".env.*",
248903
249042
  "!.env.*.example",
@@ -248986,7 +249125,7 @@ test("generated query client preserves its read contract without a live database
248986
249125
  });
248987
249126
  `,
248988
249127
  "REACTIVE.md": STARTER_REACTIVE_GUIDE,
248989
- "AGENTS.md": STARTER_REACTIVE_AGENTS,
249128
+ "AGENTS.md": STARTER_REACTIVE_AGENTS + STARTER_DATABASE_GUIDE,
248990
249129
  "tests/reactive.test.ts": STARTER_REACTIVE_TEST,
248991
249130
  "scripts/environment.ts": STARTER_ENVIRONMENT,
248992
249131
  "tests/environment.test.ts": STARTER_ENVIRONMENT_TEST,
@@ -249088,6 +249227,7 @@ import { ApplicationError, assertFeatureTransition } from "@supacloud/elysia";
249088
249227
  import { t } from "elysia";
249089
249228
  import { VerifyReviewAttachment } from "./attachment";
249090
249229
  import { ReviewUploads, ReviewUploadsController, type ReviewUploadPort } from "./uploads";
249230
+ import type { ReviewRow } from "../../db/schema";
249091
249231
 
249092
249232
  export const reviewSpec = defineFeatureSpec({
249093
249233
  name: "review",
@@ -249102,7 +249242,7 @@ export const reviewSpec = defineFeatureSpec({
249102
249242
  },
249103
249243
  });
249104
249244
 
249105
- interface Review { state: string; version: number }
249245
+ type Review = Pick<ReviewRow, "state" | "version">;
249106
249246
  // Production implementations must bind both operations to the current transaction.
249107
249247
  export interface ReviewStore extends Partial<ReviewUploadPort> {
249108
249248
  get(table: string, key: string): unknown;
@@ -249125,7 +249265,7 @@ export const requireRequest: Aspect = (context, next) => {
249125
249265
 
249126
249266
  function readReview(value: unknown): Review {
249127
249267
  if (typeof value !== "object" || value === null ||
249128
- !("state" in value) || typeof value.state !== "string" ||
249268
+ !("state" in value) || (value.state !== "draft" && value.state !== "approved") ||
249129
249269
  !("version" in value) || typeof value.version !== "number") {
249130
249270
  throw new ApplicationError("Review not found", { status: 404, code: "REVIEW_NOT_FOUND" });
249131
249271
  }
@@ -249252,6 +249392,7 @@ test("the production composition root rejects missing governance adapters", () =
249252
249392
 
249253
249393
  \`\`\`sh
249254
249394
  bun install
249395
+ bun run db:generate
249255
249396
  bun run check
249256
249397
  bun run dev
249257
249398
  \`\`\`
@@ -249273,6 +249414,28 @@ compiler-checked command/route/governance bindings, an explicit AOP function,
249273
249414
  HTTP schemas, permission denial, transaction rollback, idempotency and audit.
249274
249415
  It is not a complete Maker-Checker workflow or a production authorization policy.
249275
249416
 
249417
+ ## Frontend SDK Boundary
249418
+
249419
+ Use @supacloud/js as the platform SDK around your existing user-scoped
249420
+ @supabase/supabase-js client. Pass that same client to existing UI providers;
249421
+ supacloud.supabase exposes it unchanged. Keep UI routing, forms and query
249422
+ caches in your frontend framework or svadmin, not in a new DI container.
249423
+
249424
+ For generated/client.ts, supply createAuthenticatedFetch from
249425
+ @supacloud/js/contracts as its fetch option. Resolve the current user token
249426
+ from the same Supabase session for each request; do not capture a token at
249427
+ startup or introduce a second session store. Use a fixed trusted HTTPS API
249428
+ origin. The authenticated transport rejects missing credentials and redirects
249429
+ and does not replay a write after 401. Its underlying fetch must also be
249430
+ single-attempt.
249431
+
249432
+ Reuse the same session resolver for generated/graphql.ts when adopting queries.
249433
+ The local memory demo is not this authenticated production integration.
249434
+ Never use supacloud.commands or supacloud.workflows from a browser action:
249435
+ those RPCs require service-role credentials. Browser business commands use
249436
+ application endpoints, optionally composed through @supacloud/js/contracts.
249437
+ Management API tokens and service-role keys remain on trusted servers.
249438
+
249276
249439
  ## Typed Queries
249277
249440
 
249278
249441
  This starter uses Database First as its only GraphQL server-schema model.
@@ -249541,6 +249704,8 @@ policy. Invalid transaction/idempotency modes fail compilation instead of
249541
249704
  silently disabling governance. onExecution receives metadata-only trace events;
249542
249705
  durable audit still belongs to the command governance adapter.
249543
249706
 
249707
+ ${STARTER_DATABASE_GUIDE}
249708
+
249544
249709
  ## CI
249545
249710
 
249546
249711
  After the first compilation, commit generated/. In CI run
@@ -249574,6 +249739,55 @@ async function initializeAppProject(options) {
249574
249739
  return { root, name, files: Object.keys(files) };
249575
249740
  }
249576
249741
 
249742
+ // src/shared/tools/app-database-check.ts
249743
+ import { spawnSync } from "node:child_process";
249744
+ import { existsSync as existsSync11 } from "node:fs";
249745
+ import { join as join14, resolve as resolve16 } from "node:path";
249746
+ var CHECK_ENTRY = `
249747
+ import { createRequire } from "node:module";
249748
+ import { join } from "node:path";
249749
+ import { pathToFileURL } from "node:url";
249750
+ const root = process.argv[1];
249751
+ const cli = createRequire(join(root, "package.json")).resolve("@supacloud/db/source-contracts-cli");
249752
+ process.argv = [process.execPath, cli, "check", "--root", root];
249753
+ await import(pathToFileURL(cli).href);
249754
+ `;
249755
+ function checkAppDatabaseSources(projectRoot) {
249756
+ const root = resolve16(projectRoot);
249757
+ if (!existsSync11(join14(root, "database.sources.json")))
249758
+ return;
249759
+ const name = "database-source-contracts";
249760
+ try {
249761
+ const result = spawnSync(process.versions.bun ? "bun" : process.execPath, [
249762
+ ...process.versions.bun ? ["--no-env-file"] : ["--input-type=module"],
249763
+ "--eval",
249764
+ CHECK_ENTRY,
249765
+ "--",
249766
+ root
249767
+ ], { cwd: root, encoding: "utf8", timeout: 30000, maxBuffer: 4 * 1024 * 1024 });
249768
+ if (result.error)
249769
+ throw result.error;
249770
+ const report = JSON.parse(result.stdout);
249771
+ if (!report || typeof report !== "object" || !("scope" in report) || report.scope !== "local-source-contracts" || !("ok" in report) || typeof report.ok !== "boolean" || !("findings" in report) || !Array.isArray(report.findings)) {
249772
+ throw new Error("Invalid database source check response");
249773
+ }
249774
+ const messages = [];
249775
+ for (const finding of report.findings) {
249776
+ if (!finding || typeof finding !== "object" || !("file" in finding) || typeof finding.file !== "string" || !("message" in finding) || typeof finding.message !== "string")
249777
+ throw new Error("Invalid source finding");
249778
+ messages.push(`${finding.file}: ${finding.message}`);
249779
+ }
249780
+ return {
249781
+ name,
249782
+ ok: result.status === 0 && report.ok && !messages.length,
249783
+ detail: messages.join(`
249784
+ `) || (result.status === 0 && report.ok ? "Offline database contracts and boundaries are current" : "Database source check failed")
249785
+ };
249786
+ } catch {
249787
+ return { name, ok: false, detail: "Cannot run the project database checker. Install the project runtime and @supacloud/db with source-contracts support, then run `supacloud-db check --root .` for diagnostics." };
249788
+ }
249789
+ }
249790
+
249577
249791
  // src/shared/tools/app-resource.ts
249578
249792
  function resourceScaffold(name, className) {
249579
249793
  return {
@@ -249652,7 +249866,7 @@ test("${name} controller preserves an asynchronous read failure", async () => {
249652
249866
  // src/shared/tools/app-scaffold-writes.ts
249653
249867
  import { randomUUID as randomUUID2 } from "node:crypto";
249654
249868
  import { link, lstat as lstat4, mkdir as mkdir5, open as open4, readFile as readFile4, realpath as realpath5, rename as rename5, rmdir, unlink as unlink3 } from "node:fs/promises";
249655
- import { dirname as dirname11, isAbsolute as isAbsolute6, join as join14, relative as relative11, resolve as resolve16, sep as sep11, win32 } from "node:path";
249869
+ import { dirname as dirname11, isAbsolute as isAbsolute6, join as join15, relative as relative11, resolve as resolve17, sep as sep11, win32 } from "node:path";
249656
249870
 
249657
249871
  class ScaffoldError extends Error {
249658
249872
  code;
@@ -249673,7 +249887,7 @@ function scaffoldPath(root, path) {
249673
249887
  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")) {
249674
249888
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is reserved or not portable");
249675
249889
  }
249676
- const target = resolve16(root, path);
249890
+ const target = resolve17(root, path);
249677
249891
  const local = relative11(root, target);
249678
249892
  if (!local || local === ".." || local.startsWith(`..${sep11}`) || isAbsolute6(local)) {
249679
249893
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is outside the project root");
@@ -249685,7 +249899,7 @@ async function snapshot(root, path) {
249685
249899
  const parts = relative11(root, target).split(sep11);
249686
249900
  let current = root;
249687
249901
  for (const [index, part] of parts.entries()) {
249688
- current = join14(current, part);
249902
+ current = join15(current, part);
249689
249903
  let stat;
249690
249904
  try {
249691
249905
  stat = await lstat4(current);
@@ -249712,7 +249926,7 @@ function sameFile(a, b) {
249712
249926
  return a === null ? b === null : b !== null && a.content === b.content && a.dev === b.dev && a.ino === b.ino && a.mode === b.mode;
249713
249927
  }
249714
249928
  async function planScaffoldWrites(root, writes) {
249715
- const canonical = await realpath5(resolve16(root));
249929
+ const canonical = await realpath5(resolve17(root));
249716
249930
  const targets = new Set;
249717
249931
  const planned = [];
249718
249932
  for (const write of writes) {
@@ -249735,7 +249949,7 @@ async function planScaffoldWrites(root, writes) {
249735
249949
  return Object.freeze({ root: canonical, writes: Object.freeze(planned) });
249736
249950
  }
249737
249951
  async function applyScaffoldWrites(plan) {
249738
- const lockPath = join14(plan.root, ".supacloud-generate.lock");
249952
+ const lockPath = join15(plan.root, ".supacloud-generate.lock");
249739
249953
  const lock = await open4(lockPath, "wx").catch((error) => {
249740
249954
  if (fsCode(error) === "EEXIST")
249741
249955
  throw new ScaffoldError("SCAFFOLD_BUSY", "Another generator owns .supacloud-generate.lock; no files written");
@@ -249756,7 +249970,7 @@ async function applyScaffoldWrites(plan) {
249756
249970
  const target = scaffoldPath(plan.root, write.path);
249757
249971
  let current = plan.root;
249758
249972
  for (const part of relative11(plan.root, dirname11(target)).split(sep11).filter(Boolean)) {
249759
- current = join14(current, part);
249973
+ current = join15(current, part);
249760
249974
  try {
249761
249975
  await mkdir5(current);
249762
249976
  directories.push(current);
@@ -249865,6 +250079,7 @@ async function initProject(args) {
249865
250079
  `Initialized ${name} in ${root} (${files.length} files, template: ${template}).`,
249866
250080
  `cd '${root.replaceAll("'", "'\\''")}'`,
249867
250081
  "bun install",
250082
+ ...template === "command" ? ["bun run db:generate"] : [],
249868
250083
  "bun run check",
249869
250084
  "bun run dev",
249870
250085
  "Local demo only. Production requires persistent governance and identity adapters; see README.md."
@@ -249971,7 +250186,7 @@ async function generateScaffold(args) {
249971
250186
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", `--${flag.replaceAll("_", "-")} must be boolean`);
249972
250187
  }
249973
250188
  }
249974
- const root = resolve17(args.root || process.cwd());
250189
+ const root = resolve18(args.root || process.cwd());
249975
250190
  const dir = args.dir ?? "src/features";
249976
250191
  if (dir !== ".")
249977
250192
  scaffoldPath(root, dir);
@@ -249987,20 +250202,20 @@ async function generateScaffold(args) {
249987
250202
  let contractName;
249988
250203
  if (kind === "module" || kind === "resource") {
249989
250204
  const name = requireIdentifier(args.name, "name");
249990
- modulePath = join15(dir, name, `${name}.module.ts`).replaceAll("\\", "/");
250205
+ modulePath = join16(dir, name, `${name}.module.ts`).replaceAll("\\", "/");
249991
250206
  moduleSymbol = `${pascalName2(name)}Module`;
249992
250207
  if (kind === "module")
249993
250208
  writes.push({ path: modulePath, content: moduleScaffold(name), overwrite: args.force === true });
249994
250209
  else
249995
250210
  for (const [file, content] of Object.entries(resourceScaffold(name, pascalName2(name)))) {
249996
- writes.push({ path: join15(dir, name, file).replaceAll("\\", "/"), content });
250211
+ writes.push({ path: join16(dir, name, file).replaceAll("\\", "/"), content });
249997
250212
  }
249998
250213
  } else {
249999
250214
  const moduleName = requireIdentifier(args.module, "module");
250000
250215
  const name = kind === "controller" ? moduleName : requireIdentifier(args.name, "name");
250001
250216
  const subdir = kind === "command" ? "commands" : kind === "query" ? "queries" : kind === "job" ? "jobs" : kind === "contract" ? "contracts" : "";
250002
- const path = join15(dir, moduleName, subdir, `${name}.${kind}.ts`).replaceAll("\\", "/");
250003
- if (kind === "controller" && existsSync11(scaffoldPath(root, path))) {
250217
+ const path = join16(dir, moduleName, subdir, `${name}.${kind}.ts`).replaceAll("\\", "/");
250218
+ if (kind === "controller" && existsSync12(scaffoldPath(root, path))) {
250004
250219
  throw new ScaffoldError("SCAFFOLD_EXISTS", `Controller already exists: ${path}(请手工合并路由到现有 controller)`);
250005
250220
  }
250006
250221
  const content = kind === "command" ? commandScaffold(moduleName, name) : kind === "query" ? queryScaffold(moduleName, name) : kind === "job" ? jobScaffold(moduleName, name) : kind === "contract" ? contractScaffold(moduleName, name) : controllerScaffold(moduleName);
@@ -250018,7 +250233,7 @@ async function generateScaffold(args) {
250018
250233
  if (new RegExp(`\\b${moduleSymbol}\\b`).test(original)) {
250019
250234
  throw new ScaffoldError("SCAFFOLD_REGISTRATION_CONFLICT", `Registration target already references ${moduleSymbol}; review the import manually`);
250020
250235
  }
250021
- let importPath = relative12(dirname12(target), resolve17(root, modulePath)).replaceAll("\\", "/").replace(/\.ts$/, "");
250236
+ let importPath = relative12(dirname12(target), resolve18(root, modulePath)).replaceAll("\\", "/").replace(/\.ts$/, "");
250022
250237
  if (!importPath.startsWith("."))
250023
250238
  importPath = `./${importPath}`;
250024
250239
  const edit = await applyDiagnosticFix({
@@ -250049,7 +250264,7 @@ async function generateScaffold(args) {
250049
250264
  written: !args.dry_run,
250050
250265
  changes
250051
250266
  }, null, 2));
250052
- const lines = changes.map((change) => `${args.dry_run ? "PREVIEW" : "✅"} ${change.action}: ${join15(plan.root, change.path)}`);
250267
+ const lines = changes.map((change) => `${args.dry_run ? "PREVIEW" : "✅"} ${change.action}: ${join16(plan.root, change.path)}`);
250053
250268
  if (args.dry_run)
250054
250269
  lines.push("No files written. Omit --dry-run to apply this generation.");
250055
250270
  if (kind === "resource")
@@ -250085,17 +250300,17 @@ function parseInclude(include) {
250085
250300
  return patterns && patterns.length > 0 ? patterns : undefined;
250086
250301
  }
250087
250302
  function sourceRoot(args, root, configured) {
250088
- const hasConfig = ["ts", "mts", "js", "mjs"].some((extension) => existsSync11(join15(root, `supacloud.config.${extension}`)));
250303
+ const hasConfig = ["ts", "mts", "js", "mjs"].some((extension) => existsSync12(join16(root, `supacloud.config.${extension}`)));
250089
250304
  return args.root && !hasConfig ? "." : configured;
250090
250305
  }
250091
250306
  async function projectCompileConfig(args) {
250092
- const root = resolve17(args.root || process.cwd());
250093
- const configFile = ["ts", "mts", "js", "mjs"].map((extension) => join15(root, `supacloud.config.${extension}`)).find((candidate) => existsSync11(candidate)) ?? null;
250307
+ const root = resolve18(args.root || process.cwd());
250308
+ const configFile = ["ts", "mts", "js", "mjs"].map((extension) => join16(root, `supacloud.config.${extension}`)).find((candidate) => existsSync12(candidate)) ?? null;
250094
250309
  const loadedConfig = await loadSupacloudConfig(root);
250095
250310
  const defaults = resolveSupacloudConfig(loadedConfig, root);
250096
250311
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
250097
250312
  const include = parseInclude(args.include) ?? loadedConfig.include;
250098
- const outDir = args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir;
250313
+ const outDir = args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir;
250099
250314
  const result = await checkProject(compileOptionsFromConfig({
250100
250315
  ...loadedConfig,
250101
250316
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
@@ -250106,8 +250321,8 @@ async function projectCompileConfig(args) {
250106
250321
  return { root, configFile, outDir, result };
250107
250322
  }
250108
250323
  async function readAllowedDependencies(root) {
250109
- const path = join15(root, "package.json");
250110
- if (!existsSync11(path))
250324
+ const path = join16(root, "package.json");
250325
+ if (!existsSync12(path))
250111
250326
  return { dependencies: [], devDependencies: [] };
250112
250327
  try {
250113
250328
  const parsed = JSON.parse(await readFile8(path, "utf8"));
@@ -250194,7 +250409,7 @@ async function findUnwiredContracts(rootDir) {
250194
250409
  for (const entry of entries) {
250195
250410
  if (skip.has(entry.name))
250196
250411
  continue;
250197
- const path = join15(directory, entry.name);
250412
+ const path = join16(directory, entry.name);
250198
250413
  if (entry.isDirectory())
250199
250414
  await walk(path);
250200
250415
  else if (entry.isFile() && entry.name.endsWith(".ts"))
@@ -250222,6 +250437,12 @@ async function findUnwiredContracts(rootDir) {
250222
250437
  async function runDoctor(args) {
250223
250438
  const { root, outDir, result } = await projectCompileConfig(args);
250224
250439
  const doctor = doctorProject(root, outDir, result.graph, result.upToDate, result.diagnostics);
250440
+ const database = checkAppDatabaseSources(root);
250441
+ if (database) {
250442
+ doctor.checks.push(database);
250443
+ if (!database.ok)
250444
+ doctor.errors += 1;
250445
+ }
250225
250446
  const fixPlan = doctorFixPlan(doctor);
250226
250447
  const autoFixable = fixPlan.filter((repair) => repair.readiness === "preview").length;
250227
250448
  const inputRequired = fixPlan.filter((repair) => repair.readiness === "input-required").length;
@@ -250252,11 +250473,11 @@ async function runDoctor(args) {
250252
250473
  `), doctor.errors > 0);
250253
250474
  }
250254
250475
  async function runFix(args) {
250255
- const root = resolve17(args.root || process.cwd());
250476
+ const root = resolve18(args.root || process.cwd());
250256
250477
  const fixPath = args.fix?.trim();
250257
250478
  if (!fixPath)
250258
250479
  throw new Error("app fix requires --fix <path-to-diagnostic-fix.json>");
250259
- const parsed = JSON.parse(await readFile8(resolve17(root, fixPath), "utf8"));
250480
+ const parsed = JSON.parse(await readFile8(resolve18(root, fixPath), "utf8"));
250260
250481
  const write = args.write === true;
250261
250482
  const applied = await applyDiagnosticFix(parsed, { rootDir: root, dryRun: !write });
250262
250483
  return textResult(JSON.stringify({
@@ -250299,7 +250520,7 @@ function devDatabase(profile, explicit) {
250299
250520
  }
250300
250521
  function readManifestModules(outDir) {
250301
250522
  try {
250302
- const parsed = JSON.parse(readFileSync9(join15(outDir, "app.manifest.json"), "utf8"));
250523
+ const parsed = JSON.parse(readFileSync9(join16(outDir, "app.manifest.json"), "utf8"));
250303
250524
  return Array.isArray(parsed.modules) ? parsed.modules.map((module) => module.name) : [];
250304
250525
  } catch {
250305
250526
  return [];
@@ -250332,12 +250553,12 @@ async function runAppDev(args, options) {
250332
250553
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "app dev --profile must be fast or integration");
250333
250554
  }
250334
250555
  const database = devDatabase(profile, args.database_url);
250335
- const root = resolve17(args.root || process.cwd());
250556
+ const root = resolve18(args.root || process.cwd());
250336
250557
  const loadedConfig = await loadSupacloudConfig(root);
250337
250558
  const defaults = resolveSupacloudConfig(loadedConfig, root);
250338
250559
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
250339
250560
  const include = parseInclude(args.include) ?? loadedConfig.include;
250340
- const outDir = args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir;
250561
+ const outDir = args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir;
250341
250562
  const watch = args.once !== true && args.watch !== false;
250342
250563
  const compileOptions = compileOptionsFromConfig({
250343
250564
  ...loadedConfig,
@@ -250423,7 +250644,7 @@ async function runAppDev(args, options) {
250423
250644
  return report(lastEvent, "stopped");
250424
250645
  }
250425
250646
  async function runCompile(args) {
250426
- const root = resolve17(args.root || process.cwd());
250647
+ const root = resolve18(args.root || process.cwd());
250427
250648
  const loadedConfig = await loadSupacloudConfig(root);
250428
250649
  const defaults = resolveSupacloudConfig(loadedConfig, root);
250429
250650
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
@@ -250432,7 +250653,7 @@ async function runCompile(args) {
250432
250653
  ...compileOptionsFromConfig({
250433
250654
  ...loadedConfig,
250434
250655
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
250435
- outDir: args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir,
250656
+ outDir: args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir,
250436
250657
  ...include === undefined ? {} : { include },
250437
250658
  strict: args.strict ?? loadedConfig.strict ?? false
250438
250659
  }, root),
@@ -250456,7 +250677,8 @@ async function runCompile(args) {
250456
250677
  return textResult(text, hasError);
250457
250678
  }
250458
250679
  async function runCheck(args) {
250459
- const root = resolve17(args.root || process.cwd());
250680
+ const root = resolve18(args.root || process.cwd());
250681
+ const database = checkAppDatabaseSources(root);
250460
250682
  const loadedConfig = await loadSupacloudConfig(root);
250461
250683
  const defaults = resolveSupacloudConfig(loadedConfig, root);
250462
250684
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
@@ -250464,12 +250686,12 @@ async function runCheck(args) {
250464
250686
  const config = compileOptionsFromConfig({
250465
250687
  ...loadedConfig,
250466
250688
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
250467
- outDir: args.out_dir ? resolve17(root, args.out_dir) : defaults.outDir,
250689
+ outDir: args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir,
250468
250690
  ...include === undefined ? {} : { include },
250469
250691
  strict: args.strict ?? loadedConfig.strict ?? false
250470
250692
  }, root);
250471
250693
  const result = await checkProject(config);
250472
- const hasError = result.diagnostics.some((diagnostic) => diagnostic.severity === "error") || result.mismatches.length > 0;
250694
+ const hasError = result.diagnostics.some((diagnostic) => diagnostic.severity === "error") || result.mismatches.length > 0 || database?.ok === false;
250473
250695
  if (args.format === "json")
250474
250696
  return textResult(JSON.stringify({
250475
250697
  version: 1,
@@ -250479,12 +250701,14 @@ async function runCheck(args) {
250479
250701
  mismatches: result.mismatches,
250480
250702
  upToDate: result.upToDate,
250481
250703
  written: [],
250482
- modules: result.graph.modules.map((module) => module.name)
250704
+ modules: result.graph.modules.map((module) => module.name),
250705
+ ...database ? { database } : {}
250483
250706
  }, null, 2), hasError);
250484
250707
  const summary = `checked ${result.graph.modules.length} module(s), no files written`;
250485
250708
  return textResult([
250486
250709
  formatDiagnostics(result.diagnostics),
250487
250710
  ...result.mismatches.map((path) => `generated artifact mismatch: ${path}`),
250711
+ ...database ? [`${database.ok ? "OK" : "FAIL"} ${database.name}: ${database.detail}`] : [],
250488
250712
  "",
250489
250713
  summary
250490
250714
  ].join(`
@@ -250492,9 +250716,9 @@ async function runCheck(args) {
250492
250716
  }
250493
250717
  async function readManifest(root, args) {
250494
250718
  const config = await loadSupacloudConfig(root);
250495
- const outDir = args.out_dir ? resolve17(root, args.out_dir) : resolveSupacloudConfig(config, root).outDir;
250496
- const manifestPath = join15(outDir, "app.manifest.json");
250497
- if (!existsSync11(manifestPath)) {
250719
+ const outDir = args.out_dir ? resolve18(root, args.out_dir) : resolveSupacloudConfig(config, root).outDir;
250720
+ const manifestPath = join16(outDir, "app.manifest.json");
250721
+ if (!existsSync12(manifestPath)) {
250498
250722
  throw new Error(`Manifest not found: ${manifestPath}(先运行 app compile 生成)`);
250499
250723
  }
250500
250724
  const parsed = JSON.parse(await readFile8(manifestPath, "utf8"));
@@ -250537,7 +250761,7 @@ function formatGraphText(manifest) {
250537
250761
  `);
250538
250762
  }
250539
250763
  async function runGraph(args) {
250540
- const root = resolve17(args.root || process.cwd());
250764
+ const root = resolve18(args.root || process.cwd());
250541
250765
  const manifest = await readManifest(root, args);
250542
250766
  if (args.format === "json")
250543
250767
  return textResult(JSON.stringify(manifest, null, 2));
@@ -250605,7 +250829,7 @@ async function runExplain(args) {
250605
250829
  const target = args.target?.trim();
250606
250830
  if (!target)
250607
250831
  throw new Error("app explain requires --target(provider 类名 / token 名 / command 名 / job 名)");
250608
- const root = resolve17(args.root || process.cwd());
250832
+ const root = resolve18(args.root || process.cwd());
250609
250833
  const manifest = await readManifest(root, args);
250610
250834
  for (const module of manifest.modules) {
250611
250835
  const job = module.jobs?.find((entry) => entry.name === target || entry.className === target);
@@ -250680,16 +250904,16 @@ async function runExplain(args) {
250680
250904
  return textResult(`未找到对象: ${target}`, true);
250681
250905
  }
250682
250906
  async function runExportTools(args) {
250683
- const root = resolve17(args.root || process.cwd());
250907
+ const root = resolve18(args.root || process.cwd());
250684
250908
  const manifest = await readManifest(root, { ...args, out_dir: undefined });
250685
250909
  const definitions = buildToolDefinitions(manifest);
250686
- const outDir = resolve17(args.out_dir || join15(root, "generated"));
250910
+ const outDir = resolve18(args.out_dir || join16(root, "generated"));
250687
250911
  if (args.format === "json") {
250688
250912
  return textResult(JSON.stringify(definitions, null, 2));
250689
250913
  }
250690
250914
  await mkdir6(outDir, { recursive: true });
250691
- const openaiPath = join15(outDir, "tool-definitions.openai.json");
250692
- const mcpPath = join15(outDir, "tool-definitions.mcp.json");
250915
+ const openaiPath = join16(outDir, "tool-definitions.openai.json");
250916
+ const mcpPath = join16(outDir, "tool-definitions.mcp.json");
250693
250917
  await writeFile5(openaiPath, JSON.stringify(definitions.openai, null, 2), "utf8");
250694
250918
  await writeFile5(mcpPath, JSON.stringify(definitions.mcp, null, 2), "utf8");
250695
250919
  const summary = [
@@ -250704,11 +250928,17 @@ async function runExportTools(args) {
250704
250928
  return textResult(summary);
250705
250929
  }
250706
250930
  async function runDelivery(args) {
250707
- const root = resolve17(args.root || process.cwd());
250931
+ const root = resolve18(args.root || process.cwd());
250932
+ if (args.action === "build") {
250933
+ const database = checkAppDatabaseSources(root);
250934
+ if (database && !database.ok) {
250935
+ return textResult(JSON.stringify({ ok: false, database, written: [] }, null, 2), true);
250936
+ }
250937
+ }
250708
250938
  const loaded = await loadSupacloudConfig(root);
250709
250939
  const options = compileOptionsFromConfig({
250710
250940
  ...loaded,
250711
- ...args.out_dir === undefined ? {} : { outDir: resolve17(root, args.out_dir) },
250941
+ ...args.out_dir === undefined ? {} : { outDir: resolve18(root, args.out_dir) },
250712
250942
  ...args.include === undefined ? {} : { include: parseInclude(args.include) },
250713
250943
  ...args.strict === undefined ? {} : { strict: args.strict }
250714
250944
  }, root);
@@ -250866,8 +251096,8 @@ function registerAppAliases(server2) {
250866
251096
  }
250867
251097
 
250868
251098
  // src/shared/tools/db-governance-tools.ts
250869
- import { existsSync as existsSync12 } from "node:fs";
250870
- import { join as join16, resolve as resolve18 } from "node:path";
251099
+ import { existsSync as existsSync13 } from "node:fs";
251100
+ import { join as join17, resolve as resolve20 } from "node:path";
250871
251101
 
250872
251102
  // node_modules/@supacloud/db/dist/index.js
250873
251103
  var TABLES_SQL = `
@@ -251319,8 +251549,8 @@ function normalizeModule(candidate, sourcePath) {
251319
251549
  };
251320
251550
  }
251321
251551
  async function loadDatabaseModules(root, moduleFile) {
251322
- const filePath = moduleFile ? resolve18(root, moduleFile) : join16(root, "db", "modules.ts");
251323
- if (!existsSync12(filePath)) {
251552
+ const filePath = moduleFile ? resolve20(root, moduleFile) : join17(root, "db", "modules.ts");
251553
+ if (!existsSync13(filePath)) {
251324
251554
  throw new Error(moduleFile ? `Module file not found: ${filePath}` : `Module file not found: ${filePath}(用 --module_file 指定一个导出 defineDatabaseModule(...) 的文件)`);
251325
251555
  }
251326
251556
  let imported;
@@ -251368,7 +251598,7 @@ async function runLint(args, root) {
251368
251598
  const issues = [];
251369
251599
  for (const module of selected) {
251370
251600
  const readSqlFile = async (path) => {
251371
- const absolute = resolve18(root, path);
251601
+ const absolute = resolve20(root, path);
251372
251602
  try {
251373
251603
  return await Bun.file(absolute).text();
251374
251604
  } catch (error) {
@@ -251404,14 +251634,14 @@ var defaultLiteSpawn = async (command, cwd) => {
251404
251634
  return { exitCode, stdout, stderr };
251405
251635
  };
251406
251636
  async function runModuleCheckLite(args, root, spawn, liteBinary) {
251407
- const projectDir = resolve18(args.project_dir?.trim() || root);
251637
+ const projectDir = resolve20(args.project_dir?.trim() || root);
251408
251638
  const binary = liteBinary === undefined ? Bun.which("supacloud-lite") : liteBinary;
251409
251639
  if (!binary) {
251410
251640
  throw new Error("db module_check --lite 需要本机可用的 supacloud-lite(npm i -g @supacloud/lite,或加入 PATH)");
251411
251641
  }
251412
251642
  const command = [binary, "db", "check", "--project-dir", projectDir];
251413
251643
  if (args.module_file?.trim())
251414
- command.push("--module-file", resolve18(root, args.module_file.trim()));
251644
+ command.push("--module-file", resolve20(root, args.module_file.trim()));
251415
251645
  const result = await spawn(command, projectDir);
251416
251646
  const output = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(`
251417
251647
  `);
@@ -251462,7 +251692,7 @@ function registerDbGovernanceTools(server2, options = {}) {
251462
251692
  lite: optional(Type.Boolean(), "[module_check] Reconcile against a local SupaCloud Lite project (runs supacloud-lite db check)"),
251463
251693
  project_dir: optional(Type.String(), "[module_check] Lite project directory (with --lite; default: --root)")
251464
251694
  }, async (request) => {
251465
- const root = resolve18(request.root || fallbackRoot);
251695
+ const root = resolve20(request.root || fallbackRoot);
251466
251696
  switch (request.action) {
251467
251697
  case "lint":
251468
251698
  return runLint(request, root);
@@ -251479,7 +251709,7 @@ function registerDbGovernanceTools(server2, options = {}) {
251479
251709
  // src/shared/tools/scheduled-function-tools.ts
251480
251710
  import { randomUUID as randomUUID3 } from "node:crypto";
251481
251711
  import { readFileSync as readFileSync10, statSync as statSync7 } from "node:fs";
251482
- import { resolve as resolve20 } from "node:path";
251712
+ import { resolve as resolve21 } from "node:path";
251483
251713
  import { isDeepStrictEqual } from "node:util";
251484
251714
  var HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$/;
251485
251715
  var ENVIRONMENT_NAME_PATTERN2 = /^[A-Za-z_][A-Za-z0-9_]{0,255}$/;
@@ -251563,7 +251793,7 @@ function validScheduledFunctionCron(expression) {
251563
251793
  function readScheduleBodyFile(bodyPathInput) {
251564
251794
  if (!bodyPathInput.trim())
251565
251795
  throw new Error("'body_file' must be a path");
251566
- const bodyPath = resolve20(bodyPathInput);
251796
+ const bodyPath = resolve21(bodyPathInput);
251567
251797
  const bodyStat = statSync7(bodyPath);
251568
251798
  if (!bodyStat.isFile() || bodyStat.size > MAX_BODY_FILE_BYTES) {
251569
251799
  throw new Error("Scheduled Function body file must be a regular file no larger than 1 MiB");
@@ -252146,8 +252376,8 @@ var MUTATION_TOOL_SCHEMA = {
252146
252376
  // src/shared/tools/release-tools.ts
252147
252377
  import { execFileSync } from "node:child_process";
252148
252378
  import { createHash as createHash10 } from "node:crypto";
252149
- import { existsSync as existsSync13, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "node:fs";
252150
- import { dirname as dirname13, join as join17, relative as relative13, resolve as resolve21 } from "node:path";
252379
+ import { existsSync as existsSync14, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "node:fs";
252380
+ import { dirname as dirname13, join as join18, relative as relative13, resolve as resolve23 } from "node:path";
252151
252381
  var SAFE_PROJECT_REF = /^[A-Za-z0-9_-]{1,64}$/;
252152
252382
  var BACKUP_ID = /^logical-full_[A-Za-z0-9_-]{1,64}_[a-f0-9]{32}$/;
252153
252383
  var SHA256 = /^[a-f0-9]{64}$/;
@@ -252441,15 +252671,15 @@ function collectScopeFiles(cwd, file, files, dir, task) {
252441
252671
  const results = [];
252442
252672
  const resolvePathWithFallbacks = (filePath) => {
252443
252673
  const trimmed = filePath.trim();
252444
- const resolved = resolve21(cwd, trimmed);
252445
- if (existsSync13(resolved))
252674
+ const resolved = resolve23(cwd, trimmed);
252675
+ if (existsSync14(resolved))
252446
252676
  return resolved;
252447
252677
  const candidates = [
252448
- resolve21(cwd, "supacloud/fa/release-scopes", trimmed),
252449
- resolve21(cwd, "release-scopes", trimmed),
252450
- resolve21(cwd, "scopes", trimmed)
252678
+ resolve23(cwd, "supacloud/fa/release-scopes", trimmed),
252679
+ resolve23(cwd, "release-scopes", trimmed),
252680
+ resolve23(cwd, "scopes", trimmed)
252451
252681
  ];
252452
- const found = candidates.find(existsSync13);
252682
+ const found = candidates.find(existsSync14);
252453
252683
  if (found)
252454
252684
  return found;
252455
252685
  throw new Error(`Scope file not found: ${filePath}`);
@@ -252470,18 +252700,18 @@ function collectScopeFiles(cwd, file, files, dir, task) {
252470
252700
  if (!taskFilter && (!dir || typeof dir !== "string" || !dir.trim())) {
252471
252701
  throw new Error("At least one of --file, --files, or --task is required for scope_rebind");
252472
252702
  }
252473
- const candidates = typeof dir === "string" && dir.trim() ? [resolve21(cwd, dir.trim())] : [
252474
- resolve21(cwd, "supacloud/fa/release-scopes"),
252475
- resolve21(cwd, "release-scopes"),
252476
- resolve21(cwd, "scopes")
252703
+ const candidates = typeof dir === "string" && dir.trim() ? [resolve23(cwd, dir.trim())] : [
252704
+ resolve23(cwd, "supacloud/fa/release-scopes"),
252705
+ resolve23(cwd, "release-scopes"),
252706
+ resolve23(cwd, "scopes")
252477
252707
  ];
252478
252708
  for (const directory of candidates) {
252479
- if (existsSync13(directory)) {
252709
+ if (existsSync14(directory)) {
252480
252710
  try {
252481
252711
  const entries = readdirSync4(directory, { withFileTypes: true });
252482
252712
  for (const entry of entries) {
252483
252713
  if (entry.isFile() && entry.name.endsWith(".json")) {
252484
- const fullPath = join17(directory, entry.name);
252714
+ const fullPath = join18(directory, entry.name);
252485
252715
  if (!taskFilter) {
252486
252716
  results.push(fullPath);
252487
252717
  } else if (entry.name.toLowerCase().includes(taskFilter)) {
@@ -252507,7 +252737,7 @@ function collectScopeFiles(cwd, file, files, dir, task) {
252507
252737
  return [...new Set(results)];
252508
252738
  }
252509
252739
  function handleScopeRebind(args) {
252510
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve21(args.cwd.trim()) : process.cwd();
252740
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
252511
252741
  const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
252512
252742
  const scopeFiles = collectScopeFiles(cwd, args.file, args.files, args.dir, args.task);
252513
252743
  const dryRun = args.dry_run === true;
@@ -252559,19 +252789,19 @@ function handleScopeRebind(args) {
252559
252789
  });
252560
252790
  }
252561
252791
  function handleScopeInspect(args) {
252562
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve21(args.cwd.trim()) : process.cwd();
252792
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
252563
252793
  if (typeof args.file !== "string" || !args.file.trim()) {
252564
252794
  throw new Error("'file' is required for scope_inspect");
252565
252795
  }
252566
252796
  const trimmed = args.file.trim();
252567
- let filePath = resolve21(cwd, trimmed);
252568
- if (!existsSync13(filePath)) {
252797
+ let filePath = resolve23(cwd, trimmed);
252798
+ if (!existsSync14(filePath)) {
252569
252799
  const candidates = [
252570
- resolve21(cwd, "supacloud/fa/release-scopes", trimmed),
252571
- resolve21(cwd, "release-scopes", trimmed),
252572
- resolve21(cwd, "scopes", trimmed)
252800
+ resolve23(cwd, "supacloud/fa/release-scopes", trimmed),
252801
+ resolve23(cwd, "release-scopes", trimmed),
252802
+ resolve23(cwd, "scopes", trimmed)
252573
252803
  ];
252574
- const found = candidates.find(existsSync13);
252804
+ const found = candidates.find(existsSync14);
252575
252805
  if (found)
252576
252806
  filePath = found;
252577
252807
  else
@@ -252629,7 +252859,7 @@ function parseCommaList(value) {
252629
252859
  return [];
252630
252860
  }
252631
252861
  function handleScopeCreate(args, fallbackRef) {
252632
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve21(args.cwd.trim()) : process.cwd();
252862
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
252633
252863
  if (typeof args.file !== "string" || !args.file.trim()) {
252634
252864
  throw new Error("'file' is required for scope_create");
252635
252865
  }
@@ -252644,7 +252874,7 @@ function handleScopeCreate(args, fallbackRef) {
252644
252874
  throw new Error("'ref' is invalid for release controls");
252645
252875
  }
252646
252876
  const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
252647
- const filePath = resolve21(cwd, args.file.trim());
252877
+ const filePath = resolve23(cwd, args.file.trim());
252648
252878
  mkdirSync4(dirname13(filePath), { recursive: true });
252649
252879
  const scope = {
252650
252880
  baseCommit: targetBaseCommit,
@@ -252869,7 +253099,7 @@ function registerReleaseTools(server2, http, options = {}) {
252869
253099
  import { access as access4, lstat as lstat5, mkdtemp as mkdtemp2, opendir, readFile as readFile9, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
252870
253100
  import { createHash as createHash11 } from "node:crypto";
252871
253101
  import { tmpdir as tmpdir2 } from "node:os";
252872
- import { basename as basename9, dirname as dirname14, join as join18, relative as relative14, resolve as resolve23, sep as sep12 } from "node:path";
253102
+ import { basename as basename9, dirname as dirname14, join as join19, relative as relative14, resolve as resolve24, sep as sep12 } from "node:path";
252873
253103
  import { spawn as spawn3 } from "node:child_process";
252874
253104
 
252875
253105
  // node_modules/fflate/esm/index.mjs
@@ -253561,13 +253791,13 @@ async function readJson(path) {
253561
253791
  }
253562
253792
  }
253563
253793
  async function findDeployConfigRoot(startDirectory) {
253564
- let directory = resolve23(startDirectory);
253794
+ let directory = resolve24(startDirectory);
253565
253795
  while (true) {
253566
- if (await pathExists(join18(directory, "supacloud.json")))
253796
+ if (await pathExists(join19(directory, "supacloud.json")))
253567
253797
  return directory;
253568
253798
  const parent = dirname14(directory);
253569
253799
  if (parent === directory)
253570
- return resolve23(startDirectory);
253800
+ return resolve24(startDirectory);
253571
253801
  directory = parent;
253572
253802
  }
253573
253803
  }
@@ -253610,7 +253840,7 @@ function deployTargetConfig(candidate, name) {
253610
253840
  };
253611
253841
  }
253612
253842
  async function readDeployConfig(configRoot) {
253613
- const configPath = join18(configRoot, "supacloud.json");
253843
+ const configPath = join19(configRoot, "supacloud.json");
253614
253844
  const candidate = await readJson(configPath);
253615
253845
  if (candidate === null)
253616
253846
  return {};
@@ -253632,25 +253862,25 @@ async function readDeployConfig(configRoot) {
253632
253862
  };
253633
253863
  }
253634
253864
  async function packageName(projectDirectory) {
253635
- const candidate = record4(await readJson(join18(projectDirectory, "package.json")));
253865
+ const candidate = record4(await readJson(join19(projectDirectory, "package.json")));
253636
253866
  return typeof candidate?.name === "string" && candidate.name.trim() ? candidate.name.trim() : null;
253637
253867
  }
253638
253868
  async function pathExists(path) {
253639
253869
  return access4(path).then(() => true, () => false);
253640
253870
  }
253641
253871
  async function defaultBuildCommand(projectDirectory, configRoot) {
253642
- const packageJson = record4(await readJson(join18(projectDirectory, "package.json")));
253872
+ const packageJson = record4(await readJson(join19(projectDirectory, "package.json")));
253643
253873
  const scripts = record4(packageJson?.scripts);
253644
253874
  if (typeof scripts?.build !== "string" || !scripts.build.trim()) {
253645
253875
  throw new Error("No build command was configured and package.json has no build script");
253646
253876
  }
253647
253877
  let directory = projectDirectory;
253648
253878
  while (true) {
253649
- if (await pathExists(join18(directory, "bun.lock")) || await pathExists(join18(directory, "bun.lockb")))
253879
+ if (await pathExists(join19(directory, "bun.lock")) || await pathExists(join19(directory, "bun.lockb")))
253650
253880
  return "bun run build";
253651
- if (await pathExists(join18(directory, "pnpm-lock.yaml")))
253881
+ if (await pathExists(join19(directory, "pnpm-lock.yaml")))
253652
253882
  return "pnpm run build";
253653
- if (await pathExists(join18(directory, "yarn.lock")))
253883
+ if (await pathExists(join19(directory, "yarn.lock")))
253654
253884
  return "yarn build";
253655
253885
  if (directory === configRoot)
253656
253886
  break;
@@ -253685,9 +253915,9 @@ function selectDeployment(deployments, requestedId, projectName) {
253685
253915
  throw new Error(deployments.length === 0 ? "No frontend deployments exist for this project" : `Multiple frontend deployments found (${ids}). Set frontend.id in supacloud.json or pass --id`);
253686
253916
  }
253687
253917
  function targetRoot(configRoot, target, name) {
253688
- const root = resolve23(configRoot, target.root || (name === "frontend" ? "." : name));
253689
- const prefix = `${resolve23(configRoot)}${sep12}`;
253690
- if (root !== resolve23(configRoot) && !root.startsWith(prefix)) {
253918
+ const root = resolve24(configRoot, target.root || (name === "frontend" ? "." : name));
253919
+ const prefix = `${resolve24(configRoot)}${sep12}`;
253920
+ if (root !== resolve24(configRoot) && !root.startsWith(prefix)) {
253691
253921
  throw new Error(`Deploy target '${name}' root must stay inside the repository root`);
253692
253922
  }
253693
253923
  return root;
@@ -253738,8 +253968,8 @@ function defaultOutputDirectory(framework) {
253738
253968
  }
253739
253969
  }
253740
253970
  function resolveInsideProject(projectDirectory, candidate, allowRoot = false) {
253741
- const resolved = resolve23(projectDirectory, candidate);
253742
- const projectRoot = resolve23(projectDirectory);
253971
+ const resolved = resolve24(projectDirectory, candidate);
253972
+ const projectRoot = resolve24(projectDirectory);
253743
253973
  const projectPrefix = `${projectRoot}${sep12}`;
253744
253974
  if (!allowRoot && resolved === projectRoot || resolved !== projectRoot && !resolved.startsWith(projectPrefix)) {
253745
253975
  throw new Error("Frontend output directory must stay inside the project directory");
@@ -253770,7 +254000,7 @@ async function collectArchiveFiles(root) {
253770
254000
  entries.push(entry);
253771
254001
  entries.sort((left, right) => left.name.localeCompare(right.name, "en"));
253772
254002
  for (const entry of entries) {
253773
- const path = join18(directory, entry.name);
254003
+ const path = join19(directory, entry.name);
253774
254004
  const stats = await lstat5(path);
253775
254005
  if (stats.isSymbolicLink())
253776
254006
  throw new Error(`Frontend output cannot contain symbolic links: ${path}`);
@@ -253799,8 +254029,8 @@ async function collectArchiveFiles(root) {
253799
254029
  }
253800
254030
  async function createFrontendArchive(outputDirectory) {
253801
254031
  const collected = await collectArchiveFiles(outputDirectory);
253802
- const temporaryDirectory = await mkdtemp2(join18(tmpdir2(), "supacloud-deploy-"));
253803
- const archivePath = join18(temporaryDirectory, `${basename9(outputDirectory)}.zip`);
254032
+ const temporaryDirectory = await mkdtemp2(join19(tmpdir2(), "supacloud-deploy-"));
254033
+ const archivePath = join19(temporaryDirectory, `${basename9(outputDirectory)}.zip`);
253804
254034
  try {
253805
254035
  const archiveBytes = zipSync(collected.files, { level: 6, mtime: FIXED_ZIP_MTIME });
253806
254036
  await writeFile6(archivePath, archiveBytes);
@@ -253850,7 +254080,7 @@ function deployResponse(result, json) {
253850
254080
  }
253851
254081
  function registerDeployTools(server2, http, options = {}) {
253852
254082
  server2.tool("deploy", "Build and publish the linked frontend with one command", deployToolSchema, async (args) => {
253853
- const invocationDirectory = resolve23(String(args.cwd || options.cwd || process.cwd()));
254083
+ const invocationDirectory = resolve24(String(args.cwd || options.cwd || process.cwd()));
253854
254084
  const projectRef = String(args.ref || options.projectRef || "").trim();
253855
254085
  if (!projectRef)
253856
254086
  throw new Error("A linked project ref is required. Set SUPACLOUD_PROJECT_REF or pass --ref");
@@ -254023,11 +254253,11 @@ function registerDeployTools(server2, http, options = {}) {
254023
254253
 
254024
254254
  // src/shared/tools/remote-dev-tools.ts
254025
254255
  import { spawn as spawn4 } from "node:child_process";
254026
- import { existsSync as existsSync14 } from "node:fs";
254256
+ import { existsSync as existsSync15 } from "node:fs";
254027
254257
  import { readFile as readFile10 } from "node:fs/promises";
254028
254258
  import { readdir as readdir6 } from "node:fs/promises";
254029
254259
  import { createHash as createHash12 } from "node:crypto";
254030
- import { join as join19, resolve as resolve24 } from "node:path";
254260
+ import { join as join20, resolve as resolve25 } from "node:path";
254031
254261
  var SAFE_TOKEN = /^[A-Za-z0-9._:@/+,-]+$/;
254032
254262
  var SAFE_REMOTE_ROOT = /^\/(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+\/?$/;
254033
254263
  var remoteDevToolSchema = {
@@ -254069,21 +254299,21 @@ function runProcess(executable, args, cwd) {
254069
254299
  function resolveDrizzleCommand(root, configured) {
254070
254300
  if (configured?.trim())
254071
254301
  return configured.trim();
254072
- const local = join19(root, "node_modules", ".bin", "drizzle-kit");
254073
- return existsSync14(local) ? local : "drizzle-kit";
254302
+ const local = join20(root, "node_modules", ".bin", "drizzle-kit");
254303
+ return existsSync15(local) ? local : "drizzle-kit";
254074
254304
  }
254075
254305
  function toolFailed(value) {
254076
254306
  return value?.isError === true || value?.content?.some((chunk) => typeof chunk?.text === "string" && chunk.text.trimStart().startsWith("❌"));
254077
254307
  }
254078
254308
  async function migrateDatabase(args, options) {
254079
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
254309
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254080
254310
  const projectConfig = await readProjectConfig3(root);
254081
254311
  const config = projectConfig.dev || {};
254082
254312
  const database = config.database || {};
254083
254313
  const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
254084
- const drizzleConfig = resolve24(root, String(args.drizzle_config || database.drizzleConfig || "drizzle.config.ts"));
254314
+ const drizzleConfig = resolve25(root, String(args.drizzle_config || database.drizzleConfig || "drizzle.config.ts"));
254085
254315
  const migrationsDir = String(args.migrations_dir || database.migrationsDir || "supabase/migrations");
254086
- if (!existsSync14(drizzleConfig))
254316
+ if (!existsSync15(drizzleConfig))
254087
254317
  throw new Error(`Drizzle config not found: ${drizzleConfig}`);
254088
254318
  const generated = await execute(resolveDrizzleCommand(root, typeof args.drizzle_bin === "string" ? args.drizzle_bin : database.drizzleBin), ["generate", "--config", drizzleConfig], root);
254089
254319
  if (generated.exitCode !== 0)
@@ -254101,8 +254331,8 @@ async function migrateDatabase(args, options) {
254101
254331
  return { ok: true, mode: "dev", action: "migrate", generated: true, applied: true, migrations_dir: migrationsDir, result: applied };
254102
254332
  }
254103
254333
  async function readProjectConfig3(root) {
254104
- const file = join19(root, "supacloud.json");
254105
- if (!existsSync14(file))
254334
+ const file = join20(root, "supacloud.json");
254335
+ if (!existsSync15(file))
254106
254336
  return {};
254107
254337
  try {
254108
254338
  const parsed = JSON.parse(await readFile10(file, "utf8"));
@@ -254120,7 +254350,7 @@ async function sourceFingerprint(root) {
254120
254350
  const visit = async (directory) => {
254121
254351
  const entries = await readdir6(directory, { withFileTypes: true });
254122
254352
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
254123
- const path = join19(directory, entry.name);
254353
+ const path = join20(directory, entry.name);
254124
254354
  if (entry.isDirectory() && ![".git", "node_modules", "dist", "generated", ".supacloud"].includes(entry.name))
254125
254355
  await visit(path);
254126
254356
  else if (entry.isFile())
@@ -254148,17 +254378,17 @@ function remoteRoot(value) {
254148
254378
  }
254149
254379
  function targetDirectory(root, target, functionSlug, config = {}) {
254150
254380
  if (target === "db")
254151
- return join19(root, "supabase", "migrations");
254381
+ return join20(root, "supabase", "migrations");
254152
254382
  if (target === "functions") {
254153
254383
  const targets = config.targets && typeof config.targets === "object" ? config.targets : {};
254154
254384
  const match = Object.values(targets).find((entry) => entry?.type === "edge_function" && (!functionSlug || String(entry.slug || "") === functionSlug));
254155
- const base = match?.root ? resolve24(root, String(match.root)) : join19(root, "supabase", "functions");
254156
- return match?.root ? base : functionSlug ? join19(base, safeToken(functionSlug, "function")) : base;
254385
+ const base = match?.root ? resolve25(root, String(match.root)) : join20(root, "supabase", "functions");
254386
+ return match?.root ? base : functionSlug ? join20(base, safeToken(functionSlug, "function")) : base;
254157
254387
  }
254158
254388
  if (target === "frontend") {
254159
254389
  const targets = config.targets && typeof config.targets === "object" ? config.targets : {};
254160
254390
  const match = Object.values(targets).find((entry) => entry?.type === "frontend");
254161
- return match?.root ? resolve24(root, String(match.root)) : join19(root, "apps", "web");
254391
+ return match?.root ? resolve25(root, String(match.root)) : join20(root, "apps", "web");
254162
254392
  }
254163
254393
  return root;
254164
254394
  }
@@ -254197,10 +254427,10 @@ function reloadCommand(config, target, projectRef, functionSlug) {
254197
254427
  return [...command.split(" "), "--project-ref", safeToken(projectRef || "test", "project_ref"), "--target", targetConfigPath(target), ...functionSlug ? ["--function", safeToken(functionSlug, "function")] : []];
254198
254428
  }
254199
254429
  function sshArgs(connection, remoteCommand) {
254200
- return ["-p", String(connection.port), "-i", resolve24(connection.key), "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", `${connection.user}@${connection.host}`, ...remoteCommand];
254430
+ return ["-p", String(connection.port), "-i", resolve25(connection.key), "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", `${connection.user}@${connection.host}`, ...remoteCommand];
254201
254431
  }
254202
254432
  function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
254203
- const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${resolve24(connection.key)} -o BatchMode=yes -o StrictHostKeyChecking=yes`];
254433
+ const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${resolve25(connection.key)} -o BatchMode=yes -o StrictHostKeyChecking=yes`];
254204
254434
  if (deleteRemote)
254205
254435
  args.push("--delete-delay");
254206
254436
  for (const exclude of excludes) {
@@ -254212,17 +254442,17 @@ function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
254212
254442
  return args;
254213
254443
  }
254214
254444
  async function syncOnce(args, options) {
254215
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
254445
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254216
254446
  const projectConfig = await readProjectConfig3(root);
254217
254447
  const config = projectConfig.dev || {};
254218
254448
  const target = String(args.target || "project");
254219
254449
  const source = targetDirectory(root, target, typeof args.function === "string" ? args.function : undefined, projectConfig);
254220
- if (!existsSync14(source))
254450
+ if (!existsSync15(source))
254221
254451
  throw new Error(`Dev source directory not found: ${source}`);
254222
254452
  let compiled = false;
254223
254453
  if (config.compile === true && target !== "db") {
254224
- const compileRoot = resolve24(root, config.compileRoot || ".");
254225
- const compileOutDir = resolve24(root, config.compileOutDir || "generated");
254454
+ const compileRoot = resolve25(root, config.compileRoot || ".");
254455
+ const compileOutDir = resolve25(root, config.compileOutDir || "generated");
254226
254456
  const compilation = await compileProject({
254227
254457
  rootDir: compileRoot,
254228
254458
  outDir: compileOutDir,
@@ -254260,7 +254490,7 @@ function registerRemoteDevTools(server2, options = {}) {
254260
254490
  if (["production", "prod"].includes((options.environment || "").toLowerCase()))
254261
254491
  throw new Error("Remote dev mode is forbidden for production environments");
254262
254492
  if (args.action === "status") {
254263
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
254493
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254264
254494
  const config = await readDevConfig(root);
254265
254495
  const connection = connectionArgs(options, config, args);
254266
254496
  const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
@@ -254274,7 +254504,7 @@ function registerRemoteDevTools(server2, options = {}) {
254274
254504
  return { content: [{ type: "text", text: JSON.stringify(await migrateDatabase(args, options), null, 2) }] };
254275
254505
  }
254276
254506
  if (args.action === "watch") {
254277
- const root = resolve24(String(args.project_dir || options.cwd || process.cwd()));
254507
+ const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254278
254508
  const interval = Math.max(100, Math.min(1e4, Number(args.interval_ms || 300)));
254279
254509
  let fingerprint = "";
254280
254510
  let lastSync = null;
@@ -254295,7 +254525,7 @@ function registerRemoteDevTools(server2, options = {}) {
254295
254525
  // package.json
254296
254526
  var package_default8 = {
254297
254527
  name: "@supacloud/cli",
254298
- version: "0.62.1",
254528
+ version: "0.63.0",
254299
254529
  description: "Project-scoped CLI for SupaCloud users",
254300
254530
  type: "module",
254301
254531
  main: "./dist/index.js",
@@ -254330,7 +254560,7 @@ var package_default8 = {
254330
254560
  },
254331
254561
  dependencies: {
254332
254562
  "@sinclair/typebox": "^0.34.52",
254333
- "@supacloud/compiler": "^0.31.0",
254563
+ "@supacloud/compiler": "^0.31.1",
254334
254564
  "@supacloud/delivery": "0.4.0",
254335
254565
  "@supacloud/db": "^0.2.0",
254336
254566
  fflate: "^0.8.3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/cli",
3
- "version": "0.62.1",
3
+ "version": "0.63.0",
4
4
  "description": "Project-scoped CLI for SupaCloud users",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@sinclair/typebox": "^0.34.52",
38
- "@supacloud/compiler": "^0.31.0",
38
+ "@supacloud/compiler": "^0.31.1",
39
39
  "@supacloud/delivery": "0.4.0",
40
40
  "@supacloud/db": "^0.2.0",
41
41
  "fflate": "^0.8.3",