@supacloud/compiler 0.44.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4095,7 +4095,7 @@ var init_graphql_options = __esm(() => {
4095
4095
  });
4096
4096
 
4097
4097
  // src/graphql-inputs.ts
4098
- import { resolve as resolve5 } from "node:path";
4098
+ import { resolve as resolve6 } from "node:path";
4099
4099
  import * as ts11 from "@typescript/typescript6";
4100
4100
  function graphqlInputPaths(options) {
4101
4101
  if (!options.graphql)
@@ -4105,9 +4105,9 @@ function graphqlInputPaths(options) {
4105
4105
  } catch {
4106
4106
  return [];
4107
4107
  }
4108
- const root = resolve5(options.rootDir);
4109
- const schema = resolve5(root, options.graphql.schema);
4110
- const documents = ts11.sys.readDirectory(root, [".graphql", ".gql"], ["**/node_modules/**", "**/.git/**", resolve5(options.outDir)], options.graphql.documents ?? ["**/*.graphql", "**/*.gql"]).map((path) => resolve5(path)).filter((path) => path !== schema);
4108
+ const root = resolve6(options.rootDir);
4109
+ const schema = resolve6(root, options.graphql.schema);
4110
+ const documents = ts11.sys.readDirectory(root, [".graphql", ".gql"], ["**/node_modules/**", "**/.git/**", resolve6(options.outDir)], options.graphql.documents ?? ["**/*.graphql", "**/*.gql"]).map((path) => resolve6(path)).filter((path) => path !== schema);
4111
4111
  return [schema, ...[...new Set(documents)].sort()];
4112
4112
  }
4113
4113
  var init_graphql_inputs = __esm(() => {
@@ -4116,9 +4116,9 @@ var init_graphql_inputs = __esm(() => {
4116
4116
 
4117
4117
  // src/graphql-runtime.ts
4118
4118
  import * as ts12 from "@typescript/typescript6";
4119
- import { resolve as resolve6 } from "node:path";
4119
+ import { resolve as resolve7 } from "node:path";
4120
4120
  function renderGraphqlValidators(source, operationNames, operationKinds = new Map) {
4121
- const fileName = resolve6("/__supacloud_graphql__/contracts.ts");
4121
+ const fileName = resolve7("/__supacloud_graphql__/contracts.ts");
4122
4122
  const options = {
4123
4123
  strict: true,
4124
4124
  noUncheckedIndexedAccess: true,
@@ -4134,7 +4134,7 @@ function renderGraphqlValidators(source, operationNames, operationKinds = new Ma
4134
4134
  };
4135
4135
  const host = ts12.createCompilerHost(options);
4136
4136
  const getSourceFile = host.getSourceFile.bind(host);
4137
- host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => resolve6(path) === fileName ? ts12.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
4137
+ host.getSourceFile = (path, languageVersion, onError, shouldCreateNewSourceFile) => resolve7(path) === fileName ? ts12.createSourceFile(path, source, languageVersion, true) : getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile);
4138
4138
  const program = ts12.createProgram([fileName], options, host);
4139
4139
  const diagnostics = ts12.getPreEmitDiagnostics(program);
4140
4140
  if (diagnostics.length) {
@@ -12868,7 +12868,7 @@ function FromObject10(context, type, value) {
12868
12868
  return value;
12869
12869
  const additionalProperties = GetAdditionalProperties(type);
12870
12870
  for (const key of Keys(value)) {
12871
- if (HasPropertyKey(type.properties, key)) {
12871
+ if (HasPropertyKey(type.properties, key) && IsSchema(type.properties[key])) {
12872
12872
  value[key] = FromType19(context, type.properties[key], value[key]);
12873
12873
  continue;
12874
12874
  }
@@ -13000,6 +13000,9 @@ function FromProperties4(properties) {
13000
13000
  result[key] = FromType20(properties[key]);
13001
13001
  return result;
13002
13002
  }
13003
+ function FromRecordKey(type) {
13004
+ return String2({ pattern: RecordPattern(type) });
13005
+ }
13003
13006
  function FromPriorityTypes(types) {
13004
13007
  return FromTypes6(Priority(types));
13005
13008
  }
@@ -13007,7 +13010,7 @@ function FromTypes6(types) {
13007
13010
  return types.map((type) => FromType20(type));
13008
13011
  }
13009
13012
  function FromType20(type) {
13010
- const next = IsArray2(type) ? _Array_(FromType20(type.items), ArrayOptions(type)) : IsIntersect(type) ? Intersect(FromTypes6(type.allOf)) : IsUnion(type) ? Union(FromPriorityTypes(type.anyOf)) : IsObject2(type) ? _Object_(FromProperties4(type.properties)) : IsRecord(type) ? Record(RecordKey(type), FromType20(RecordValue(type))) : IsTuple(type) ? Tuple(FromTypes6(type.items)) : type;
13013
+ const next = IsArray2(type) ? _Array_(FromType20(type.items), ArrayOptions(type)) : IsIntersect(type) ? Intersect(FromTypes6(type.allOf)) : IsUnion(type) ? Union(FromPriorityTypes(type.anyOf)) : IsObject2(type) ? _Object_(FromProperties4(type.properties)) : IsRecord(type) ? Record(FromRecordKey(type), FromType20(RecordValue(type))) : IsTuple(type) ? Tuple(FromTypes6(type.items)) : type;
13011
13014
  return Modifiers(type, next);
13012
13015
  }
13013
13016
  function UnionPrioritySort(type) {
@@ -13023,6 +13026,7 @@ var init_union_priority_sort = __esm(() => {
13023
13026
  init_type3();
13024
13027
  init_type3();
13025
13028
  init_type3();
13029
+ init_type3();
13026
13030
  });
13027
13031
 
13028
13032
  // node_modules/typebox/build/value/clean/clean.mjs
@@ -14712,7 +14716,7 @@ var init_delivery_schema = __esm(() => {
14712
14716
  import { createHash as createHash8 } from "node:crypto";
14713
14717
  import { constants } from "node:fs";
14714
14718
  import { lstat, mkdir as mkdir2, open, readFile as readFile3, readdir, realpath, rename as rename2, rm, writeFile as writeFile2 } from "node:fs/promises";
14715
- import { dirname as dirname4, isAbsolute, join as join5, relative as relative5, resolve as resolve8, sep as sep5 } from "node:path";
14719
+ import { dirname as dirname4, isAbsolute, join as join5, relative as relative5, resolve as resolve9, sep as sep5 } from "node:path";
14716
14720
  function canonical2(value) {
14717
14721
  return JSON.stringify(value, (_key, item) => item !== null && typeof item === "object" && !Array.isArray(item) ? Object.fromEntries(Object.entries(item).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) : item);
14718
14722
  }
@@ -14775,7 +14779,7 @@ async function reserveOutput(project, requested) {
14775
14779
  if (!inside(project, requested))
14776
14780
  throw new Error("Delivery output must be inside the application project.");
14777
14781
  const base = await realpath(project);
14778
- const path = resolve8(base, relative5(project, requested));
14782
+ const path = resolve9(base, relative5(project, requested));
14779
14783
  if (relative5(base, path).split(sep5).some((part) => part === ".git" || part === "node_modules")) {
14780
14784
  throw new Error("Delivery output cannot use repository or dependency internals.");
14781
14785
  }
@@ -15864,9 +15868,9 @@ var init_delivery_files2 = __esm(() => {
15864
15868
 
15865
15869
  // node_modules/@supacloud/delivery/src/delivery-artifact.ts
15866
15870
  import { readdir as readdir2, realpath as realpath2 } from "node:fs/promises";
15867
- import { basename, dirname as dirname6, join as join8, resolve as resolve10 } from "node:path";
15871
+ import { basename, dirname as dirname6, join as join8, resolve as resolve11 } from "node:path";
15868
15872
  async function readDeliveryManifest(manifestPath) {
15869
- const selected = resolve10(manifestPath);
15873
+ const selected = resolve11(manifestPath);
15870
15874
  const root = await realpath2(dirname6(selected));
15871
15875
  const manifest = parseDeliveryBuildManifest(JSON.parse((await readBoundedOwned(root, join8(root, basename(selected)), JSON_LIMIT)).toString("utf8")));
15872
15876
  return { root, manifest };
@@ -16105,37 +16109,67 @@ var init_application_deploy_plan = __esm(() => {
16105
16109
  }, { additionalProperties: false });
16106
16110
  });
16107
16111
 
16108
- // node_modules/@supacloud/delivery/src/application-release-operation.ts
16109
- var closed6, nullableActivation, ApplicationReleaseRequestSchema, ApplicationReleaseResultSchema;
16110
- var init_application_release_operation = __esm(() => {
16112
+ // node_modules/@supacloud/delivery/src/application-deploy-operation.ts
16113
+ var closed6, sha256, nullableActivation, ApplicationDeployWebReleaseSchema, ApplicationDeployRequestSchema, ApplicationBackendReceiptSchema, ApplicationDeployResultSchema;
16114
+ var init_application_deploy_operation = __esm(() => {
16111
16115
  init_build();
16112
16116
  init_value2();
16113
16117
  init_application_activation();
16114
16118
  init_application_configuration();
16115
16119
  init_application_release();
16116
16120
  closed6 = { additionalProperties: false };
16121
+ sha256 = ApplicationReleaseIdSchema;
16117
16122
  nullableActivation = Union([ApplicationActivationIdSchema, Null()]);
16118
- ApplicationReleaseRequestSchema = _Object_({
16119
- release_id: ApplicationReleaseIdSchema,
16123
+ ApplicationDeployWebReleaseSchema = _Object_({
16124
+ deployment_id: String2({ pattern: "^[A-Za-z0-9_-]{1,128}$" }),
16125
+ release_id: sha256
16126
+ }, closed6);
16127
+ ApplicationDeployRequestSchema = _Object_({
16128
+ mutation_id: ApplicationActivationIdSchema,
16129
+ release_id: sha256,
16120
16130
  configuration_id: Optional(ApplicationConfigurationIdSchema),
16121
16131
  configuration_write: Optional(ApplicationConfigurationWriteSchema),
16122
- activation_id: Optional(ApplicationActivationIdSchema),
16123
- expected_activation_id: Optional(nullableActivation),
16124
- expected_plan_sha256: Optional(ApplicationReleaseIdSchema)
16132
+ expected_plan_sha256: Optional(sha256),
16133
+ approved_migration_digest: Optional(sha256),
16134
+ web_release: Optional(ApplicationDeployWebReleaseSchema)
16125
16135
  }, closed6);
16126
- ApplicationReleaseResultSchema = _Object_({
16127
- schema: Literal("supacloud.application-release.v1"),
16136
+ ApplicationBackendReceiptSchema = _Object_({
16137
+ schema: Literal("supacloud.application-backend-receipt.v1"),
16128
16138
  project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
16129
16139
  application_id: ApplicationIdSchema,
16130
16140
  environment_id: ApplicationIdSchema,
16131
- release_id: ApplicationReleaseIdSchema,
16141
+ release_id: sha256,
16142
+ manifest_sha256: sha256,
16143
+ mutation_id: ApplicationActivationIdSchema,
16144
+ plan_sha256: sha256,
16145
+ backup_id: Union([String2(), Null()]),
16146
+ before_ledger_digest: sha256,
16147
+ after_ledger_digest: sha256,
16148
+ applied_versions: _Array_(String2({ pattern: "^\\d{1,20}$" }), { uniqueItems: true }),
16149
+ schema_reloaded: Boolean2(),
16150
+ postgrest_healthy: Boolean2()
16151
+ }, closed6);
16152
+ ApplicationDeployResultSchema = _Object_({
16153
+ schema: Literal("supacloud.application-deploy.v1"),
16154
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
16155
+ application_id: ApplicationIdSchema,
16156
+ environment_id: ApplicationIdSchema,
16157
+ mutation_id: ApplicationActivationIdSchema,
16158
+ release_id: sha256,
16132
16159
  configuration_id: ApplicationConfigurationIdSchema,
16133
16160
  activation_id: ApplicationActivationIdSchema,
16134
16161
  expected_activation_id: nullableActivation,
16135
- plan_sha256: ApplicationReleaseIdSchema,
16162
+ plan_sha256: sha256,
16136
16163
  action: Union([Literal("activate"), Literal("no-op")]),
16137
16164
  replayed: Boolean2(),
16138
- execution_performed: Boolean2()
16165
+ execution_performed: Boolean2(),
16166
+ backend_receipt: ApplicationBackendReceiptSchema,
16167
+ web: Optional(_Object_({
16168
+ deployment_id: String2({ pattern: "^[A-Za-z0-9_-]{1,128}$" }),
16169
+ release_id: sha256,
16170
+ activation_id: ApplicationActivationIdSchema,
16171
+ replayed: Boolean2()
16172
+ }, closed6))
16139
16173
  }, closed6);
16140
16174
  });
16141
16175
 
@@ -16291,14 +16325,14 @@ var init_application_release_transfer = __esm(() => {
16291
16325
  });
16292
16326
 
16293
16327
  // node_modules/@supacloud/delivery/src/deployment-evidence.ts
16294
- var closed8, sha256, isoDate, status, evidenceStatus, DEPLOYMENT_EVIDENCE_SCHEMA = "supacloud.deployment-evidence.v1", DatabaseProviderSchema, componentName, DeploymentComponentEvidenceSchema, DeploymentEvidenceSchema;
16328
+ var closed8, sha2562, isoDate, status, evidenceStatus, DEPLOYMENT_EVIDENCE_SCHEMA = "supacloud.deployment-evidence.v1", DatabaseProviderSchema, componentName, DeploymentComponentEvidenceSchema, DeploymentEvidenceSchema;
16295
16329
  var init_deployment_evidence = __esm(() => {
16296
16330
  init_build();
16297
16331
  init_value2();
16298
16332
  init_application_configuration();
16299
16333
  init_application_release();
16300
16334
  closed8 = { additionalProperties: false };
16301
- sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
16335
+ sha2562 = String2({ pattern: "^[a-f0-9]{64}$" });
16302
16336
  isoDate = String2({ minLength: 20, maxLength: 40 });
16303
16337
  status = Union([
16304
16338
  Literal("confirmed"),
@@ -16317,7 +16351,7 @@ var init_deployment_evidence = __esm(() => {
16317
16351
  topology: Union([Literal("single-node"), Literal("distributed")]),
16318
16352
  migration: _Object_({
16319
16353
  status,
16320
- inventory_sha256: Union([sha256, Null()]),
16354
+ inventory_sha256: Union([sha2562, Null()]),
16321
16355
  compatibility: Union([
16322
16356
  Literal("verified"),
16323
16357
  Literal("not-proven"),
@@ -16365,9 +16399,9 @@ var init_deployment_evidence = __esm(() => {
16365
16399
  }, closed8),
16366
16400
  source: _Object_({
16367
16401
  commit_sha: Union([String2({ pattern: "^[0-9a-f]{7,64}$" }), Null()]),
16368
- manifest_sha256: sha256,
16402
+ manifest_sha256: sha2562,
16369
16403
  contract_schema: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
16370
- environment_binding_version: Union([sha256, Null()])
16404
+ environment_binding_version: Union([sha2562, Null()])
16371
16405
  }, closed8),
16372
16406
  database: DatabaseProviderSchema,
16373
16407
  components: _Array_(DeploymentComponentEvidenceSchema, { minItems: 1, maxItems: 32 }),
@@ -16392,7 +16426,7 @@ var init_deployment_evidence = __esm(() => {
16392
16426
  });
16393
16427
 
16394
16428
  // node_modules/@supacloud/delivery/src/application-promotion.ts
16395
- var closed9, projectRef2, sha2562, nullableActivation2, nullableDigest, observation, blocker, ApplicationPromotionPlanSchema;
16429
+ var closed9, projectRef2, sha2563, nullableActivation2, nullableDigest, observation, blocker, ApplicationPromotionPlanSchema;
16396
16430
  var init_application_promotion = __esm(() => {
16397
16431
  init_build();
16398
16432
  init_value2();
@@ -16402,9 +16436,9 @@ var init_application_promotion = __esm(() => {
16402
16436
  init_application_release();
16403
16437
  closed9 = { additionalProperties: false };
16404
16438
  projectRef2 = String2({ pattern: "^[a-z0-9-]{1,20}$" });
16405
- sha2562 = ApplicationReleaseIdSchema;
16439
+ sha2563 = ApplicationReleaseIdSchema;
16406
16440
  nullableActivation2 = Union([ApplicationActivationIdSchema, Null()]);
16407
- nullableDigest = Union([sha2562, Null()]);
16441
+ nullableDigest = Union([sha2563, Null()]);
16408
16442
  observation = {
16409
16443
  activation_id: nullableActivation2,
16410
16444
  receipt_confirmed: Boolean2(),
@@ -16430,24 +16464,24 @@ var init_application_promotion = __esm(() => {
16430
16464
  project_ref: projectRef2,
16431
16465
  application_id: ApplicationIdSchema,
16432
16466
  environment_id: ApplicationIdSchema,
16433
- manifest_sha256: sha2562,
16434
- plan_sha256: sha2562,
16467
+ manifest_sha256: sha2563,
16468
+ plan_sha256: sha2563,
16435
16469
  source: _Object_({
16436
16470
  project_ref: projectRef2,
16437
16471
  environment_id: ApplicationIdSchema,
16438
- release_id: sha2562,
16472
+ release_id: sha2563,
16439
16473
  ...observation
16440
16474
  }, closed9),
16441
16475
  target: _Object_({
16442
- candidate_release_id: sha2562,
16443
- current_release_id: Union([sha2562, Null()]),
16476
+ candidate_release_id: sha2563,
16477
+ current_release_id: Union([sha2563, Null()]),
16444
16478
  artifact_action: Union([Literal("materialize"), Literal("reuse")]),
16445
16479
  configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
16446
16480
  configuration: Union([ApplicationConfigurationViewSchema, Null()]),
16447
16481
  ...observation
16448
16482
  }, closed9),
16449
16483
  migrations: _Object_({
16450
- ledger_digest: sha2562,
16484
+ ledger_digest: sha2563,
16451
16485
  ledger_compatible: Boolean2(),
16452
16486
  project_migrations_applied: Boolean2(),
16453
16487
  pending_versions: _Array_(String2({ pattern: "^\\d{1,20}$" }), { maxItems: 4096, uniqueItems: true }),
@@ -16590,7 +16624,7 @@ var init_src = __esm(() => {
16590
16624
  init_worker_execution();
16591
16625
  init_application_activation();
16592
16626
  init_application_deploy_plan();
16593
- init_application_release_operation();
16627
+ init_application_deploy_operation();
16594
16628
  init_application_history();
16595
16629
  init_application_release();
16596
16630
  init_application_preview();
@@ -16612,13 +16646,13 @@ var init_delivery_migration_archive2 = __esm(() => {
16612
16646
  // src/fixes.ts
16613
16647
  import { createHash as createHash9, randomUUID } from "node:crypto";
16614
16648
  import { lstat as lstat2, readFile as readFile6, realpath as realpath4, rename as rename4, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
16615
- import { dirname as dirname8, isAbsolute as isAbsolute3, relative as relative8, resolve as resolve13, sep as sep8 } from "node:path";
16649
+ import { dirname as dirname8, isAbsolute as isAbsolute3, relative as relative8, resolve as resolve14, sep as sep8 } from "node:path";
16616
16650
  import * as ts16 from "@typescript/typescript6";
16617
16651
  async function applyDiagnosticFix(fix, options = {}) {
16618
16652
  if (!fix || typeof fix.targetFile !== "string")
16619
16653
  throw new Error("Invalid DiagnosticFix");
16620
16654
  const root = await realpath4(options.rootDir ?? process.cwd());
16621
- const file = resolve13(root, fix.targetFile);
16655
+ const file = resolve14(root, fix.targetFile);
16622
16656
  const stat = await lstat2(file);
16623
16657
  const resolved = await realpath4(file);
16624
16658
  const relativePath = relative8(root, resolved);
@@ -16793,8 +16827,8 @@ function moduleObjects(source) {
16793
16827
  }
16794
16828
  function importSymbol(source, path, symbol) {
16795
16829
  identifier2(symbol);
16796
- const current = resolve13(source.fileName).replace(/\.(tsx?|mts|cts)$/, "");
16797
- const target = resolve13(dirname8(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
16830
+ const current = resolve14(source.fileName).replace(/\.(tsx?|mts|cts)$/, "");
16831
+ const target = resolve14(dirname8(source.fileName), path).replace(/\.(tsx?|mts|cts)$/, "");
16798
16832
  if (current === target)
16799
16833
  return source.text;
16800
16834
  const matches = source.statements.filter((item) => ts16.isImportDeclaration(item) && ts16.isStringLiteral(item.moduleSpecifier) && item.moduleSpecifier.text === path);
@@ -17271,7 +17305,7 @@ var init_release_evidence = __esm(() => {
17271
17305
 
17272
17306
  // src/graphql-schema.ts
17273
17307
  import { mkdir as mkdir5, readFile as readFile12 } from "node:fs/promises";
17274
- import { dirname as dirname11, resolve as resolve21 } from "node:path";
17308
+ import { dirname as dirname11, resolve as resolve22 } from "node:path";
17275
17309
  async function pullGraphqlSchema(options) {
17276
17310
  assertGraphqlOptions({ schema: options.output });
17277
17311
  const endpoint = new URL(options.url);
@@ -17311,7 +17345,7 @@ async function pullGraphqlSchema(options) {
17311
17345
  throw new Error("GraphQL schema export failed. Verify caller grants and enable introspection only in the intended development environment.");
17312
17346
  }
17313
17347
  const schema = lexicographicSortSchema(buildClientSchema(data));
17314
- const path = resolve21(options.output);
17348
+ const path = resolve22(options.output);
17315
17349
  const content = path.endsWith(".json") ? JSON.stringify(introspectionFromSchema(schema), null, 2) + `
17316
17350
  ` : `# GENERATED BY supacloud-compiler graphql-schema. DO NOT EDIT.
17317
17351
  # Database First: change database declarations, apply migrations, then re-export for the intended role.
@@ -17341,7 +17375,7 @@ var init_graphql_schema = __esm(() => {
17341
17375
  // src/database-contracts.ts
17342
17376
  import { createHash as createHash12 } from "node:crypto";
17343
17377
  import { mkdir as mkdir6, readFile as readFile14 } from "node:fs/promises";
17344
- import { dirname as dirname12, relative as relative12, resolve as resolve23 } from "node:path";
17378
+ import { dirname as dirname12, relative as relative12, resolve as resolve24 } from "node:path";
17345
17379
  import * as ts18 from "@typescript/typescript6";
17346
17380
  function hash3(value) {
17347
17381
  return createHash12("sha256").update(value).digest("hex");
@@ -17369,18 +17403,18 @@ function parseDatabaseContractsOptions(value, directory) {
17369
17403
  throw new TypeError("migrations must be an ordered list of SQL files");
17370
17404
  }
17371
17405
  return {
17372
- rootDir: resolve23(directory, field("rootDir")),
17373
- outDir: resolve23(directory, field("outDir")),
17374
- postgrestTypes: resolve23(directory, field("postgrestTypes")),
17375
- drizzleSchema: resolve23(directory, field("drizzleSchema")),
17406
+ rootDir: resolve24(directory, field("rootDir")),
17407
+ outDir: resolve24(directory, field("outDir")),
17408
+ postgrestTypes: resolve24(directory, field("postgrestTypes")),
17409
+ drizzleSchema: resolve24(directory, field("drizzleSchema")),
17376
17410
  role: field("role"),
17377
- graphql: { ...graphql, schema: resolve23(directory, graphql.schema) },
17378
- migrations: migrations.map((file) => resolve23(directory, file))
17411
+ graphql: { ...graphql, schema: resolve24(directory, graphql.schema) },
17412
+ migrations: migrations.map((file) => resolve24(directory, file))
17379
17413
  };
17380
17414
  }
17381
17415
  async function generateDatabaseContracts(options, check = false) {
17382
- const rootDir = resolve23(options.rootDir), outDir = resolve23(options.outDir);
17383
- const postgrestTypes = resolve23(rootDir, options.postgrestTypes), drizzleSchema = resolve23(rootDir, options.drizzleSchema);
17416
+ const rootDir = resolve24(options.rootDir), outDir = resolve24(options.outDir);
17417
+ const postgrestTypes = resolve24(rootDir, options.postgrestTypes), drizzleSchema = resolve24(rootDir, options.drizzleSchema);
17384
17418
  const snapshot = await readFile14(postgrestTypes, "utf8");
17385
17419
  const syntax = ts18.createSourceFile(postgrestTypes, snapshot, ts18.ScriptTarget.Latest, true);
17386
17420
  const database = syntax.statements.find((node) => (ts18.isTypeAliasDeclaration(node) || ts18.isInterfaceDeclaration(node)) && node.name.text === "Database" && node.modifiers?.some((modifier) => modifier.kind === ts18.SyntaxKind.ExportKeyword));
@@ -17408,7 +17442,7 @@ async function generateDatabaseContracts(options, check = false) {
17408
17442
  }
17409
17443
  const inputs = {};
17410
17444
  const addInput = async (path) => {
17411
- const absolute = resolve23(rootDir, path);
17445
+ const absolute = resolve24(rootDir, path);
17412
17446
  inputs[relative12(rootDir, absolute).replaceAll("\\", "/")] = hash3(await readFile14(absolute, "utf8"));
17413
17447
  };
17414
17448
  await addInput(postgrestTypes);
@@ -17425,8 +17459,8 @@ async function generateDatabaseContracts(options, check = false) {
17425
17459
  if (!source.isDeclarationFile && !source.fileName.includes("/node_modules/"))
17426
17460
  await addInput(source.fileName);
17427
17461
  }
17428
- await addInput(resolve23(rootDir, options.graphql.schema));
17429
- if (new Set(options.migrations.map((path) => resolve23(rootDir, path))).size !== options.migrations.length) {
17462
+ await addInput(resolve24(rootDir, options.graphql.schema));
17463
+ if (new Set(options.migrations.map((path) => resolve24(rootDir, path))).size !== options.migrations.length) {
17430
17464
  throw new Error("Duplicate migration in database contracts configuration");
17431
17465
  }
17432
17466
  for (const path of options.migrations)
@@ -17447,14 +17481,14 @@ async function generateDatabaseContracts(options, check = false) {
17447
17481
  version: 1,
17448
17482
  role: options.role,
17449
17483
  inputs: Object.fromEntries(Object.entries(inputs).sort(([a], [b]) => a.localeCompare(b))),
17450
- migrationOrder: options.migrations.map((path) => relative12(rootDir, resolve23(rootDir, path)).replaceAll("\\", "/")),
17484
+ migrationOrder: options.migrations.map((path) => relative12(rootDir, resolve24(rootDir, path)).replaceAll("\\", "/")),
17451
17485
  outputs: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)).map(([file, text]) => [file, hash3(text)]))
17452
17486
  };
17453
17487
  files["database.manifest.json"] = JSON.stringify(manifest, null, 2) + `
17454
17488
  `;
17455
17489
  const mismatches = [];
17456
17490
  for (const [file, content] of Object.entries(files)) {
17457
- const path = resolve23(outDir, file);
17491
+ const path = resolve24(outDir, file);
17458
17492
  let current;
17459
17493
  try {
17460
17494
  current = await readFile14(path, "utf8");
@@ -17468,12 +17502,12 @@ async function generateDatabaseContracts(options, check = false) {
17468
17502
  if (!check) {
17469
17503
  await mkdir6(outDir, { recursive: true });
17470
17504
  for (const [file, content] of Object.entries(files))
17471
- await writeFileIfChanged(resolve23(outDir, file), content);
17505
+ await writeFileIfChanged(resolve24(outDir, file), content);
17472
17506
  }
17473
17507
  return { upToDate: mismatches.length === 0, mismatches, written: check ? [] : mismatches, manifest };
17474
17508
  }
17475
17509
  async function runDatabaseContractsFile(path, check = false) {
17476
- const absolute = resolve23(path);
17510
+ const absolute = resolve24(path);
17477
17511
  const value = JSON.parse(await readFile14(absolute, "utf8"));
17478
17512
  return generateDatabaseContracts(parseDatabaseContractsOptions(value, dirname12(absolute)), check);
17479
17513
  }
@@ -21627,6 +21661,52 @@ function validateEffectPolicies(graph, options = {}) {
21627
21661
  return diagnostics;
21628
21662
  }
21629
21663
 
21664
+ // src/database-governance.ts
21665
+ import { execFile } from "node:child_process";
21666
+ import { resolve as resolve5 } from "node:path";
21667
+ import { fileURLToPath } from "node:url";
21668
+ function assertDatabaseGovernance(value) {
21669
+ if (!value || typeof value !== "object" || Array.isArray(value))
21670
+ throw new Error("Invalid databaseGovernance configuration.");
21671
+ const entry = value;
21672
+ if (entry["mode"] !== "off" && entry["mode"] !== "check" && entry["mode"] !== "enforce" || Object.keys(entry).some((key) => !["mode", "projectRoot", "moduleFile", "databaseUrl", "databaseUrlEnv", "schemas"].includes(key)) || ["projectRoot", "moduleFile", "databaseUrl", "databaseUrlEnv"].some((key) => entry[key] !== undefined && (typeof entry[key] !== "string" || !entry[key].trim())) || entry["databaseUrlEnv"] !== undefined && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(String(entry["databaseUrlEnv"])) || entry["schemas"] !== undefined && (!Array.isArray(entry["schemas"]) || !entry["schemas"].length || !entry["schemas"].every((schema) => typeof schema === "string" && schema.trim()))) {
21673
+ throw new Error("Invalid databaseGovernance mode, paths, connection or schemas.");
21674
+ }
21675
+ }
21676
+ async function checkDatabaseGovernance(rootDir, value) {
21677
+ if (value === undefined)
21678
+ return [];
21679
+ const failure = () => [{
21680
+ severity: "error",
21681
+ code: "database-governance",
21682
+ message: "Database governance could not be verified. Check configuration, installed @supacloud/db, Bun and read-only database access."
21683
+ }];
21684
+ try {
21685
+ assertDatabaseGovernance(value);
21686
+ if (value.mode === "off")
21687
+ return [];
21688
+ const options = { ...value, projectRoot: resolve5(rootDir, value.projectRoot ?? ".") };
21689
+ const worker = fileURLToPath(new URL(import.meta.url.endsWith(".ts") ? "./database-governance-worker.ts" : "./database-governance-worker.js", import.meta.url));
21690
+ const output = await new Promise((accept, reject) => {
21691
+ const child = execFile(process.versions.bun ? process.execPath : "bun", ["--no-env-file", worker], { timeout: 30000, killSignal: "SIGKILL", maxBuffer: 1024 * 1024 }, (error, stdout) => error ? reject(error) : accept(stdout));
21692
+ child.stdin?.on("error", reject);
21693
+ child.stdin?.end(JSON.stringify(options));
21694
+ });
21695
+ const report = JSON.parse(output);
21696
+ if (!report || typeof report !== "object" || !("diagnostics" in report) || !Array.isArray(report.diagnostics))
21697
+ return failure();
21698
+ const diagnostics = [];
21699
+ for (const item of report.diagnostics) {
21700
+ if (!item || typeof item !== "object" || !("code" in item) || typeof item.code !== "string" || !item.code.startsWith("database-") || !("message" in item) || typeof item.message !== "string" || !("severity" in item) || item.severity !== "error")
21701
+ return failure();
21702
+ diagnostics.push({ severity: "error", code: item.code, message: item.message });
21703
+ }
21704
+ return diagnostics;
21705
+ } catch {
21706
+ return failure();
21707
+ }
21708
+ }
21709
+
21630
21710
  // src/compile.ts
21631
21711
  function withDefaultGovernance(options) {
21632
21712
  return options.commandCapabilities === undefined ? { ...options, commandCapabilities: {
@@ -21649,6 +21729,10 @@ async function compileProject(options) {
21649
21729
  ...validateClientSchemaBoundaries(graph, options),
21650
21730
  ...validateEffectPolicies(graph, options.effect)
21651
21731
  ];
21732
+ const databaseDiagnostics = await checkDatabaseGovernance(options.rootDir, options.databaseGovernance);
21733
+ diagnostics.push(...databaseDiagnostics);
21734
+ if (databaseDiagnostics.length)
21735
+ return { diagnostics, graph, written: [] };
21652
21736
  if (diagnostics.some((item) => item.code === "runtime-injection-disallowed")) {
21653
21737
  return { diagnostics, graph, written: [] };
21654
21738
  }
@@ -21715,6 +21799,11 @@ async function checkProject(options) {
21715
21799
  ...validateClientSchemaBoundaries(graph, options),
21716
21800
  ...validateEffectPolicies(graph, options.effect)
21717
21801
  ];
21802
+ const databaseDiagnostics = await checkDatabaseGovernance(options.rootDir, options.databaseGovernance);
21803
+ diagnostics.push(...databaseDiagnostics);
21804
+ if (databaseDiagnostics.length) {
21805
+ return { diagnostics, graph, upToDate: false, mismatches: ["Database governance verification failed."] };
21806
+ }
21718
21807
  if (diagnostics.some((item) => item.code === "runtime-injection-disallowed")) {
21719
21808
  return { diagnostics, graph, upToDate: false, mismatches: ["Runtime DI must be migrated to constructor injection."] };
21720
21809
  }
@@ -22041,7 +22130,7 @@ function formatDeliveryPlan(result) {
22041
22130
  // src/delivery-build.ts
22042
22131
  import { mkdir as mkdir3, mkdtemp, readFile as readFile5, realpath as realpath3, rename as rename3, rm as rm2 } from "node:fs/promises";
22043
22132
  import { readFileSync as readFileSync3 } from "node:fs";
22044
- import { dirname as dirname7, join as join9, relative as relative7, resolve as resolve12, sep as sep7 } from "node:path";
22133
+ import { dirname as dirname7, join as join9, relative as relative7, resolve as resolve13, sep as sep7 } from "node:path";
22045
22134
  import * as ts15 from "@typescript/typescript6";
22046
22135
 
22047
22136
  // src/delivery-build-schema.ts
@@ -22083,7 +22172,7 @@ function renderDeliveryTarget(graph, target, options) {
22083
22172
  init_delivery_files2();
22084
22173
  import { isBuiltin } from "node:module";
22085
22174
  import { readFile as readFile4 } from "node:fs/promises";
22086
- import { join as join7, resolve as resolve9 } from "node:path";
22175
+ import { join as join7, resolve as resolve10 } from "node:path";
22087
22176
  import * as ts14 from "@typescript/typescript6";
22088
22177
 
22089
22178
  // src/delivery-imports.ts
@@ -22260,7 +22349,7 @@ async function bundleDeliveryTarget(name, code, project, generatedDirectory, opt
22260
22349
  async function bundleDeliveryTargetInProcess(name, code, project, generatedDirectory, options) {
22261
22350
  const inputs = new Map;
22262
22351
  const workingDirectory = process.cwd();
22263
- const entry = resolve9(generatedDirectory, `delivery-${name}.ts`);
22352
+ const entry = resolve10(generatedDirectory, `delivery-${name}.ts`);
22264
22353
  const entryPattern = new RegExp(`^${entry.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`);
22265
22354
  const result = await Bun.build({
22266
22355
  entrypoints: [entry],
@@ -22283,7 +22372,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
22283
22372
  if (args.path === entry)
22284
22373
  return { contents: code, loader: "ts" };
22285
22374
  const bytes = await readFile4(args.path);
22286
- inputs.set(resolve9(args.path), digest(bytes));
22375
+ inputs.set(resolve10(args.path), digest(bytes));
22287
22376
  return { contents: staticDeliveryImports(args.path, bytes), loader: args.loader };
22288
22377
  });
22289
22378
  }
@@ -22293,7 +22382,7 @@ async function bundleDeliveryTargetInProcess(name, code, project, generatedDirec
22293
22382
  throw new Error("Independent bundle failed or has no dependency metadata.");
22294
22383
  const runtimeImports = new Set;
22295
22384
  for (const [path, metadata] of Object.entries(result.metafile.inputs)) {
22296
- if (resolve9(workingDirectory, path) !== entry && !inputs.has(resolve9(workingDirectory, path))) {
22385
+ if (resolve10(workingDirectory, path) !== entry && !inputs.has(resolve10(workingDirectory, path))) {
22297
22386
  throw new Error("Bundler reported an input that was not captured by the delivery snapshot.");
22298
22387
  }
22299
22388
  for (const imported of metadata.imports) {
@@ -22632,14 +22721,14 @@ interface DeliveryWorkerHost {
22632
22721
 
22633
22722
  // src/delivery-migrations.ts
22634
22723
  init_delivery_files2();
22635
- import { resolve as resolve11 } from "node:path";
22724
+ import { resolve as resolve12 } from "node:path";
22636
22725
  async function prepareDeliveryMigrations(project, generatedRoot, declarations = []) {
22637
22726
  const entries = [];
22638
22727
  const files = new Map;
22639
22728
  const inputs = new Map;
22640
22729
  let totalBytes = 0;
22641
22730
  for (const declaration of [...declarations].sort((a, b) => BigInt(a.version) < BigInt(b.version) ? -1 : BigInt(a.version) > BigInt(b.version) ? 1 : 0)) {
22642
- const source = resolve11(project, declaration.source);
22731
+ const source = resolve12(project, declaration.source);
22643
22732
  if (!inside(project, source) || inside(generatedRoot, source))
22644
22733
  throw new Error("Invalid migration source.");
22645
22734
  const bytes = await readBoundedOwned(project, source, 1048576);
@@ -22690,7 +22779,7 @@ async function buildDeliveryProject(options, delivery) {
22690
22779
  const settings = parseDeliveryOptions(delivery);
22691
22780
  if (typeof Bun === "undefined")
22692
22781
  throw new Error("Independent delivery builds require Bun.");
22693
- const configPath = ts15.findConfigFile(resolve12(options.rootDir), ts15.sys.fileExists);
22782
+ const configPath = ts15.findConfigFile(resolve13(options.rootDir), ts15.sys.fileExists);
22694
22783
  if (!configPath)
22695
22784
  throw new Error("Independent delivery builds require a project tsconfig.json.");
22696
22785
  const lexicalProject = dirname7(configPath);
@@ -22698,11 +22787,11 @@ async function buildDeliveryProject(options, delivery) {
22698
22787
  const sourceRoot = await realpath3(options.rootDir);
22699
22788
  if (!inside(project, sourceRoot))
22700
22789
  throw new Error("Application sources must be inside the project.");
22701
- const requested = resolve12(options.outDir, "delivery");
22790
+ const requested = resolve13(options.outDir, "delivery");
22702
22791
  if (!inside(lexicalProject, requested))
22703
22792
  throw new Error("Output must be inside the application project.");
22704
- const buildRoot = resolve12(project, relative7(lexicalProject, requested));
22705
- const generatedRoot = resolve12(project, relative7(lexicalProject, options.outDir));
22793
+ const buildRoot = resolve13(project, relative7(lexicalProject, requested));
22794
+ const generatedRoot = resolve13(project, relative7(lexicalProject, options.outDir));
22706
22795
  if (inside(generatedRoot, sourceRoot))
22707
22796
  throw new Error("Output must not contain the application source root.");
22708
22797
  const configInputs = new Map;
@@ -22710,7 +22799,7 @@ async function buildDeliveryProject(options, delivery) {
22710
22799
  ...ts15.sys,
22711
22800
  readFile(path) {
22712
22801
  const contents = readFileSync3(path, "utf8");
22713
- configInputs.set(resolve12(path), digest(contents));
22802
+ configInputs.set(resolve13(path), digest(contents));
22714
22803
  return contents;
22715
22804
  },
22716
22805
  onUnRecoverableConfigFileDiagnostic() {
@@ -22748,7 +22837,7 @@ async function buildDeliveryProject(options, delivery) {
22748
22837
  if (!target || (kind === "worker" ? target.kind !== "jobs" : target.kind === "jobs")) {
22749
22838
  throw new Error("Delivery host kind does not match its target.");
22750
22839
  }
22751
- const path = resolve12(sourceRoot, app.source);
22840
+ const path = resolve13(sourceRoot, app.source);
22752
22841
  if (inside(generatedRoot, path) || !/\.[cm]?ts$/.test(path))
22753
22842
  throw new Error("Hosts require application TypeScript source.");
22754
22843
  hosts.set(app.target, { path, kind, hash: digest(await readOwned(sourceRoot, path)) });
@@ -22875,7 +22964,7 @@ async function buildDeliveryProject(options, delivery) {
22875
22964
  }));
22876
22965
  const assetInputs = {};
22877
22966
  for (const asset of assets.filter((asset) => asset.target === target.name)) {
22878
- const path = resolve12(sourceRoot, asset.source);
22967
+ const path = resolve13(sourceRoot, asset.source);
22879
22968
  const bytes = await readOwned(sourceRoot, path);
22880
22969
  const hash = digest(bytes);
22881
22970
  const previousHash = snapshots.get(path);
@@ -23210,12 +23299,12 @@ init_release_evidence();
23210
23299
 
23211
23300
  // src/watch.ts
23212
23301
  import { existsSync as existsSync4, watch } from "node:fs";
23213
- import { dirname as dirname9, relative as relative10, resolve as resolve15, sep as sep10 } from "node:path";
23302
+ import { dirname as dirname9, relative as relative10, resolve as resolve16, sep as sep10 } from "node:path";
23214
23303
 
23215
23304
  // src/incremental.ts
23216
23305
  import { createHash as createHash10 } from "node:crypto";
23217
23306
  import { access as access3, readdir as readdir3, readFile as readFile7 } from "node:fs/promises";
23218
- import { isAbsolute as isAbsolute4, relative as relative9, resolve as resolve14, sep as sep9 } from "node:path";
23307
+ import { isAbsolute as isAbsolute4, relative as relative9, resolve as resolve15, sep as sep9 } from "node:path";
23219
23308
  init_graphql_inputs();
23220
23309
  function createDependencyGraphCache() {
23221
23310
  return {
@@ -23284,11 +23373,11 @@ async function readSourceBytes(path) {
23284
23373
  return readFile7(path);
23285
23374
  }
23286
23375
  async function updateSnapshot(previous, options, changedPaths) {
23287
- const rootDir = resolve14(options.rootDir);
23288
- const outDir = resolve14(options.outDir);
23376
+ const rootDir = resolve15(options.rootDir);
23377
+ const outDir = resolve15(options.outDir);
23289
23378
  const files = { ...previous.files };
23290
23379
  await Promise.all(changedPaths.map(async (changedPath) => {
23291
- const absolutePath = isAbsolute4(changedPath) ? resolve14(changedPath) : resolve14(rootDir, changedPath);
23380
+ const absolutePath = isAbsolute4(changedPath) ? resolve15(changedPath) : resolve15(rootDir, changedPath);
23292
23381
  const relativeChangedPath = relative9(rootDir, absolutePath);
23293
23382
  if (relativeChangedPath === ".." || relativeChangedPath.startsWith(`..${sep9}`))
23294
23383
  return;
@@ -23306,8 +23395,8 @@ async function updateSnapshot(previous, options, changedPaths) {
23306
23395
  return { files, optionsKey: optionsKeyOf(options) };
23307
23396
  }
23308
23397
  async function createSnapshot(options) {
23309
- const rootDir = resolve14(options.rootDir);
23310
- const outDir = resolve14(options.outDir);
23398
+ const rootDir = resolve15(options.rootDir);
23399
+ const outDir = resolve15(options.outDir);
23311
23400
  const paths = await listSourceFiles(rootDir, outDir);
23312
23401
  const files = {};
23313
23402
  const entries = await Promise.all(paths.map(async (path) => {
@@ -23330,8 +23419,8 @@ async function createSnapshot(options) {
23330
23419
  }
23331
23420
  function optionsKeyOf(options) {
23332
23421
  return JSON.stringify({
23333
- rootDir: resolve14(options.rootDir),
23334
- outDir: resolve14(options.outDir),
23422
+ rootDir: resolve15(options.rootDir),
23423
+ outDir: resolve15(options.outDir),
23335
23424
  include: options.include,
23336
23425
  strict: options.strict,
23337
23426
  writeOnError: options.writeOnError,
@@ -23347,6 +23436,10 @@ function optionsKeyOf(options) {
23347
23436
  openApi: options.openApi,
23348
23437
  generatePermissions: options.generatePermissions,
23349
23438
  typeSafety: options.typeSafety,
23439
+ databaseGovernance: options.databaseGovernance && {
23440
+ ...options.databaseGovernance,
23441
+ databaseUrl: undefined
23442
+ },
23350
23443
  effect: options.effect,
23351
23444
  treeShakeUnusedProviders: options.treeShakeUnusedProviders,
23352
23445
  graphql: options.graphql
@@ -23356,7 +23449,7 @@ async function listSourceFiles(rootDir, outDir) {
23356
23449
  const result = [];
23357
23450
  const visit = async (directory) => {
23358
23451
  for (const entry of await readdir3(directory, { withFileTypes: true })) {
23359
- const path = resolve14(directory, entry.name);
23452
+ const path = resolve15(directory, entry.name);
23360
23453
  if (entry.isDirectory()) {
23361
23454
  if (entry.name === "node_modules" || entry.name === ".git" || path === outDir)
23362
23455
  continue;
@@ -23491,8 +23584,8 @@ function isCompilerConfigurationPath(rootDir, changedPath) {
23491
23584
  ].includes(relativePath) || /^tsconfig\.[^/]+\.json$/.test(relativePath);
23492
23585
  }
23493
23586
  function watchProject(options) {
23494
- const rootDir = resolve15(options.rootDir);
23495
- const outDir = resolve15(options.outDir);
23587
+ const rootDir = resolve16(options.rootDir);
23588
+ const outDir = resolve16(options.outDir);
23496
23589
  const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
23497
23590
  let timer;
23498
23591
  let closed = false;
@@ -23502,7 +23595,9 @@ function watchProject(options) {
23502
23595
  const pendingPaths = new Set;
23503
23596
  let watcher;
23504
23597
  let schemaWatcher;
23505
- const schemaPath = options.graphql ? resolve15(rootDir, options.graphql.schema) : undefined;
23598
+ let databaseWatcher;
23599
+ const databaseRoot = options.databaseGovernance && options.databaseGovernance.mode !== "off" ? resolve16(rootDir, options.databaseGovernance.projectRoot ?? ".") : undefined;
23600
+ const schemaPath = options.graphql ? resolve16(rootDir, options.graphql.schema) : undefined;
23506
23601
  const incremental = createIncrementalCompiler();
23507
23602
  let initialEvent;
23508
23603
  let resolveReady = () => {
@@ -23529,6 +23624,7 @@ function watchProject(options) {
23529
23624
  clearTimeout(timer);
23530
23625
  watcher?.close();
23531
23626
  schemaWatcher?.close();
23627
+ databaseWatcher?.close();
23532
23628
  };
23533
23629
  const compile = (initial, changedPaths = []) => {
23534
23630
  if (closed && !initial)
@@ -23603,6 +23699,13 @@ function watchProject(options) {
23603
23699
  startRecompile(paths);
23604
23700
  }, debounceMs);
23605
23701
  };
23702
+ const isDatabaseInput = (path) => {
23703
+ if (!databaseRoot)
23704
+ return false;
23705
+ const local = relative10(databaseRoot, path);
23706
+ const output = relative10(outDir, path);
23707
+ return local !== ".." && !local.startsWith(`..${sep10}`) && output !== "" && (output === ".." || output.startsWith(`..${sep10}`)) && !local.split(sep10).some((part) => ["node_modules", ".git", ".wt", ".worktrees", "dist", "output"].includes(part)) && /\.(?:sql|json|[cm]?[jt]s)$/.test(path);
23708
+ };
23606
23709
  const startup = compile(true).then(() => {
23607
23710
  if (closed) {
23608
23711
  if (initialEvent)
@@ -23612,20 +23715,27 @@ function watchProject(options) {
23612
23715
  watcher = watch(rootDir, { recursive: true }, (_eventType, filename) => {
23613
23716
  if (!filename)
23614
23717
  return schedule();
23615
- const changedPath = resolve15(rootDir, filename.toString());
23718
+ const changedPath = resolve16(rootDir, filename.toString());
23616
23719
  const relativePath = relative10(outDir, changedPath);
23617
23720
  if (!relativePath.startsWith("..") && relativePath !== "")
23618
23721
  return;
23619
- if (/\.(tsx?|mts|cts)$/.test(changedPath) || isCompilerConfigurationPath(rootDir, changedPath) || options.graphql && (/\.(graphql|gql)$/.test(changedPath) || changedPath === schemaPath)) {
23722
+ if (/\.(tsx?|mts|cts)$/.test(changedPath) || isCompilerConfigurationPath(rootDir, changedPath) || isDatabaseInput(changedPath) || options.graphql && (/\.(graphql|gql)$/.test(changedPath) || changedPath === schemaPath)) {
23620
23723
  schedule(relative10(rootDir, changedPath));
23621
23724
  }
23622
23725
  });
23726
+ if (databaseRoot && databaseRoot !== rootDir) {
23727
+ databaseWatcher = watch(databaseRoot, { recursive: true }, (_eventType, filename) => {
23728
+ const path = filename ? resolve16(databaseRoot, filename.toString()) : undefined;
23729
+ if (!path || isDatabaseInput(path))
23730
+ schedule(path);
23731
+ });
23732
+ }
23623
23733
  if (schemaPath && relative10(rootDir, schemaPath).startsWith(`..${sep10}`)) {
23624
23734
  let directory = dirname9(schemaPath);
23625
23735
  while (!existsSync4(directory) && dirname9(directory) !== directory)
23626
23736
  directory = dirname9(directory);
23627
23737
  schemaWatcher = watch(directory, { recursive: true }, (_eventType, filename) => {
23628
- if (!filename || resolve15(directory, filename.toString()) === schemaPath)
23738
+ if (!filename || resolve16(directory, filename.toString()) === schemaPath)
23629
23739
  schedule(schemaPath);
23630
23740
  });
23631
23741
  }
@@ -23648,19 +23758,19 @@ function watchProject(options) {
23648
23758
  }
23649
23759
  // src/migrations.ts
23650
23760
  import { rename as rename5, readFile as readFile9, writeFile as writeFile4, rm as rm3 } from "node:fs/promises";
23651
- import { relative as relative11, resolve as resolve17 } from "node:path";
23761
+ import { relative as relative11, resolve as resolve18 } from "node:path";
23652
23762
  import * as ts17 from "@typescript/typescript6";
23653
23763
 
23654
23764
  // src/migration-policy.ts
23655
23765
  import { readFile as readFile8 } from "node:fs/promises";
23656
23766
  import { readFileSync as readFileSync4 } from "node:fs";
23657
- import { resolve as resolve16 } from "node:path";
23767
+ import { resolve as resolve17 } from "node:path";
23658
23768
 
23659
23769
  // src/migration-app-version.ts
23660
- var MIGRATION_APP_VERSION = "0.26.0";
23770
+ var MIGRATION_APP_VERSION = "0.26.1";
23661
23771
 
23662
23772
  // src/migration-elysia-version.ts
23663
- var MIGRATION_ELYSIA_VERSION = "0.29.1";
23773
+ var MIGRATION_ELYSIA_VERSION = "0.29.2";
23664
23774
 
23665
23775
  // src/migration-policy.ts
23666
23776
  var cachedCompilerVersion;
@@ -23687,7 +23797,7 @@ async function checkMigrationDependencies(rootDir) {
23687
23797
  const problems = [];
23688
23798
  for (const [name, expected] of Object.entries(migrationDependencies())) {
23689
23799
  try {
23690
- const manifest = JSON.parse(await readFile8(resolve16(rootDir, "node_modules", name, "package.json"), "utf8"));
23800
+ const manifest = JSON.parse(await readFile8(resolve17(rootDir, "node_modules", name, "package.json"), "utf8"));
23691
23801
  if (!manifest || typeof manifest !== "object" || !("name" in manifest) || manifest.name !== name || !("version" in manifest) || manifest.version !== expected) {
23692
23802
  problems.push(`${name}: requires tested installed version ${expected}`);
23693
23803
  }
@@ -23802,10 +23912,10 @@ function createMigrationProgram(fileNames, sourceOverrides, rootDir) {
23802
23912
  const fileExists = host.fileExists.bind(host);
23803
23913
  const readFile = host.readFile.bind(host);
23804
23914
  const currentDirectory = host.getCurrentDirectory.bind(host);
23805
- host.fileExists = (fileName) => sourceOverrides.has(resolve17(fileName)) || fileExists(fileName);
23806
- host.readFile = (fileName) => sourceOverrides.get(resolve17(fileName)) ?? readFile(fileName);
23915
+ host.fileExists = (fileName) => sourceOverrides.has(resolve18(fileName)) || fileExists(fileName);
23916
+ host.readFile = (fileName) => sourceOverrides.get(resolve18(fileName)) ?? readFile(fileName);
23807
23917
  host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
23808
- const source = sourceOverrides.get(resolve17(fileName));
23918
+ const source = sourceOverrides.get(resolve18(fileName));
23809
23919
  return source === undefined ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) : ts17.createSourceFile(fileName, source, languageVersion, true);
23810
23920
  };
23811
23921
  host.getCurrentDirectory = () => rootDir ?? currentDirectory();
@@ -23831,7 +23941,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
23831
23941
  issues.push(issue);
23832
23942
  };
23833
23943
  for (const sourceFile of sourceFiles) {
23834
- const sourcePath = resolve17(sourceFile.fileName);
23944
+ const sourcePath = resolve18(sourceFile.fileName);
23835
23945
  if (!includedFiles.has(sourcePath))
23836
23946
  continue;
23837
23947
  const visit = (node) => {
@@ -23839,7 +23949,7 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
23839
23949
  const options = node.arguments[1];
23840
23950
  const object = options && resolveStaticObjectLiteral2(options, checker);
23841
23951
  if (object) {
23842
- const objectPath = resolve17(object.getSourceFile().fileName);
23952
+ const objectPath = resolve18(object.getSourceFile().fileName);
23843
23953
  const properties = routeResponseProperties(object);
23844
23954
  if (properties.response) {
23845
23955
  if (!includedFiles.has(objectPath)) {
@@ -23882,13 +23992,13 @@ function planRouteResponseMigration(sourceFiles, checker, rootDir, includedFiles
23882
23992
  line: lineOf2(sourceFile, response)
23883
23993
  });
23884
23994
  } else {
23885
- const replacements = replacementsByFile.get(resolve17(sourceFile.fileName)) ?? [];
23995
+ const replacements = replacementsByFile.get(resolve18(sourceFile.fileName)) ?? [];
23886
23996
  replacements.push({
23887
23997
  start: response.getStart(sourceFile),
23888
23998
  end: response.getEnd(),
23889
23999
  text: `responses: { 200: ${response.initializer.getText(sourceFile)} }`
23890
24000
  });
23891
- replacementsByFile.set(resolve17(sourceFile.fileName), replacements);
24001
+ replacementsByFile.set(resolve18(sourceFile.fileName), replacements);
23892
24002
  }
23893
24003
  }
23894
24004
  return { replacementsByFile, issues };
@@ -23901,7 +24011,7 @@ function applyReplacements(source, replacements) {
23901
24011
  return content;
23902
24012
  }
23903
24013
  function migrateRouteResponse(source, fileName) {
23904
- const absoluteFile = resolve17(fileName);
24014
+ const absoluteFile = resolve18(fileName);
23905
24015
  const sourceOverrides = new Map([[absoluteFile, source]]);
23906
24016
  const program = createMigrationProgram([absoluteFile], sourceOverrides);
23907
24017
  const sourceFile = program.getSourceFile(absoluteFile);
@@ -23917,7 +24027,7 @@ function migrateRouteResponse(source, fileName) {
23917
24027
  }]
23918
24028
  };
23919
24029
  }
23920
- const plan = planRouteResponseMigration([sourceFile], program.getTypeChecker(), resolve17("."), new Set([absoluteFile]));
24030
+ const plan = planRouteResponseMigration([sourceFile], program.getTypeChecker(), resolve18("."), new Set([absoluteFile]));
23921
24031
  const replacements = plan.replacementsByFile.get(absoluteFile) ?? [];
23922
24032
  return {
23923
24033
  changed: replacements.length > 0,
@@ -23927,7 +24037,7 @@ function migrateRouteResponse(source, fileName) {
23927
24037
  };
23928
24038
  }
23929
24039
  function migrateRouteResponseProject(files, rootDir, sourceByPath) {
23930
- const absoluteFiles = files.map((file) => resolve17(file));
24040
+ const absoluteFiles = files.map((file) => resolve18(file));
23931
24041
  const program = createMigrationProgram(absoluteFiles, sourceByPath, rootDir);
23932
24042
  const sourceFiles = absoluteFiles.map((file) => program.getSourceFile(file)).filter((file) => file !== undefined);
23933
24043
  const plan = planRouteResponseMigration(sourceFiles, program.getTypeChecker(), rootDir, new Set(absoluteFiles));
@@ -23940,11 +24050,11 @@ function migrateRouteResponseProject(files, rootDir, sourceByPath) {
23940
24050
  changed: replacements.length > 0,
23941
24051
  content: applyReplacements(source, replacements),
23942
24052
  replacements: replacements.length,
23943
- issues: plan.issues.filter((issue) => resolve17(rootDir, issue.file) === file)
24053
+ issues: plan.issues.filter((issue) => resolve18(rootDir, issue.file) === file)
23944
24054
  });
23945
24055
  }
23946
24056
  for (const issue of plan.issues) {
23947
- const path = resolve17(rootDir, issue.file);
24057
+ const path = resolve18(rootDir, issue.file);
23948
24058
  if (!results.has(path) && sourceByPath.has(path)) {
23949
24059
  results.set(path, {
23950
24060
  changed: false,
@@ -23982,7 +24092,7 @@ async function writeAtomically(path, content) {
23982
24092
  }
23983
24093
  }
23984
24094
  async function migrateProject(options) {
23985
- const rootDir = resolve17(options.rootDir);
24095
+ const rootDir = resolve18(options.rootDir);
23986
24096
  let migrations = SUPACLOUD_MIGRATIONS;
23987
24097
  const preflightIssues = [];
23988
24098
  if (options.fromVersion !== undefined || options.toVersion !== undefined) {
@@ -24038,7 +24148,7 @@ async function migrateProject(options) {
24038
24148
  }
24039
24149
  };
24040
24150
  for (const filePath of files) {
24041
- sourceByPath.set(resolve17(filePath), await readFile9(filePath, "utf8"));
24151
+ sourceByPath.set(resolve18(filePath), await readFile9(filePath, "utf8"));
24042
24152
  }
24043
24153
  const originalSources = new Map(sourceByPath);
24044
24154
  const writtenFiles = new Set;
@@ -24047,7 +24157,7 @@ async function migrateProject(options) {
24047
24157
  if (projectResults)
24048
24158
  appendIssues(projectResults.issues);
24049
24159
  for (const filePath of files) {
24050
- const absoluteFile = resolve17(filePath);
24160
+ const absoluteFile = resolve18(filePath);
24051
24161
  const file = relative11(rootDir, absoluteFile) || absoluteFile;
24052
24162
  const before = sourceByPath.get(absoluteFile);
24053
24163
  if (before === undefined)
@@ -24108,11 +24218,11 @@ async function migrateProject(options) {
24108
24218
  // src/migration-assess.ts
24109
24219
  import { createHash as createHash11 } from "node:crypto";
24110
24220
  import { readFile as readFile11 } from "node:fs/promises";
24111
- import { join as join10, resolve as resolve19 } from "node:path";
24221
+ import { join as join10, resolve as resolve20 } from "node:path";
24112
24222
 
24113
24223
  // src/openapi-tools.ts
24114
24224
  import { mkdir as mkdir4, readFile as readFile10, rename as rename6, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
24115
- import { dirname as dirname10, resolve as resolve18 } from "node:path";
24225
+ import { dirname as dirname10, resolve as resolve19 } from "node:path";
24116
24226
  import { pathToFileURL } from "node:url";
24117
24227
 
24118
24228
  class OpenApiDocumentError extends Error {
@@ -24503,7 +24613,7 @@ function serializeOpenApiJson(document, space = 2) {
24503
24613
  }
24504
24614
  async function readOpenApiJson(path) {
24505
24615
  try {
24506
- const value = JSON.parse(await readFile10(resolve18(path), "utf8"));
24616
+ const value = JSON.parse(await readFile10(resolve19(path), "utf8"));
24507
24617
  return parseOpenApiDocument(value);
24508
24618
  } catch (error) {
24509
24619
  if (error instanceof OpenApiDocumentError)
@@ -24512,7 +24622,7 @@ async function readOpenApiJson(path) {
24512
24622
  }
24513
24623
  }
24514
24624
  async function writeOpenApiJson(document, outputPath, space = 2) {
24515
- const path = resolve18(outputPath);
24625
+ const path = resolve19(outputPath);
24516
24626
  const content = serializeOpenApiJson(document, space);
24517
24627
  await mkdir4(dirname10(path), { recursive: true });
24518
24628
  try {
@@ -24533,7 +24643,7 @@ async function writeOpenApiJson(document, outputPath, space = 2) {
24533
24643
  }
24534
24644
  async function loadGeneratedOpenApiDocument(modulePath) {
24535
24645
  try {
24536
- const moduleUrl = pathToFileURL(resolve18(modulePath));
24646
+ const moduleUrl = pathToFileURL(resolve19(modulePath));
24537
24647
  moduleUrl.searchParams.set("supacloud-openapi-export", "1");
24538
24648
  const loaded = await import(moduleUrl.href);
24539
24649
  if (!isRecord(loaded))
@@ -24629,18 +24739,18 @@ function isRecord2(value) {
24629
24739
  function arrayLength(value) {
24630
24740
  return Array.isArray(value) ? value.length : undefined;
24631
24741
  }
24632
- async function sha2563(path) {
24742
+ async function sha2564(path) {
24633
24743
  return createHash11("sha256").update(await readFile11(path)).digest("hex");
24634
24744
  }
24635
24745
  function overallStatus(findings) {
24636
24746
  return findings.reduce((current, finding) => STATUS_PRIORITY[finding.status] > STATUS_PRIORITY[current] ? finding.status : current, "compatible");
24637
24747
  }
24638
24748
  async function assessMigration(options) {
24639
- const projectDir = resolve19(options.projectDir);
24749
+ const projectDir = resolve20(options.projectDir);
24640
24750
  const compile = {
24641
24751
  ...options.compile,
24642
- rootDir: resolve19(options.compile.rootDir),
24643
- outDir: resolve19(options.compile.outDir)
24752
+ rootDir: resolve20(options.compile.rootDir),
24753
+ outDir: resolve20(options.compile.outDir)
24644
24754
  };
24645
24755
  const findings = [];
24646
24756
  const dependencyProblems = await checkMigrationDependencies(projectDir);
@@ -24706,7 +24816,7 @@ async function assessMigration(options) {
24706
24816
  contractsManifest = {
24707
24817
  path: contractsManifestPath,
24708
24818
  present: true,
24709
- sha256: await sha2563(contractsManifestPath),
24819
+ sha256: await sha2564(contractsManifestPath),
24710
24820
  version: 1,
24711
24821
  ...commands === undefined ? {} : { commands },
24712
24822
  ...routes === undefined ? {} : { routes },
@@ -24723,15 +24833,15 @@ async function assessMigration(options) {
24723
24833
  }
24724
24834
  let openApi;
24725
24835
  if (options.baselineOpenApiPath && options.currentOpenApiPath) {
24726
- const baselinePath = resolve19(projectDir, options.baselineOpenApiPath);
24727
- const currentPath = resolve19(projectDir, options.currentOpenApiPath);
24836
+ const baselinePath = resolve20(projectDir, options.baselineOpenApiPath);
24837
+ const currentPath = resolve20(projectDir, options.currentOpenApiPath);
24728
24838
  try {
24729
24839
  const diff = diffOpenApiDocuments(await readOpenApiJson(baselinePath), await readOpenApiJson(currentPath));
24730
24840
  openApi = {
24731
24841
  baselinePath,
24732
- baselineSha256: await sha2563(baselinePath),
24842
+ baselineSha256: await sha2564(baselinePath),
24733
24843
  currentPath,
24734
- currentSha256: await sha2563(currentPath),
24844
+ currentSha256: await sha2564(currentPath),
24735
24845
  diff
24736
24846
  };
24737
24847
  if (!diff.ok) {
@@ -24813,9 +24923,10 @@ init_validate();
24813
24923
  // src/config.ts
24814
24924
  init_graphql_options();
24815
24925
  import { existsSync as existsSync5 } from "node:fs";
24816
- import { join as join11, resolve as resolve20 } from "node:path";
24926
+ import { join as join11, resolve as resolve21 } from "node:path";
24817
24927
  import { pathToFileURL as pathToFileURL2 } from "node:url";
24818
24928
  var DEFAULT_SUPACLOUD_CONFIG = {
24929
+ databaseGovernance: { mode: "off" },
24819
24930
  graphql: false,
24820
24931
  root: "src",
24821
24932
  outDir: "generated",
@@ -24846,6 +24957,8 @@ var DEFAULT_SUPACLOUD_CONFIG = {
24846
24957
  }
24847
24958
  };
24848
24959
  function defineSupacloudConfig(config = {}) {
24960
+ if (config.databaseGovernance !== undefined)
24961
+ assertDatabaseGovernance(config.databaseGovernance);
24849
24962
  if (config.delivery !== undefined)
24850
24963
  parseDeliveryOptions(config.delivery);
24851
24964
  if (config.graphql !== undefined && config.graphql !== false)
@@ -24945,8 +25058,8 @@ function validateGovernanceConfig(config) {
24945
25058
  function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
24946
25059
  const resolved = defineSupacloudConfig(config);
24947
25060
  return {
24948
- rootDir: resolve20(cwd, resolved.root ?? DEFAULT_SUPACLOUD_CONFIG.root),
24949
- outDir: resolve20(cwd, resolved.outDir ?? DEFAULT_SUPACLOUD_CONFIG.outDir),
25061
+ rootDir: resolve21(cwd, resolved.root ?? DEFAULT_SUPACLOUD_CONFIG.root),
25062
+ outDir: resolve21(cwd, resolved.outDir ?? DEFAULT_SUPACLOUD_CONFIG.outDir),
24950
25063
  include: resolved.include ?? [...DEFAULT_SUPACLOUD_CONFIG.include],
24951
25064
  strict: resolved.strict ?? DEFAULT_SUPACLOUD_CONFIG.strict,
24952
25065
  requireRouteContracts: resolved.requireRouteContracts ?? DEFAULT_SUPACLOUD_CONFIG.requireRouteContracts,
@@ -24958,6 +25071,12 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
24958
25071
  commandCapabilities: resolved.commandCapabilities ?? DEFAULT_SUPACLOUD_CONFIG.commandCapabilities,
24959
25072
  ...resolved.moduleBoundaries ? { moduleBoundaries: resolved.moduleBoundaries } : {},
24960
25073
  ...resolved.typeSafety ? { typeSafety: resolved.typeSafety } : {},
25074
+ ...resolved.databaseGovernance === undefined ? {} : {
25075
+ databaseGovernance: {
25076
+ ...resolved.databaseGovernance,
25077
+ projectRoot: resolve21(cwd, resolved.databaseGovernance.projectRoot ?? ".")
25078
+ }
25079
+ },
24961
25080
  ...resolved.allowRouteCommandBindings === undefined ? {} : { allowRouteCommandBindings: resolved.allowRouteCommandBindings },
24962
25081
  ...resolved.disallowControllerDirectDb === undefined ? {} : { disallowControllerDirectDb: resolved.disallowControllerDirectDb },
24963
25082
  ...resolved.detectOrphanModules === undefined ? {} : { detectOrphanModules: resolved.detectOrphanModules },
@@ -24965,7 +25084,7 @@ function resolveSupacloudConfig(config = {}, cwd = process.cwd()) {
24965
25084
  treeShakeUnusedProviders: resolved.treeShakeUnusedProviders ?? DEFAULT_SUPACLOUD_CONFIG.treeShakeUnusedProviders,
24966
25085
  ...resolved.graphql === undefined || resolved.graphql === false ? {} : { graphql: {
24967
25086
  ...resolved.graphql,
24968
- schema: resolve20(cwd, resolved.graphql.schema)
25087
+ schema: resolve21(cwd, resolved.graphql.schema)
24969
25088
  } }
24970
25089
  };
24971
25090
  }
@@ -24994,7 +25113,7 @@ init_graphql_schema();
24994
25113
  // src/graphql-governance.ts
24995
25114
  init_graphql_schema_hashes();
24996
25115
  import { readFile as readFile13 } from "node:fs/promises";
24997
- import { resolve as resolve22 } from "node:path";
25116
+ import { resolve as resolve23 } from "node:path";
24998
25117
  import {
24999
25118
  buildClientSchema as buildClientSchema2,
25000
25119
  buildSchema as buildSchema2,
@@ -25014,7 +25133,7 @@ function schemaFromSource(source, path = "schema.graphql") {
25014
25133
  return buildSchema2(source);
25015
25134
  }
25016
25135
  async function readGraphqlSchema(path) {
25017
- const absolute = resolve22(path);
25136
+ const absolute = resolve23(path);
25018
25137
  const source = await readFile13(absolute, "utf8");
25019
25138
  const hashes = graphqlSchemaHashes(source);
25020
25139
  return { path: absolute, source, schema: schemaFromSource(source, absolute), ...hashes };