@sequenceholdings/orm 2.1.1 → 2.2.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 (68) hide show
  1. package/README.md +3 -1
  2. package/dist/authoring.cjs +284 -99
  3. package/dist/authoring.cjs.map +1 -1
  4. package/dist/authoring.d.cts +31 -8
  5. package/dist/authoring.d.ts +31 -8
  6. package/dist/authoring.js +282 -100
  7. package/dist/authoring.js.map +1 -1
  8. package/dist/canonical.cjs +51 -3
  9. package/dist/canonical.cjs.map +1 -1
  10. package/dist/canonical.d.cts +838 -12
  11. package/dist/canonical.d.ts +838 -12
  12. package/dist/canonical.js +47 -4
  13. package/dist/canonical.js.map +1 -1
  14. package/dist/cli.cjs +5838 -4197
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.js +5838 -4197
  17. package/dist/cli.js.map +1 -1
  18. package/dist/client.cjs +49 -32
  19. package/dist/client.cjs.map +1 -1
  20. package/dist/client.d.cts +49 -6
  21. package/dist/client.d.ts +49 -6
  22. package/dist/client.js +49 -32
  23. package/dist/client.js.map +1 -1
  24. package/dist/compiler.cjs +1237 -263
  25. package/dist/compiler.cjs.map +1 -1
  26. package/dist/compiler.d.cts +57 -3
  27. package/dist/compiler.d.ts +57 -3
  28. package/dist/compiler.js +1230 -264
  29. package/dist/compiler.js.map +1 -1
  30. package/dist/{constants-YoFGjIBM.d.cts → constants-C6EG6Wq7.d.cts} +1 -1
  31. package/dist/{constants-YoFGjIBM.d.ts → constants-C6EG6Wq7.d.ts} +1 -1
  32. package/dist/definition-DjfC7Lll.d.cts +91 -0
  33. package/dist/definition-DjfC7Lll.d.ts +91 -0
  34. package/dist/dynamic-input.cjs +2 -1
  35. package/dist/dynamic-input.cjs.map +1 -1
  36. package/dist/dynamic-input.d.cts +9 -2
  37. package/dist/dynamic-input.d.ts +9 -2
  38. package/dist/dynamic-input.js +2 -1
  39. package/dist/dynamic-input.js.map +1 -1
  40. package/dist/index.cjs +1094 -321
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +479 -19
  43. package/dist/index.d.ts +479 -19
  44. package/dist/index.js +1083 -322
  45. package/dist/index.js.map +1 -1
  46. package/dist/ir.cjs +84 -10
  47. package/dist/ir.cjs.map +1 -1
  48. package/dist/ir.d.cts +138 -13
  49. package/dist/ir.d.ts +138 -13
  50. package/dist/ir.js +81 -11
  51. package/dist/ir.js.map +1 -1
  52. package/dist/predicate-v2.cjs +78 -9
  53. package/dist/predicate-v2.cjs.map +1 -1
  54. package/dist/predicate-v2.d.cts +1 -1
  55. package/dist/predicate-v2.d.ts +1 -1
  56. package/dist/predicate-v2.js +78 -9
  57. package/dist/predicate-v2.js.map +1 -1
  58. package/dist/sdl.cjs +156 -21
  59. package/dist/sdl.cjs.map +1 -1
  60. package/dist/sdl.d.cts +8 -1
  61. package/dist/sdl.d.ts +8 -1
  62. package/dist/sdl.js +156 -21
  63. package/dist/sdl.js.map +1 -1
  64. package/package.json +5 -4
  65. package/src/codegen-gql/server-fns.cjs +2 -2
  66. package/templates/orm-namespace/AGENTS.md +10 -0
  67. package/templates/orm-namespace/CLAUDE.md +1 -84
  68. package/templates/orm-namespace/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -165,8 +165,8 @@ var COLUMN_IDENTIFIER_PATTERN = /^_?[a-z][a-z0-9_]*$/;
165
165
  var MAX_IDENTIFIER_LENGTH = 63;
166
166
  var CAPABILITY_KEY_PATTERN = /^(?:org\/|app\/[a-z][a-z0-9-]{0,63}\/)?[a-z0-9-]{1,64}$/;
167
167
  var CLAIM_KEY_PATTERN = /^[a-z][a-z0-9_]*$/;
168
- var QUALIFIED_TABLE_PATTERN = /^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$/;
169
- var SYNCED_SOURCE_PATTERN = /^gold\.[a-z][a-z0-9_]*$/;
168
+ var QUALIFIED_TABLE_PATTERN = /^[a-z][a-z0-9_]{0,62}\.[a-z][a-z0-9_]{0,62}$/;
169
+ var SYNCED_SOURCE_PATTERN = QUALIFIED_TABLE_PATTERN;
170
170
  var ORM_SCHEMA_PREFIX = "orm_";
171
171
  var CONSUMER_ROLE_SUFFIX = "_consumer";
172
172
  var ormSchemaName = (namespace) => `${ORM_SCHEMA_PREFIX}${namespace}`;
@@ -267,6 +267,9 @@ function registerNamespaceConfig(value) {
267
267
  // src/authoring/table.ts
268
268
  var TABLE_BRAND = "seq-table";
269
269
  var LINK_BRAND = "seq-link";
270
+ function objectRef(namespace, table) {
271
+ return { kind: "seq-external-object", namespace, table };
272
+ }
270
273
  function toOne(target, options) {
271
274
  return {
272
275
  kind: LINK_BRAND,
@@ -320,51 +323,51 @@ function assertIdentifier({ value, what, file, pattern = IDENTIFIER_PATTERN }) {
320
323
  );
321
324
  }
322
325
  }
323
- function defineTable(name, columns, config = {}) {
326
+ function defineTable(name2, columns, config = {}) {
324
327
  const file = activeAuthoringContext()?.currentFile;
325
- assertIdentifier({ value: name, what: "table name", file });
328
+ assertIdentifier({ value: name2, what: "table name", file });
326
329
  const entries = Object.entries(columns);
327
330
  if (entries.length === 0) {
328
- throw new OrmDefinitionError(`table "${name}" declares no columns`, file);
331
+ throw new OrmDefinitionError(`table "${name2}" declares no columns`, file);
329
332
  }
330
333
  const seenColumnNames = /* @__PURE__ */ new Map();
331
334
  for (const [propertyName, builder] of entries) {
332
335
  if (!isColumnBuilder(builder)) {
333
336
  throw new OrmDefinitionError(
334
- `table "${name}": column "${propertyName}" is not a column builder \u2014 use the t.* factories (t.uuid(), t.text(), \u2026)`,
337
+ `table "${name2}": column "${propertyName}" is not a column builder \u2014 use the t.* factories (t.uuid(), t.text(), \u2026)`,
335
338
  file
336
339
  );
337
340
  }
338
341
  const columnName = builder.columnNameFor(propertyName);
339
- assertIdentifier({ value: columnName, what: `table "${name}": column "${propertyName}" column name`, file, pattern: COLUMN_IDENTIFIER_PATTERN });
342
+ assertIdentifier({ value: columnName, what: `table "${name2}": column "${propertyName}" column name`, file, pattern: COLUMN_IDENTIFIER_PATTERN });
340
343
  if (config.materializes === void 0 && (propertyName === CELLS_FIELD || Object.values(CELL_PART_SUFFIX).some((suffix) => columnName.endsWith(suffix) || propertyName.endsWith(suffix)))) {
341
344
  throw new OrmDefinitionError(
342
- `table "${name}": "${propertyName}" collides with the reserved cell-metadata names ('${CELLS_FIELD}', or a ${Object.values(CELL_PART_SUFFIX).join("/")} suffix)`,
345
+ `table "${name2}": "${propertyName}" collides with the reserved cell-metadata names ('${CELLS_FIELD}', or a ${Object.values(CELL_PART_SUFFIX).join("/")} suffix)`,
343
346
  file
344
347
  );
345
348
  }
346
349
  const existing = seenColumnNames.get(columnName);
347
350
  if (existing !== void 0) {
348
351
  throw new OrmDefinitionError(
349
- `table "${name}": columns "${existing}" and "${propertyName}" both map to Postgres column "${columnName}"`,
352
+ `table "${name2}": columns "${existing}" and "${propertyName}" both map to Postgres column "${columnName}"`,
350
353
  file
351
354
  );
352
355
  }
353
356
  seenColumnNames.set(columnName, propertyName);
354
357
  }
355
- const table = { kind: TABLE_BRAND, tableName: name, columns, config, source: void 0, file };
358
+ const table = { kind: TABLE_BRAND, tableName: name2, columns, config, source: void 0, file };
356
359
  registerTable(table);
357
360
  return table;
358
361
  }
359
- function defineSyncedTable(name, columnsOrConfig, maybeConfig) {
362
+ function defineSyncedTable(name2, columnsOrConfig, maybeConfig) {
360
363
  const file = activeAuthoringContext()?.currentFile;
361
- assertIdentifier({ value: name, what: "table name", file });
364
+ assertIdentifier({ value: name2, what: "table name", file });
362
365
  const isTyped = maybeConfig !== void 0;
363
366
  const columns = isTyped ? columnsOrConfig : {};
364
367
  const config = isTyped ? maybeConfig : columnsOrConfig;
365
368
  if (!SYNCED_SOURCE_PATTERN.test(config.source)) {
366
369
  throw new OrmDefinitionError(
367
- `synced table "${name}": source "${config.source}" must match ${SYNCED_SOURCE_PATTERN} (gold layer only)`,
370
+ `synced table "${name2}": source "${config.source}" must be a qualified lowercase schema.table identifier`,
368
371
  file
369
372
  );
370
373
  }
@@ -374,21 +377,21 @@ function defineSyncedTable(name, columnsOrConfig, maybeConfig) {
374
377
  for (const [propertyName, builder] of entries) {
375
378
  if (!isColumnBuilder(builder)) {
376
379
  throw new OrmDefinitionError(
377
- `synced table "${name}": column "${propertyName}" is not a column builder \u2014 use the t.* factories (t.uuid(), t.text(), \u2026)`,
380
+ `synced table "${name2}": column "${propertyName}" is not a column builder \u2014 use the t.* factories (t.uuid(), t.text(), \u2026)`,
378
381
  file
379
382
  );
380
383
  }
381
384
  const columnName = builder.columnNameFor(propertyName);
382
385
  assertIdentifier({
383
386
  value: columnName,
384
- what: `synced table "${name}": column "${propertyName}" column name`,
387
+ what: `synced table "${name2}": column "${propertyName}" column name`,
385
388
  file,
386
389
  pattern: COLUMN_IDENTIFIER_PATTERN
387
390
  });
388
391
  const existing = seenColumnNames.get(columnName);
389
392
  if (existing !== void 0) {
390
393
  throw new OrmDefinitionError(
391
- `synced table "${name}": columns "${existing}" and "${propertyName}" both map to Postgres column "${columnName}"`,
394
+ `synced table "${name2}": columns "${existing}" and "${propertyName}" both map to Postgres column "${columnName}"`,
392
395
  file
393
396
  );
394
397
  }
@@ -399,13 +402,13 @@ function defineSyncedTable(name, columnsOrConfig, maybeConfig) {
399
402
  const hasConfigPk = config.primaryKey !== void 0 && config.primaryKey.length > 0;
400
403
  if (columnLevelPk.length === 0 && !hasConfigPk) {
401
404
  throw new OrmDefinitionError(
402
- `synced table "${name}" declares columns but no primary key \u2014 use .primaryKey() or config.primaryKey`,
405
+ `synced table "${name2}" declares columns but no primary key \u2014 use .primaryKey() or config.primaryKey`,
403
406
  file
404
407
  );
405
408
  }
406
409
  if (columnLevelPk.length > 0 && hasConfigPk) {
407
410
  throw new OrmDefinitionError(
408
- `synced table "${name}": declare the primary key either with .primaryKey() on columns or with config.primaryKey \u2014 not both`,
411
+ `synced table "${name2}": declare the primary key either with .primaryKey() on columns or with config.primaryKey \u2014 not both`,
409
412
  file
410
413
  );
411
414
  }
@@ -417,7 +420,7 @@ function defineSyncedTable(name, columnsOrConfig, maybeConfig) {
417
420
  if (config.policies !== void 0) tableConfig.policies = { read: config.policies.read };
418
421
  const table = {
419
422
  kind: TABLE_BRAND,
420
- tableName: name,
423
+ tableName: name2,
421
424
  columns,
422
425
  config: tableConfig,
423
426
  source: config.source,
@@ -426,26 +429,26 @@ function defineSyncedTable(name, columnsOrConfig, maybeConfig) {
426
429
  registerTable(table);
427
430
  return table;
428
431
  }
429
- function defineEnum(name, values) {
432
+ function defineEnum(name2, values) {
430
433
  const file = activeAuthoringContext()?.currentFile;
431
- assertIdentifier({ value: name, what: "enum name", file });
434
+ assertIdentifier({ value: name2, what: "enum name", file });
432
435
  if (values.length === 0 || values.length > 100) {
433
- throw new OrmDefinitionError(`enum "${name}" must declare between 1 and 100 values`, file);
436
+ throw new OrmDefinitionError(`enum "${name2}" must declare between 1 and 100 values`, file);
434
437
  }
435
438
  const seen = /* @__PURE__ */ new Set();
436
439
  for (const value of values) {
437
440
  if (value.length === 0 || value.length > MAX_IDENTIFIER_LENGTH) {
438
441
  throw new OrmDefinitionError(
439
- `enum "${name}": value ${JSON.stringify(value)} must be 1-${MAX_IDENTIFIER_LENGTH} characters`,
442
+ `enum "${name2}": value ${JSON.stringify(value)} must be 1-${MAX_IDENTIFIER_LENGTH} characters`,
440
443
  file
441
444
  );
442
445
  }
443
446
  if (seen.has(value)) {
444
- throw new OrmDefinitionError(`enum "${name}" declares duplicate value "${value}"`, file);
447
+ throw new OrmDefinitionError(`enum "${name2}" declares duplicate value "${value}"`, file);
445
448
  }
446
449
  seen.add(value);
447
450
  }
448
- const ref = { kind: ENUM_BRAND, name, values: [...values] };
451
+ const ref = { kind: ENUM_BRAND, name: name2, values: [...values] };
449
452
  registerEnum(ref);
450
453
  return ref;
451
454
  }
@@ -453,52 +456,52 @@ var VIEW_BRAND = "seq-view";
453
456
  function isSeqView(value) {
454
457
  return typeof value === "object" && value !== null && value.kind === VIEW_BRAND;
455
458
  }
456
- function defineView(name, columns, config) {
459
+ function defineView(name2, columns, config) {
457
460
  const file = activeAuthoringContext()?.currentFile;
458
- if (!IDENTIFIER_PATTERN.test(name) || name.length > MAX_IDENTIFIER_LENGTH) {
461
+ if (!IDENTIFIER_PATTERN.test(name2) || name2.length > MAX_IDENTIFIER_LENGTH) {
459
462
  throw new OrmDefinitionError(
460
- `view name "${name}" must match ${IDENTIFIER_PATTERN} and be at most ${MAX_IDENTIFIER_LENGTH} characters`,
463
+ `view name "${name2}" must match ${IDENTIFIER_PATTERN} and be at most ${MAX_IDENTIFIER_LENGTH} characters`,
461
464
  file
462
465
  );
463
466
  }
464
467
  const entries = Object.entries(columns);
465
- if (entries.length === 0) throw new OrmDefinitionError(`view "${name}" declares no columns`, file);
468
+ if (entries.length === 0) throw new OrmDefinitionError(`view "${name2}" declares no columns`, file);
466
469
  const seenColumnNames = /* @__PURE__ */ new Map();
467
470
  for (const [propertyName, builder] of entries) {
468
471
  if (!isColumnBuilder(builder)) {
469
472
  throw new OrmDefinitionError(
470
- `view "${name}": column "${propertyName}" is not a column builder \u2014 use the t.* factories`,
473
+ `view "${name2}": column "${propertyName}" is not a column builder \u2014 use the t.* factories`,
471
474
  file
472
475
  );
473
476
  }
474
477
  const columnName = builder.columnNameFor(propertyName);
475
478
  if (!COLUMN_IDENTIFIER_PATTERN.test(columnName) || columnName.length > MAX_IDENTIFIER_LENGTH) {
476
- throw new OrmDefinitionError(`view "${name}": column "${propertyName}" has invalid column name "${columnName}"`, file);
479
+ throw new OrmDefinitionError(`view "${name2}": column "${propertyName}" has invalid column name "${columnName}"`, file);
477
480
  }
478
481
  const existing = seenColumnNames.get(columnName);
479
482
  if (existing !== void 0) {
480
483
  throw new OrmDefinitionError(
481
- `view "${name}": columns "${existing}" and "${propertyName}" both map to Postgres column "${columnName}"`,
484
+ `view "${name2}": columns "${existing}" and "${propertyName}" both map to Postgres column "${columnName}"`,
482
485
  file
483
486
  );
484
487
  }
485
488
  seenColumnNames.set(columnName, propertyName);
486
489
  }
487
- const view = { kind: VIEW_BRAND, viewName: name, columns, config, file };
490
+ const view = { kind: VIEW_BRAND, viewName: name2, columns, config, file };
488
491
  registerView(view);
489
492
  return view;
490
493
  }
491
494
  var QUERY_COLUMN_FACTORIES = {
492
- uuid: (name) => pgCore.uuid(name),
493
- text: (name) => pgCore.text(name),
494
- integer: (name) => pgCore.integer(name),
495
- bigint: (name) => pgCore.bigint(name, { mode: "bigint" }),
496
- numeric: (name) => pgCore.numeric(name),
497
- double: (name) => pgCore.doublePrecision(name),
498
- boolean: (name) => pgCore.boolean(name),
499
- timestamptz: (name) => pgCore.timestamp(name, { withTimezone: true }),
500
- date: (name) => pgCore.date(name),
501
- jsonb: (name) => pgCore.jsonb(name)
495
+ uuid: (name2) => pgCore.uuid(name2),
496
+ text: (name2) => pgCore.text(name2),
497
+ integer: (name2) => pgCore.integer(name2),
498
+ bigint: (name2) => pgCore.bigint(name2, { mode: "bigint" }),
499
+ numeric: (name2) => pgCore.numeric(name2),
500
+ double: (name2) => pgCore.doublePrecision(name2),
501
+ boolean: (name2) => pgCore.boolean(name2),
502
+ timestamptz: (name2) => pgCore.timestamp(name2, { withTimezone: true }),
503
+ date: (name2) => pgCore.date(name2),
504
+ jsonb: (name2) => pgCore.jsonb(name2)
502
505
  };
503
506
  function compileViewQueries(input) {
504
507
  const schemaName = `orm_${input.namespace}`;
@@ -554,9 +557,9 @@ function compileViewQueries(input) {
554
557
  }
555
558
  const handle = handles.get(resolved);
556
559
  if (!handle) {
557
- const name = isSeqTable(resolved) ? resolved.tableName : resolved.viewName;
560
+ const name2 = isSeqTable(resolved) ? resolved.tableName : resolved.viewName;
558
561
  throw new OrmDefinitionError(
559
- `view "${authored.viewName}" references relation "${name}" which is not part of this namespace`,
562
+ `view "${authored.viewName}" references relation "${name2}" which is not part of this namespace`,
560
563
  authored.file
561
564
  );
562
565
  }
@@ -747,8 +750,8 @@ function overlayWinsUnion(input) {
747
750
  // src/authoring/cow-mutations.ts
748
751
  function overrideRowMutation(input) {
749
752
  const { overlay, synced, pk } = input;
750
- const name = input.name ?? `override_${overlay.tableName}`;
751
- assertMutationName(name, "overrideRowMutation");
753
+ const name2 = input.name ?? `override_${overlay.tableName}`;
754
+ assertMutationName(name2, "overrideRowMutation");
752
755
  assertOverlayPairPrimaryKey({ overlay, synced, pk, helper: "overrideRowMutation" });
753
756
  const sharedProperties = sharedNonPkProperties({ overlay, synced, pk });
754
757
  const setProperties = resolveSetProperties({
@@ -767,7 +770,7 @@ function overrideRowMutation(input) {
767
770
  });
768
771
  return {
769
772
  kind: "override",
770
- name,
773
+ name: name2,
771
774
  synced: synced.tableName,
772
775
  pk,
773
776
  copy: [pk, ...sharedProperties],
@@ -776,23 +779,23 @@ function overrideRowMutation(input) {
776
779
  }
777
780
  function revertOverlayMutation(input) {
778
781
  const { overlay, synced, pk } = input;
779
- const name = input.name ?? `revert_${overlay.tableName}`;
780
- assertMutationName(name, "revertOverlayMutation");
782
+ const name2 = input.name ?? `revert_${overlay.tableName}`;
783
+ assertMutationName(name2, "revertOverlayMutation");
781
784
  assertOverlayPairPrimaryKey({ overlay, synced, pk, helper: "revertOverlayMutation" });
782
785
  assertMatchingColumns({ overlay, synced, properties: [pk], helper: "revertOverlayMutation" });
783
786
  return {
784
787
  kind: "revert",
785
- name,
788
+ name: name2,
786
789
  synced: synced.tableName,
787
790
  pk,
788
791
  copy: [],
789
792
  set: []
790
793
  };
791
794
  }
792
- function assertMutationName(name, helper) {
793
- if (!IDENTIFIER_PATTERN.test(name) || name.length > MAX_IDENTIFIER_LENGTH) {
795
+ function assertMutationName(name2, helper) {
796
+ if (!IDENTIFIER_PATTERN.test(name2) || name2.length > MAX_IDENTIFIER_LENGTH) {
794
797
  throw new OrmDefinitionError(
795
- `${helper}: mutation name "${name}" must match ${IDENTIFIER_PATTERN} and be at most ${MAX_IDENTIFIER_LENGTH} characters`
798
+ `${helper}: mutation name "${name2}" must match ${IDENTIFIER_PATTERN} and be at most ${MAX_IDENTIFIER_LENGTH} characters`
796
799
  );
797
800
  }
798
801
  }
@@ -918,17 +921,35 @@ function scalarColumnType(table, property, helper) {
918
921
  }
919
922
  return type;
920
923
  }
924
+ var objectRef2 = zod.z.string().max(255).regex(/^[a-z][a-z0-9_]{0,40}\/[A-Za-z_][A-Za-z0-9_]*$/, "Expected an explicit namespace/object reference (no wildcards)");
925
+ var functionRef = zod.z.string().max(255).regex(/^[a-z][a-z0-9-]*$/, "Expected a function slug");
926
+ var refs = (schema) => zod.z.array(schema).max(256).refine(
927
+ (values) => new Set(values).size === values.length,
928
+ "Duplicate dependency reference"
929
+ ).default([]);
930
+ var ontologyContractSchema = zod.z.strictObject({
931
+ version: zod.z.literal(1),
932
+ read: refs(objectRef2),
933
+ write: refs(objectRef2),
934
+ produce: refs(objectRef2),
935
+ invoke: refs(functionRef)
936
+ }).refine((contract) => JSON.stringify(contract).length <= 4096, "Ontology contract exceeds the 4 KiB signed-context budget");
937
+ function readOntologyContract(manifest) {
938
+ if (!manifest || typeof manifest !== "object" || !("ontology" in manifest) || manifest.ontology === void 0) return void 0;
939
+ return ontologyContractSchema.parse(manifest.ontology);
940
+ }
921
941
 
922
942
  // src/compiler/sql.ts
923
943
  var CLAIMS_SETTING = "request.jwt.claims";
924
944
  var CAPABILITIES_CLAIM_KEY = "capabilities";
925
945
  var ROLES_CLAIM_KEY = "roles";
926
- var quoteIdentifier = (name) => `"${name.replaceAll('"', '""')}"`;
946
+ var quoteIdentifier = (name2) => `"${name2.replaceAll('"', '""')}"`;
927
947
  var quoteLiteral = (value) => `'${value.replaceAll("'", "''")}'`;
928
948
  var CLAIMS_SOURCE = `nullif(current_setting('${CLAIMS_SETTING}', true), '')::jsonb`;
929
949
  var claimExpression = (key) => `(${CLAIMS_SOURCE} ->> ${quoteLiteral(key)})`;
930
- var capabilityExpression = (key) => `coalesce(${CLAIMS_SOURCE} -> '${CAPABILITIES_CLAIM_KEY}' ? ${quoteLiteral(key)}, false)`;
931
- var roleExpression = (key) => `coalesce(${CLAIMS_SOURCE} -> '${ROLES_CLAIM_KEY}' ? ${quoteLiteral(key)}, false)`;
950
+ var scopedClaimsSource = (namespace) => namespace ? `(CASE WHEN ${CLAIMS_SOURCE} ? 'namespaces' THEN ${CLAIMS_SOURCE} -> 'namespaces' -> ${quoteLiteral(namespace)} ELSE ${CLAIMS_SOURCE} END)` : CLAIMS_SOURCE;
951
+ var capabilityExpression = (key, namespace) => `coalesce(${scopedClaimsSource(namespace)} -> '${CAPABILITIES_CLAIM_KEY}' ? ${quoteLiteral(key)}, false)`;
952
+ var roleExpression = (key, namespace) => `coalesce(${scopedClaimsSource(namespace)} -> '${ROLES_CLAIM_KEY}' ? ${quoteLiteral(key)}, false)`;
932
953
 
933
954
  // src/checks/compile.ts
934
955
  function tokenize(source) {
@@ -1261,8 +1282,8 @@ function validateResolvedView({ view, tables, views = [] }) {
1261
1282
  validateRules(scope);
1262
1283
  validateViewCells(scope);
1263
1284
  if (resolved.materialized) validateMaterialized({ scope, tableByName, views });
1264
- for (const name of resolved.deletedBy) {
1265
- if (scope.sourceByName.get(name)?.kind !== "manual") fail(`deletedBy '${name}' must be the manual source`);
1285
+ for (const name2 of resolved.deletedBy) {
1286
+ if (scope.sourceByName.get(name2)?.kind !== "manual") fail(`deletedBy '${name2}' must be the manual source`);
1266
1287
  }
1267
1288
  return errors;
1268
1289
  }
@@ -1359,7 +1380,7 @@ function validateViewCells({ view, dataColumns, pkColumn, fail }) {
1359
1380
  if (column.type !== VIEW_CELL_TYPES[column.cell.part]) fail(`cell column '${column.name}' must be ${VIEW_CELL_TYPES[column.cell.part]}`);
1360
1381
  expected.delete(column.name);
1361
1382
  }
1362
- for (const name of expected.keys()) fail(`missing cell column '${name}'`);
1383
+ for (const name2 of expected.keys()) fail(`missing cell column '${name2}'`);
1363
1384
  }
1364
1385
  var columnSignature = (columns) => JSON.stringify(columns.map((column) => [column.name, column.columnName, column.type]));
1365
1386
  function validateMaterialized({ scope, tableByName, views }) {
@@ -1450,6 +1471,8 @@ var canonicalLinkSchema = zod.z.object({
1450
1471
  kind: zod.z.enum(["toOne", "toMany", "toPlatformUser"]),
1451
1472
  /** Target table name (namespace-local). Absent for toPlatformUser. */
1452
1473
  target: identifier2.optional(),
1474
+ /** Owning namespace of an imported target; omitted for local links. */
1475
+ namespace: identifier2.max(41).optional(),
1453
1476
  /** FK column on the owning side (toOne/toPlatformUser: on this table; toMany: on the target). */
1454
1477
  on: columnIdentifier,
1455
1478
  /** Referenced column on the target (default: target's PK / platform user `sub`). */
@@ -1708,11 +1731,12 @@ var canonicalForeignKeySchema = zod.z.object({
1708
1731
  }).strict();
1709
1732
  var canonicalTableSchema = zod.z.object({
1710
1733
  table: identifier2,
1734
+ displayName: zod.z.string().trim().min(1).max(120).optional(),
1711
1735
  description: zod.z.string().max(2e3).optional(),
1712
1736
  /** Table-level rename hint (new in v2). */
1713
1737
  renamedFrom: identifier2.optional(),
1714
- /** Synced/reflected read-only tables (`source: gold.*`) — v1 semantics. */
1715
- source: zod.z.string().regex(/^gold\.[a-z][a-z0-9_]*$/).optional(),
1738
+ /** Synced/reflected read-only tables (`source: schema.table`) — v1 semantics. */
1739
+ source: zod.z.string().regex(QUALIFIED_TABLE_PATTERN).optional(),
1716
1740
  columns: zod.z.array(canonicalColumnSchema).default([]),
1717
1741
  primaryKey: zod.z.array(columnIdentifier).min(1).max(8).optional(),
1718
1742
  links: zod.z.array(canonicalLinkSchema).default([]),
@@ -1865,7 +1889,9 @@ function validateCellMetadata(table, index3, ctx) {
1865
1889
  }
1866
1890
  }
1867
1891
  }
1868
- var canonicalDefinitionSchema = zod.z.object({
1892
+ var exportGateSchema = zod.z.union([zod.z.literal(true), zod.z.object({ capability: zod.z.string().min(1) }).strict(), zod.z.object({ role: zod.z.string().min(1) }).strict()]);
1893
+ var relationExportSchema = zod.z.object({ read: exportGateSchema, write: exportGateSchema.optional() }).strict();
1894
+ var localDefinitionSchema = zod.z.object({
1869
1895
  definition_format: zod.z.literal(CANONICAL_FORMAT),
1870
1896
  namespace: identifier2.max(41),
1871
1897
  description: zod.z.string().max(2e3).optional(),
@@ -1873,6 +1899,8 @@ var canonicalDefinitionSchema = zod.z.object({
1873
1899
  tables: zod.z.array(canonicalTableSchema).min(0).max(500),
1874
1900
  /** Optional to preserve byte-identical hashes for pre-view canonical v2 documents. */
1875
1901
  views: zod.z.array(canonicalViewSchema).max(500).optional(),
1902
+ /** Target-owned cross-namespace access contract, using existing namespace grants. */
1903
+ exports: zod.z.record(identifier2, relationExportSchema).optional(),
1876
1904
  /** Verbatim custom-roles grammar (@sequenceholdings/custom-roles-manifest). */
1877
1905
  capabilities: zod.z.object({
1878
1906
  roles: zod.z.unknown().optional(),
@@ -1899,7 +1927,16 @@ var canonicalDefinitionSchema = zod.z.object({
1899
1927
  }
1900
1928
  }
1901
1929
  const fkTables = new Map(definition.tables.map((table) => [table.table, table]));
1930
+ const relations = /* @__PURE__ */ new Set([...fkTables.keys(), ...(definition.views ?? []).map((view) => view.view)]);
1931
+ for (const name2 of Object.keys(definition.exports ?? {})) {
1932
+ if (!relations.has(name2)) ctx.addIssue({ code: "custom", path: ["exports", name2], message: `export '${name2}' is not a local object` });
1933
+ }
1902
1934
  for (const [tableIndex, table] of definition.tables.entries()) {
1935
+ for (const [linkIndex, link] of table.links.entries()) {
1936
+ if (link.enforce && link.namespace !== void 0 && link.namespace !== definition.namespace) {
1937
+ ctx.addIssue({ code: "custom", path: ["tables", tableIndex, "links", linkIndex], message: "physical foreign keys require a local target; use an ORM link without enforce" });
1938
+ }
1939
+ }
1903
1940
  const names = /* @__PURE__ */ new Set([
1904
1941
  ...table.primaryKey?.length ? [`${table.table}_pkey`] : [],
1905
1942
  ...table.columns.filter((column) => column.unique && !(table.primaryKey?.length === 1 && table.primaryKey[0] === column.columnName)).map((column) => `${table.table}_${column.columnName}_unique`),
@@ -1936,14 +1973,14 @@ var canonicalDefinitionSchema = zod.z.object({
1936
1973
  }
1937
1974
  if (fk.columns.length !== fk.references.length) fail("foreign key columns and references must have the same number of columns");
1938
1975
  if (new Set(fk.columns).size !== fk.columns.length || new Set(fk.references).size !== fk.references.length) fail("foreign key columns must not repeat");
1939
- for (const [position, name] of fk.columns.entries()) {
1940
- const sourceColumn = table.columns.find((column) => column.columnName === name);
1976
+ for (const [position, name2] of fk.columns.entries()) {
1977
+ const sourceColumn = table.columns.find((column) => column.columnName === name2);
1941
1978
  const targetColumn = target.columns.find((column) => column.columnName === fk.references[position]);
1942
1979
  if (!sourceColumn || !targetColumn) fail("foreign key references an unknown column");
1943
1980
  else if (JSON.stringify(sourceColumn.type) !== JSON.stringify(targetColumn.type)) fail("foreign key column types must match");
1944
1981
  }
1945
1982
  if (fk.onDelete === "set null" || fk.onUpdate === "set null") {
1946
- if (fk.columns.some((name) => table.columns.find((column) => column.columnName === name)?.nullable === false || table.primaryKey?.includes(name))) fail("SET NULL requires nullable source columns");
1983
+ if (fk.columns.some((name2) => table.columns.find((column) => column.columnName === name2)?.nullable === false || table.primaryKey?.includes(name2))) fail("SET NULL requires nullable source columns");
1947
1984
  }
1948
1985
  const uniqueKeys = [target.primaryKey ?? [], ...target.indexes.filter((index4) => index4.unique).map((index4) => index4.columns), ...target.columns.filter((column) => column.unique).map((column) => [column.columnName])];
1949
1986
  if (!uniqueKeys.some((key) => key.length === fk.references.length && key.every((column) => fk.references.includes(column)))) fail("foreign key target columns must form a unique key");
@@ -2048,27 +2085,31 @@ var canonicalDefinitionSchema = zod.z.object({
2048
2085
  const visiting = /* @__PURE__ */ new Set();
2049
2086
  const visited = /* @__PURE__ */ new Set();
2050
2087
  let cycleReported = false;
2051
- const visit = (name, path) => {
2052
- if (visited.has(name) || cycleReported) return;
2053
- if (visiting.has(name)) {
2088
+ const visit = (name2, path) => {
2089
+ if (visited.has(name2) || cycleReported) return;
2090
+ if (visiting.has(name2)) {
2054
2091
  cycleReported = true;
2055
2092
  ctx.addIssue({
2056
2093
  code: "custom",
2057
2094
  path: ["views"],
2058
- message: `view dependencies form a cycle: ${[...path, name].join(" -> ")}`
2095
+ message: `view dependencies form a cycle: ${[...path, name2].join(" -> ")}`
2059
2096
  });
2060
2097
  return;
2061
2098
  }
2062
- visiting.add(name);
2063
- const view = viewByName.get(name);
2099
+ visiting.add(name2);
2100
+ const view = viewByName.get(name2);
2064
2101
  for (const dependency of view?.dependencies ?? []) {
2065
- if (viewByName.has(dependency)) visit(dependency, [...path, name]);
2102
+ if (viewByName.has(dependency)) visit(dependency, [...path, name2]);
2066
2103
  }
2067
- visiting.delete(name);
2068
- visited.add(name);
2104
+ visiting.delete(name2);
2105
+ visited.add(name2);
2069
2106
  };
2070
2107
  for (const view of views) visit(view.view, []);
2071
2108
  });
2109
+ var canonicalDefinitionSchema = localDefinitionSchema.safeExtend({
2110
+ /** Flattened, pinned snapshots. Imported relations never participate in this namespace's DDL. */
2111
+ imports: zod.z.array(localDefinitionSchema).max(32).optional()
2112
+ });
2072
2113
  function canonicalRelations(definition) {
2073
2114
  const views = (definition.views ?? []).map((view) => ({
2074
2115
  table: view.view,
@@ -2112,6 +2153,11 @@ function normalizeCanonical(definition) {
2112
2153
  dependencies: [...view.dependencies].sort()
2113
2154
  }));
2114
2155
  }
2156
+ if (definition.imports?.length) {
2157
+ normalized.imports = definition.imports.map(normalizeCanonical).sort((a, b) => a.namespace.localeCompare(b.namespace));
2158
+ } else {
2159
+ delete normalized.imports;
2160
+ }
2115
2161
  return normalized;
2116
2162
  }
2117
2163
 
@@ -2236,8 +2282,8 @@ var literal = (value) => `'${value.replace(/'/g, "''")}'`;
2236
2282
  var physical = ({ source, property }) => source.table.columns[property].columnNameFor(property);
2237
2283
  function candidateSql({ source, column, pk, pgType }) {
2238
2284
  const a = ident(`s_${source.name}`);
2239
- const name = physical({ source, property: column });
2240
- const value = `CAST(${a}.${ident(name)} AS ${pgType})`;
2285
+ const name2 = physical({ source, property: column });
2286
+ const value = `CAST(${a}.${ident(name2)} AS ${pgType})`;
2241
2287
  if (source.kind === "etl") {
2242
2288
  return {
2243
2289
  source: source.name,
@@ -2247,9 +2293,9 @@ function candidateSql({ source, column, pk, pgType }) {
2247
2293
  by: "CAST(NULL AS text)"
2248
2294
  };
2249
2295
  }
2250
- const at = `${a}.${ident(cellColumnName(name, "at"))}`;
2296
+ const at = `${a}.${ident(cellColumnName(name2, "at"))}`;
2251
2297
  const tombstoned2 = source.kind === "prefetch" ? ` AND NOT ${a}.${ident(RESOLVED_SOURCE_SYSTEM_COLUMNS.tombstoned.columnName)}` : "";
2252
- return { source: source.name, value, has: `(${at} IS NOT NULL${tombstoned2})`, at, by: `${a}.${ident(cellColumnName(name, "by"))}` };
2298
+ return { source: source.name, value, has: `(${at} IS NOT NULL${tombstoned2})`, at, by: `${a}.${ident(cellColumnName(name2, "by"))}` };
2253
2299
  }
2254
2300
  function outranks({ i, j, key, direction, inclusive }) {
2255
2301
  const ki = i[key];
@@ -2342,7 +2388,7 @@ function buildResolvedQuery({ context, plan }) {
2342
2388
  plan.rules.forEach((rule, index3) => {
2343
2389
  const canonical = plan.columns[rule.column].toCanonicalColumn(rule.column);
2344
2390
  const pgType = typeof canonical.type === "string" ? PG_TYPE[canonical.type] : `${schema === void 0 ? "" : `${ident(schema)}.`}${ident(canonical.type.enum)}`;
2345
- const candidates = rule.candidates.map((name) => candidateSql({ source: sourceByName.get(name), column: rule.column, pk: plan.pk, pgType }));
2391
+ const candidates = rule.candidates.map((name2) => candidateSql({ source: sourceByName.get(name2), column: rule.column, pk: plan.pk, pgType }));
2346
2392
  cells.set(rule.column, rule.comparator === "custom" ? customCell({ candidates, orderBy: rule.orderBy, index: index3 }) : builtinCell({ comparator: rule.comparator, candidates }));
2347
2393
  });
2348
2394
  const laterals = [...cells.values()].flatMap((cell) => cell.lateral ? [drizzleOrm.sql.raw(cell.lateral)] : []);
@@ -2363,7 +2409,7 @@ function buildResolvedQuery({ context, plan }) {
2363
2409
  const system = RESOLVED_VIEW_SYSTEM_COLUMNS;
2364
2410
  selected[system.writebackStatus.name] = drizzleOrm.sql.raw(`${alias(manual.name)}.${ident(RESOLVED_SOURCE_SYSTEM_COLUMNS.writebackStatus.columnName)}`).as(system.writebackStatus.columnName);
2365
2411
  selected[system.writebackError.name] = drizzleOrm.sql.raw(`${alias(manual.name)}.${ident(RESOLVED_SOURCE_SYSTEM_COLUMNS.writebackError.columnName)}`).as(system.writebackError.columnName);
2366
- const hidden = plan.deletedBy.map((name) => `NOT COALESCE(${alias(name)}.${ident(tombstoned2)}, false)`);
2412
+ const hidden = plan.deletedBy.map((name2) => `NOT COALESCE(${alias(name2)}.${ident(tombstoned2)}, false)`);
2367
2413
  const query = qb.select(selected).from(from);
2368
2414
  return hidden.length > 0 ? query.where(drizzleOrm.sql.raw(hidden.join(" AND "))) : query;
2369
2415
  }
@@ -2389,12 +2435,12 @@ var SYSTEM_VIEW_COLUMNS = {
2389
2435
  [RESOLVED_VIEW_SYSTEM_COLUMNS.writebackStatus.name]: () => t.text(RESOLVED_VIEW_SYSTEM_COLUMNS.writebackStatus.columnName),
2390
2436
  [RESOLVED_VIEW_SYSTEM_COLUMNS.writebackError.name]: () => t.text(RESOLVED_VIEW_SYSTEM_COLUMNS.writebackError.columnName)
2391
2437
  };
2392
- function defineResolvedTable(name, columns, config) {
2438
+ function defineResolvedTable(name2, columns, config) {
2393
2439
  const file = activeAuthoringContext()?.currentFile;
2394
2440
  const fail = (message) => {
2395
- throw new OrmDefinitionError(`resolved table "${name}": ${message}`, file);
2441
+ throw new OrmDefinitionError(`resolved table "${name2}": ${message}`, file);
2396
2442
  };
2397
- if (!IDENTIFIER_PATTERN.test(name)) fail(`name must match ${IDENTIFIER_PATTERN}`);
2443
+ if (!IDENTIFIER_PATTERN.test(name2)) fail(`name must match ${IDENTIFIER_PATTERN}`);
2398
2444
  for (const property of Object.keys(columns)) {
2399
2445
  if (RESERVED_RESOLVED_COLUMN_NAMES.has(property) || RESERVED_RESOLVED_COLUMN_NAMES.has(columns[property].columnNameFor(property))) {
2400
2446
  fail(`column "${property}" collides with a reserved system column`);
@@ -2413,7 +2459,7 @@ function defineResolvedTable(name, columns, config) {
2413
2459
  const sourceEntries = Object.entries(config.sources);
2414
2460
  if (sourceEntries.filter(([, source]) => source.kind === "manual").length !== 1) fail("declare exactly one manualSource()");
2415
2461
  const plans = sourceEntries.map(
2416
- ([sourceName, input]) => planSource({ viewName: name, sourceName, input, columns, pk, pkBuilder, dataColumns, fail })
2462
+ ([sourceName, input]) => planSource({ viewName: name2, sourceName, input, columns, pk, pkBuilder, dataColumns, fail })
2417
2463
  );
2418
2464
  const rules = planRules({ config, plans, dataColumns, fail });
2419
2465
  const deletedBy = [...config.rows?.deletedBy ?? []];
@@ -2447,23 +2493,23 @@ function defineResolvedTable(name, columns, config) {
2447
2493
  policies: { read }
2448
2494
  };
2449
2495
  if (!config.materialize) {
2450
- return defineView(name, typedColumns, { ...surface, query: (context) => buildResolvedQuery({ context, plan: queryPlan }), resolved });
2496
+ return defineView(name2, typedColumns, { ...surface, query: (context) => buildResolvedQuery({ context, plan: queryPlan }), resolved });
2451
2497
  }
2452
2498
  const materialize = config.materialize === true ? {} : config.materialize;
2453
- const computeName = `${name}__compute`;
2454
- const tableName = `${name}__materialized`;
2499
+ const computeName = `${name2}__compute`;
2500
+ const tableName = `${name2}__materialized`;
2455
2501
  const compute = defineView(computeName, typedColumns, {
2456
2502
  policies: { read },
2457
2503
  query: (context) => buildResolvedQuery({ context, plan: queryPlan }),
2458
2504
  internal: true
2459
2505
  });
2460
2506
  const table = defineTable(tableName, viewColumns, {
2461
- description: `Materialized rows of resolved table "${name}". System-maintained from "${computeName}".`,
2507
+ description: `Materialized rows of resolved table "${name2}". System-maintained from "${computeName}".`,
2462
2508
  internal: true,
2463
- materializes: name,
2509
+ materializes: name2,
2464
2510
  ...materialize.indexes !== void 0 ? { indexes: materialize.indexes } : {}
2465
2511
  });
2466
- return defineView(name, typedColumns, {
2512
+ return defineView(name2, typedColumns, {
2467
2513
  ...surface,
2468
2514
  query: (context) => {
2469
2515
  const handle = context.relation(table);
@@ -2490,7 +2536,7 @@ function planRules({ config, plans, dataColumns, fail }) {
2490
2536
  return dataColumns.map((column) => {
2491
2537
  const explicit = config.resolve?.[column];
2492
2538
  const comparator = explicit ?? fallback;
2493
- const candidates = explicit ? [...explicit.candidates] : comparator.candidates.filter((name) => plans.find((plan) => plan.name === name)?.columns.includes(column));
2539
+ const candidates = explicit ? [...explicit.candidates] : comparator.candidates.filter((name2) => plans.find((plan) => plan.name === name2)?.columns.includes(column));
2494
2540
  for (const candidate of candidates) {
2495
2541
  const plan = plans.find((entry) => entry.name === candidate);
2496
2542
  if (!plan) fail(`column "${column}" names unknown source "${candidate}"`);
@@ -2592,8 +2638,8 @@ function canonicalTable(table) {
2592
2638
  },
2593
2639
  actions: emptyToNull(
2594
2640
  Object.fromEntries(
2595
- Object.entries(table.actions ?? {}).map(([name, action]) => [
2596
- name,
2641
+ Object.entries(table.actions ?? {}).map(([name2, action]) => [
2642
+ name2,
2597
2643
  {
2598
2644
  description: action.description ?? null,
2599
2645
  requires: action.requires?.source ?? null,
@@ -2647,6 +2693,72 @@ function computeDefinitionHash(definition) {
2647
2693
  return crypto.createHash("sha256").update(HASH_DOMAIN).update(stableJson(canonicalizeDefinition(definition))).digest("hex");
2648
2694
  }
2649
2695
 
2696
+ // src/canonical/composition.ts
2697
+ function localContract(definition) {
2698
+ return normalizeCanonical(localDefinitionSchema.parse(definition));
2699
+ }
2700
+ function flattenNamespaceImports(inputs) {
2701
+ const definitions = /* @__PURE__ */ new Map();
2702
+ const visit = (value, depth) => {
2703
+ if (depth > 16 || definitions.size > 32) throw new OrmDefinitionError("namespace import graph is too large");
2704
+ const definition = localContract(localDefinitionSchema.parse(value));
2705
+ const previous = definitions.get(definition.namespace);
2706
+ if (previous) {
2707
+ if (stableJson(previous) !== stableJson(definition)) throw new OrmDefinitionError(`conflicting contracts for namespace '${definition.namespace}'`);
2708
+ }
2709
+ definitions.set(definition.namespace, definition);
2710
+ if (typeof value === "object" && value !== null && "imports" in value && Array.isArray(value.imports)) {
2711
+ for (const dependency of value.imports) visit(dependency, depth + 1);
2712
+ }
2713
+ };
2714
+ for (const input of inputs) visit(input, 0);
2715
+ return [...definitions.values()].sort((a, b) => a.namespace.localeCompare(b.namespace));
2716
+ }
2717
+ function composeNamespace(definition) {
2718
+ const all = [localContract(definition), ...definition.imports ?? []];
2719
+ const owners = /* @__PURE__ */ new Map();
2720
+ const namespaces = /* @__PURE__ */ new Set();
2721
+ const enums = /* @__PURE__ */ new Map();
2722
+ for (const owner of all) {
2723
+ if (namespaces.has(owner.namespace)) throw new OrmDefinitionError(`duplicate imported namespace '${owner.namespace}'`);
2724
+ namespaces.add(owner.namespace);
2725
+ for (const value of owner.enums) {
2726
+ const previous = enums.get(value.name);
2727
+ if (previous && stableJson(previous) !== stableJson(value)) {
2728
+ throw new OrmDefinitionError(`conflicting imported enum '${value.name}'`);
2729
+ }
2730
+ enums.set(value.name, value);
2731
+ }
2732
+ for (const relation of canonicalRelations(owner)) {
2733
+ if (owners.has(relation.table)) throw new OrmDefinitionError(`ambiguous imported relation '${relation.table}'`);
2734
+ owners.set(relation.table, owner);
2735
+ }
2736
+ }
2737
+ for (const owner of definition.imports?.length ? all : []) {
2738
+ for (const relation of canonicalRelations(owner)) {
2739
+ for (const link of relation.links) {
2740
+ if (link.kind === "toPlatformUser") continue;
2741
+ const target = owners.get(link.target ?? "");
2742
+ if (!target || target.namespace !== (link.namespace ?? owner.namespace)) {
2743
+ throw new OrmDefinitionError(`link '${owner.namespace}/${relation.table}.${link.name}' has no matching imported target`);
2744
+ }
2745
+ if (target.namespace !== owner.namespace && !target.exports?.[link.target ?? ""]) {
2746
+ throw new OrmDefinitionError(`target '${target.namespace}/${link.target}' is not exported`);
2747
+ }
2748
+ }
2749
+ }
2750
+ }
2751
+ return {
2752
+ owners,
2753
+ definition: {
2754
+ ...localContract(definition),
2755
+ tables: all.flatMap((item) => item.tables),
2756
+ views: all.flatMap((item) => item.views ?? []),
2757
+ enums: [...enums.values()]
2758
+ }
2759
+ };
2760
+ }
2761
+
2650
2762
  // src/authoring/namespace.ts
2651
2763
  var NAMESPACE_CONFIG_BRAND = "seq-namespace-config";
2652
2764
  function isSeqNamespaceConfig(value) {
@@ -2662,6 +2774,8 @@ function defineNamespace(input) {
2662
2774
  namespace: input.namespace,
2663
2775
  description: input.description,
2664
2776
  capabilities: input.capabilities ?? {},
2777
+ imports: input.imports,
2778
+ exports: input.exports,
2665
2779
  file
2666
2780
  };
2667
2781
  registerNamespaceConfig(config);
@@ -2706,15 +2820,15 @@ function serializeNamespace(input) {
2706
2820
  }
2707
2821
  const relationsByName = /* @__PURE__ */ new Map();
2708
2822
  for (const relation of [...tables, ...views]) {
2709
- const name = relationName(relation);
2710
- const existing = relationsByName.get(name);
2823
+ const name2 = relationName(relation);
2824
+ const existing = relationsByName.get(name2);
2711
2825
  if (existing) {
2712
2826
  throw new OrmDefinitionError(
2713
- `duplicate relation "${name}" (defined as ${relationKind(existing)} in ${describeFile(existing)} and ${relationKind(relation)} in ${describeFile(relation)})`,
2827
+ `duplicate relation "${name2}" (defined as ${relationKind(existing)} in ${describeFile(existing)} and ${relationKind(relation)} in ${describeFile(relation)})`,
2714
2828
  relation.file
2715
2829
  );
2716
2830
  }
2717
- relationsByName.set(name, relation);
2831
+ relationsByName.set(name2, relation);
2718
2832
  }
2719
2833
  const enumsByName = /* @__PURE__ */ new Map();
2720
2834
  for (const ref of enums) {
@@ -2755,6 +2869,8 @@ function serializeNamespace(input) {
2755
2869
  };
2756
2870
  if (config.description !== void 0) candidate.description = config.description;
2757
2871
  if (canonicalViews.length > 0) candidate.views = canonicalViews;
2872
+ if (config.imports?.length) candidate.imports = flattenNamespaceImports(config.imports);
2873
+ if (config.exports) candidate.exports = config.exports;
2758
2874
  let parsed;
2759
2875
  try {
2760
2876
  parsed = canonicalDefinitionSchema.parse(candidate);
@@ -2764,7 +2880,9 @@ function serializeNamespace(input) {
2764
2880
  }
2765
2881
  throw error;
2766
2882
  }
2767
- return normalizeCanonical(parsed);
2883
+ const normalized = normalizeCanonical(parsed);
2884
+ if (normalized.imports?.length) composeNamespace(normalized);
2885
+ return normalized;
2768
2886
  }
2769
2887
  function computeCanonicalHash(definition) {
2770
2888
  return crypto.createHash("sha256").update(HASH_DOMAIN).update(stableJson(definition)).digest("hex");
@@ -2778,6 +2896,7 @@ function buildCanonicalTable({ table, relationsByName, enumsByName }) {
2778
2896
  policies: {},
2779
2897
  actions: []
2780
2898
  };
2899
+ if (table.config.displayName !== void 0) candidate.displayName = table.config.displayName;
2781
2900
  if (table.config.description !== void 0) candidate.description = table.config.description;
2782
2901
  if (table.config.renamedFrom !== void 0) candidate.renamedFrom = table.config.renamedFrom;
2783
2902
  if (table.source !== void 0) candidate.source = table.source;
@@ -2861,6 +2980,9 @@ function buildCanonicalTable({ table, relationsByName, enumsByName }) {
2861
2980
  if (table.config.foreignKeys?.length) {
2862
2981
  if (table.source) throw new OrmDefinitionError(`synced table "${table.tableName}" cannot enforce foreign keys`, table.file);
2863
2982
  candidate.foreignKeys = table.config.foreignKeys.map((fk) => {
2983
+ if (typeof fk.target === "object" && fk.target.kind === "seq-external-object") {
2984
+ throw new OrmDefinitionError("physical foreign keys require a local target; use a cross-namespace ORM link", table.file);
2985
+ }
2864
2986
  const target = resolveRelationRef({ ref: fk.target, fail: (message) => {
2865
2987
  throw new OrmDefinitionError(message, table.file);
2866
2988
  } });
@@ -3031,6 +3153,19 @@ function buildCanonicalLink({
3031
3153
  ...link.description !== void 0 ? { description: link.description } : {}
3032
3154
  };
3033
3155
  }
3156
+ if (typeof link.target === "object" && link.target?.kind === "seq-external-object") {
3157
+ if (link.enforce) return fail("cannot enforce a cross-namespace physical foreign key; use an ORM link without enforce");
3158
+ return {
3159
+ name: linkName,
3160
+ kind: link.linkKind,
3161
+ namespace: link.target.namespace,
3162
+ target: link.target.table,
3163
+ on: link.linkKind === "toOne" ? resolveColumnRef({ relation, ref: link.on, role: "link on" }) : link.on,
3164
+ ...link.references !== void 0 ? { references: link.linkKind === "toMany" ? resolveColumnRef({ relation, ref: link.references, role: "link references" }) : link.references } : {},
3165
+ enforce: false,
3166
+ ...link.description !== void 0 ? { description: link.description } : {}
3167
+ };
3168
+ }
3034
3169
  const target = resolveRelationRef({ ref: link.target, fail });
3035
3170
  const targetName = relationName(target);
3036
3171
  if (!relationsByName.has(targetName)) {
@@ -3087,11 +3222,11 @@ function assertAcyclicViewDependencies(views) {
3087
3222
  views.map((view) => [view.view, new Set(view.dependencies.filter((dependency) => viewNames.has(dependency)))])
3088
3223
  );
3089
3224
  while (remaining.size > 0) {
3090
- const ready = [...remaining.entries()].filter(([, dependencies]) => [...dependencies].every((dependency) => !remaining.has(dependency))).map(([name]) => name);
3225
+ const ready = [...remaining.entries()].filter(([, dependencies]) => [...dependencies].every((dependency) => !remaining.has(dependency))).map(([name2]) => name2);
3091
3226
  if (ready.length === 0) {
3092
3227
  throw new OrmDefinitionError(`view dependencies form a cycle among: ${[...remaining.keys()].sort().join(", ")}`);
3093
3228
  }
3094
- for (const name of ready) remaining.delete(name);
3229
+ for (const name2 of ready) remaining.delete(name2);
3095
3230
  }
3096
3231
  }
3097
3232
  function toCanonicalPolicy(policy) {
@@ -3137,8 +3272,8 @@ function syncedContractSurface({
3137
3272
  namespace,
3138
3273
  table,
3139
3274
  columns: Object.fromEntries(
3140
- Object.entries(columns).map(([name, column]) => [
3141
- name,
3275
+ Object.entries(columns).map(([name2, column]) => [
3276
+ name2,
3142
3277
  { type: column.type, nullable: column.nullable, key: column.key }
3143
3278
  ])
3144
3279
  ),
@@ -3159,7 +3294,7 @@ function extractOrmSyncedTableContract({
3159
3294
  }
3160
3295
  if (table.source === void 0) {
3161
3296
  throw new OrmDefinitionError(
3162
- `table "${table.table}" is not a synced table \u2014 extractOrmSyncedTableContract requires source: gold.*`
3297
+ `table "${table.table}" is not a synced table \u2014 extractOrmSyncedTableContract requires a qualified source`
3163
3298
  );
3164
3299
  }
3165
3300
  if (table.columns.length === 0) {
@@ -3306,6 +3441,53 @@ function purgeModuleCache(root) {
3306
3441
  if (key.startsWith(prefix)) delete require2.cache[key];
3307
3442
  }
3308
3443
  }
3444
+ var sqlScalarSchema = zod.z.enum(["text", "boolean", "integer", "bigint", "numeric", "double", "uuid", "date", "timestamptz"]);
3445
+ var name = zod.z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).max(63).refine((value) => !["__proto__", "prototype", "constructor"].includes(value), "reserved name");
3446
+ var base = zod.z.object({
3447
+ name,
3448
+ namespace: name,
3449
+ language: zod.z.literal("sql"),
3450
+ kind: zod.z.literal("query"),
3451
+ requires: zod.z.object({ capability: zod.z.string().min(1).max(128) }).strict(),
3452
+ ontology: zod.z.object({ read: zod.z.array(zod.z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*\/[A-Za-z_][A-Za-z0-9_]*$/)).min(1).max(256) }).strict(),
3453
+ maxRows: zod.z.number().int().min(1).max(1e4).default(1e3)
3454
+ });
3455
+ var fixed = base.extend({
3456
+ parameters: zod.z.record(name, zod.z.object({ type: sqlScalarSchema, required: zod.z.boolean().default(true) }).strict()).default({}),
3457
+ sql: zod.z.string().min(1).max(65536)
3458
+ }).strict();
3459
+ var runtime = base.extend({ mode: zod.z.literal("runtime") }).strict();
3460
+ var sqlOperationDefinitionSchema = zod.z.union([fixed, runtime]);
3461
+ function defineOperation(input) {
3462
+ return sqlOperationDefinitionSchema.parse(input);
3463
+ }
3464
+
3465
+ // src/authoring/catalog.ts
3466
+ var SEGMENT = /^[^./\\\s][^/\\]*[^./\\\s]$|^[^./\\\s]$/;
3467
+ function validateNamespaceCatalog(catalog, file) {
3468
+ const paths = /* @__PURE__ */ new Set([""]);
3469
+ function visit(folders, parent) {
3470
+ for (const [name2, children] of Object.entries(folders)) {
3471
+ if (!SEGMENT.test(name2) || ["__proto__", "constructor", "prototype"].includes(name2)) {
3472
+ throw new OrmDefinitionError(`invalid catalog folder name "${name2}"`, file);
3473
+ }
3474
+ const path = parent ? `${parent}/${name2}` : name2;
3475
+ paths.add(path);
3476
+ if (children !== null) {
3477
+ if (typeof children !== "object" || Array.isArray(children)) {
3478
+ throw new OrmDefinitionError(`catalog folder "${path}" must contain folders or null`, file);
3479
+ }
3480
+ visit(children, path);
3481
+ }
3482
+ }
3483
+ }
3484
+ visit(catalog.folders, "");
3485
+ for (const [object, path] of Object.entries(catalog.objects)) {
3486
+ if (!object || !paths.has(path)) {
3487
+ throw new OrmDefinitionError(`catalog object "${object}" references missing folder "${path}"`, file);
3488
+ }
3489
+ }
3490
+ }
3309
3491
 
3310
3492
  // src/codegen/types.ts
3311
3493
  var WIRE_TYPES = {
@@ -3337,9 +3519,9 @@ function generateNamespaceTypes(definition) {
3337
3519
  lines.push(` /** Synced from ${table.source} \u2014 read-only typed contract. */`);
3338
3520
  }
3339
3521
  lines.push(` ${table.table}: {`);
3340
- for (const [name, column] of columns) {
3522
+ for (const [name2, column] of columns) {
3341
3523
  if (column.deprecated) continue;
3342
- lines.push(` ${name}: ${columnWireType(column)}`);
3524
+ lines.push(` ${name2}: ${columnWireType(column)}`);
3343
3525
  }
3344
3526
  lines.push(" }");
3345
3527
  }
@@ -3350,8 +3532,8 @@ function generateNamespaceTypes(definition) {
3350
3532
  function actionTypeLines(definition) {
3351
3533
  const actions = definition.tables.flatMap((table) => Object.entries(table.actions ?? {}));
3352
3534
  const lines = [`export type ${actionsInterfaceName(definition.namespace)} = {`];
3353
- for (const [name, action] of actions.sort(([a], [b]) => a.localeCompare(b))) {
3354
- lines.push(` ${name}: { params: ${actionParamsType(action)}; result: ${actionResultType(action)} }`);
3535
+ for (const [name2, action] of actions.sort(([a], [b]) => a.localeCompare(b))) {
3536
+ lines.push(` ${name2}: { params: ${actionParamsType(action)}; result: ${actionResultType(action)} }`);
3355
3537
  }
3356
3538
  lines.push("}", "");
3357
3539
  return lines;
@@ -3359,17 +3541,17 @@ function actionTypeLines(definition) {
3359
3541
  function actionParamsType(action) {
3360
3542
  const entries = Object.entries(action.params ?? {});
3361
3543
  if (entries.length === 0) return "Record<never, never>";
3362
- const fields = entries.map(([name, param]) => {
3363
- const base = WIRE_TYPES[param.type];
3364
- return param.optional ? `${name}?: ${base} | null` : `${name}: ${base}`;
3544
+ const fields = entries.map(([name2, param]) => {
3545
+ const base2 = WIRE_TYPES[param.type];
3546
+ return param.optional ? `${name2}?: ${base2} | null` : `${name2}: ${base2}`;
3365
3547
  });
3366
3548
  return `{ ${fields.join("; ")} }`;
3367
3549
  }
3368
3550
  function actionResultType(action) {
3369
3551
  if (!action.returns) return "{ rowsAffected: number }";
3370
- const columns = Object.entries(action.returns).map(([name, type]) => {
3371
- const base = WIRE_TYPES[type];
3372
- return base === "unknown" ? `${name}: ${base}` : `${name}: ${base} | null`;
3552
+ const columns = Object.entries(action.returns).map(([name2, type]) => {
3553
+ const base2 = WIRE_TYPES[type];
3554
+ return base2 === "unknown" ? `${name2}: ${base2}` : `${name2}: ${base2} | null`;
3373
3555
  });
3374
3556
  return `{ rows: Array<{ ${columns.join("; ")} }> }`;
3375
3557
  }
@@ -3383,9 +3565,9 @@ function pascalCase(namespace) {
3383
3565
  return namespace.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
3384
3566
  }
3385
3567
  function columnWireType(column) {
3386
- const base = WIRE_TYPES[column.type];
3568
+ const base2 = WIRE_TYPES[column.type];
3387
3569
  const notNull = column.primary_key === true || column.nullable === false;
3388
- return notNull || base === "unknown" ? base : `${base} | null`;
3570
+ return notNull || base2 === "unknown" ? base2 : `${base2} | null`;
3389
3571
  }
3390
3572
 
3391
3573
  // src/predicate/ast.ts
@@ -3850,7 +4032,7 @@ function executesIssues(executes, declaredParams, hasReturns) {
3850
4032
  if (hasReturns && last && !RETURNING_PATTERN.test(last.replace(QUOTED_STRING_PATTERN, "''"))) {
3851
4033
  issues.push("the last executes statement must use RETURNING to populate the declared returns columns");
3852
4034
  }
3853
- const undeclared = extractNamedParams(statements.join("\n")).filter((name) => !declaredParams.has(name));
4035
+ const undeclared = extractNamedParams(statements.join("\n")).filter((name2) => !declaredParams.has(name2));
3854
4036
  if (undeclared.length > 0) issues.push(`executes references undeclared params: ${undeclared.join(", ")}`);
3855
4037
  return issues;
3856
4038
  }
@@ -3925,19 +4107,19 @@ var PARAM_SCHEMAS = {
3925
4107
  function buildActionParamsSchema(action) {
3926
4108
  const shape = {};
3927
4109
  const entries = Object.entries(action.params ?? {});
3928
- for (const [name, param] of entries) {
3929
- shape[name] = param.optional ? PARAM_SCHEMAS[param.type].nullish() : PARAM_SCHEMAS[param.type];
4110
+ for (const [name2, param] of entries) {
4111
+ shape[name2] = param.optional ? PARAM_SCHEMAS[param.type].nullish() : PARAM_SCHEMAS[param.type];
3930
4112
  }
3931
4113
  return zod.z.strictObject(shape).superRefine((obj, ctx) => {
3932
- for (const [name, param] of entries) {
3933
- if (!param.optional && param.type === "jsonb" && obj[name] === void 0) {
3934
- ctx.addIssue({ code: "custom", message: "Required", path: [name] });
4114
+ for (const [name2, param] of entries) {
4115
+ if (!param.optional && param.type === "jsonb" && obj[name2] === void 0) {
4116
+ ctx.addIssue({ code: "custom", message: "Required", path: [name2] });
3935
4117
  }
3936
4118
  }
3937
4119
  });
3938
4120
  }
3939
4121
  var actionParamOrder = (action) => Object.keys(action.params ?? {});
3940
- var actionParamArg = (name) => `p_${name}`;
4122
+ var actionParamArg = (name2) => `p_${name2}`;
3941
4123
  function compileActionStatements(action, renderParam = actionParamArg) {
3942
4124
  return actionStatementSources(action.executes).map((statement) => compileStatement(statement, renderParam));
3943
4125
  }
@@ -3988,10 +4170,12 @@ function compilePredIrToSql(pred, options = {}) {
3988
4170
  case "cmp":
3989
4171
  return compileCmp(pred.op, pred.column, pred.value, options);
3990
4172
  case "capability":
3991
- return `(${capabilityExpression(pred.key)})`;
4173
+ return `(${capabilityExpression(pred.key, pred.namespace ?? options.namespace)})`;
3992
4174
  case "role":
3993
- return `(${roleExpression(pred.key)})`;
4175
+ return `(${roleExpression(pred.key, pred.namespace ?? options.namespace)})`;
3994
4176
  case "exists":
4177
+ if (options.exists) return options.exists(pred);
4178
+ throw new OrmDefinitionError("synced view read policy cannot use 'exists' without a relationship resolver");
3995
4179
  case "aggPredicate":
3996
4180
  case "dynamicFilter":
3997
4181
  throw new OrmDefinitionError(
@@ -4010,7 +4194,8 @@ function compileCmp(op, column, value, options) {
4010
4194
  const physical2 = physicalColumn(column, options);
4011
4195
  const declared = options.columnTypes?.[physical2] ?? options.columnTypes?.[column];
4012
4196
  const isEnum = typeof declared === "object" && declared !== null;
4013
- const col = isEnum ? `${quoteIdentifier(physical2)}::text` : quoteIdentifier(physical2);
4197
+ const qualified = options.alias ? `${quoteIdentifier(options.alias)}.${quoteIdentifier(physical2)}` : quoteIdentifier(physical2);
4198
+ const col = isEnum ? `${qualified}::text` : qualified;
4014
4199
  const columnType = isEnum ? "text" : declared;
4015
4200
  switch (op) {
4016
4201
  case "eq":
@@ -4094,22 +4279,22 @@ function returnProjection(returns, lastStatement) {
4094
4279
  const projection = Object.keys(returns).map(quoteIdentifier).join(", ");
4095
4280
  return `WITH orm_returning AS (${lastStatement}) SELECT ${projection} FROM orm_returning`;
4096
4281
  }
4097
- var allActions = (definition) => definition.tables.flatMap((table) => Object.entries(table.actions ?? {}).map(([name, action]) => ({ name, action }))).sort((a, b) => a.name.localeCompare(b.name));
4282
+ var allActions = (definition) => definition.tables.flatMap((table) => Object.entries(table.actions ?? {}).map(([name2, action]) => ({ name: name2, action }))).sort((a, b) => a.name.localeCompare(b.name));
4098
4283
  function actionFunctionStatements(definition) {
4099
4284
  const schema = ormSchemaName(definition.namespace);
4100
- return [dropAllActionFunctions(schema), ...allActions(definition).flatMap(({ name, action }) => createActionFunction(definition, name, action))];
4285
+ return [dropAllActionFunctions(schema), ...allActions(definition).flatMap(({ name: name2, action }) => createActionFunction(definition, name2, action))];
4101
4286
  }
4102
4287
  function actionPrepareChecks(definition) {
4103
4288
  const actions = allActions(definition);
4104
4289
  if (actions.length === 0) return [];
4105
4290
  const statements = [`SET LOCAL search_path TO ${quoteIdentifier(ormSchemaName(definition.namespace))}`];
4106
- for (const { name, action } of actions) {
4291
+ for (const { name: name2, action } of actions) {
4107
4292
  const order = actionParamOrder(action);
4108
4293
  const signature = order.length > 0 ? ` (${order.map((param) => sqlTypeName(action.params[param].type)).join(", ")})` : "";
4109
4294
  const compiled = compileActionStatements(action, (param) => `$${order.indexOf(param) + 1}`);
4110
4295
  compiled.forEach((sql7, index3) => {
4111
4296
  const checked = action.returns && index3 === compiled.length - 1 ? returnProjection(action.returns, sql7) : sql7;
4112
- statements.push(`PREPARE ${quoteIdentifier(`orm_check_${name}_${index3}`)}${signature} AS ${checked}`);
4297
+ statements.push(`PREPARE ${quoteIdentifier(`orm_check_${name2}_${index3}`)}${signature} AS ${checked}`);
4113
4298
  });
4114
4299
  }
4115
4300
  return statements;
@@ -4130,9 +4315,9 @@ BEGIN
4130
4315
  END
4131
4316
  $orm_reconcile_actions$`;
4132
4317
  }
4133
- function createActionFunction(definition, name, action) {
4318
+ function createActionFunction(definition, name2, action) {
4134
4319
  const schema = quoteIdentifier(ormSchemaName(definition.namespace));
4135
- const fn = `${schema}.${quoteIdentifier(actionFunctionName(name))}`;
4320
+ const fn = `${schema}.${quoteIdentifier(actionFunctionName(name2))}`;
4136
4321
  const order = actionParamOrder(action);
4137
4322
  const signature = order.map((paramName) => `${quoteIdentifier(actionParamArg(paramName))} ${sqlTypeName(action.params[paramName].type)}`).join(", ");
4138
4323
  const argTypes = order.map((paramName) => sqlTypeName(action.params[paramName].type)).join(", ");
@@ -4152,7 +4337,7 @@ AS $orm_action$
4152
4337
  -- columns; resolve unqualified names to the column.
4153
4338
  #variable_conflict use_column
4154
4339
  BEGIN
4155
- ${[functionGuards(definition, name, action), ...leading, ` RETURN QUERY ${returnProjection(action.returns, last)};`].filter(Boolean).join("\n")}
4340
+ ${[functionGuards(definition, name2, action), ...leading, ` RETURN QUERY ${returnProjection(action.returns, last)};`].filter(Boolean).join("\n")}
4156
4341
  END
4157
4342
  $orm_action$`
4158
4343
  ) : (
@@ -4166,7 +4351,7 @@ AS $orm_action$
4166
4351
  DECLARE
4167
4352
  v_count bigint;
4168
4353
  BEGIN
4169
- ${[functionGuards(definition, name, action), ...leading, ` ${last};`].filter(Boolean).join("\n")}
4354
+ ${[functionGuards(definition, name2, action), ...leading, ` ${last};`].filter(Boolean).join("\n")}
4170
4355
  GET DIAGNOSTICS v_count = ROW_COUNT;
4171
4356
  RETURN v_count;
4172
4357
  END
@@ -4178,13 +4363,13 @@ $orm_action$`
4178
4363
  `GRANT EXECUTE ON FUNCTION ${fn}(${argTypes}) TO ${role}`
4179
4364
  ];
4180
4365
  }
4181
- function functionGuards(definition, name, action) {
4366
+ function functionGuards(definition, name2, action) {
4182
4367
  const lines = [];
4183
4368
  const requires = compileActionRequires(action);
4184
4369
  if (requires) {
4185
4370
  lines.push(
4186
4371
  ` IF NOT (${requires}) THEN`,
4187
- ` RAISE EXCEPTION 'action ${name} requires a grant the caller does not hold' USING ERRCODE = ${quoteLiteral(ACTION_REQUIRES_DENIED_SQLSTATE)};`,
4372
+ ` RAISE EXCEPTION 'action ${name2} requires a grant the caller does not hold' USING ERRCODE = ${quoteLiteral(ACTION_REQUIRES_DENIED_SQLSTATE)};`,
4188
4373
  ` END IF;`
4189
4374
  );
4190
4375
  }
@@ -4236,7 +4421,7 @@ var tableFileSchema = zod.z.strictObject({
4236
4421
  table: identifierSchema,
4237
4422
  description: zod.z.string().optional(),
4238
4423
  columns: zod.z.record(identifierSchema, columnSchema).optional(),
4239
- source: zod.z.string().regex(SYNCED_SOURCE_PATTERN, "source must reference a gold-layer table").optional(),
4424
+ source: zod.z.string().regex(SYNCED_SOURCE_PATTERN, "source must be a qualified lowercase schema.table identifier").optional(),
4240
4425
  links: zod.z.record(identifierSchema, linkSchema).optional(),
4241
4426
  indexes: zod.z.array(indexSchema).optional(),
4242
4427
  policies: policiesSchema.optional(),
@@ -4245,12 +4430,12 @@ var tableFileSchema = zod.z.strictObject({
4245
4430
  if (RESERVED_TABLE_NAMES.has(table.table)) {
4246
4431
  ctx.addIssue({ code: "custom", message: `'${table.table}' is a reserved table name`, path: ["table"] });
4247
4432
  }
4248
- for (const name of Object.keys(table.columns ?? {})) {
4249
- if (RESERVED_COLUMN_NAMES.has(name)) {
4433
+ for (const name2 of Object.keys(table.columns ?? {})) {
4434
+ if (RESERVED_COLUMN_NAMES.has(name2)) {
4250
4435
  ctx.addIssue({
4251
4436
  code: "custom",
4252
- message: `column '${name}' collides with the Data API's reserved query parameters (select, order, limit, offset) \u2014 it could never be filtered`,
4253
- path: ["columns", name]
4437
+ message: `column '${name2}' collides with the Data API's reserved query parameters (select, order, limit, offset) \u2014 it could never be filtered`,
4438
+ path: ["columns", name2]
4254
4439
  });
4255
4440
  }
4256
4441
  }
@@ -4283,41 +4468,41 @@ function validateSyncedTable(table, ctx) {
4283
4468
  const columns = table.columns ?? {};
4284
4469
  const names = Object.keys(columns);
4285
4470
  if (names.length === 0) return;
4286
- const primaryKeys = names.filter((name) => columns[name]?.primary_key);
4471
+ const primaryKeys = names.filter((name2) => columns[name2]?.primary_key);
4287
4472
  if (primaryKeys.length !== 1) {
4288
4473
  ctx.addIssue({ code: "custom", message: "exactly one column must be primary_key", path: ["columns"] });
4289
4474
  }
4290
4475
  validateRenames(columns, names, ctx);
4291
- for (const name of names) {
4292
- const column = columns[name];
4476
+ for (const name2 of names) {
4477
+ const column = columns[name2];
4293
4478
  if (!column) continue;
4294
4479
  const cast = column.cast ? castParts(column.cast) : null;
4295
- if (column.cast && cast?.column !== name) {
4480
+ if (column.cast && cast?.column !== name2) {
4296
4481
  ctx.addIssue({
4297
4482
  code: "custom",
4298
4483
  message: "cast must reference the column it is declared on",
4299
- path: ["columns", name, "cast"]
4484
+ path: ["columns", name2, "cast"]
4300
4485
  });
4301
4486
  }
4302
4487
  if (cast && cast.type !== column.type) {
4303
4488
  ctx.addIssue({
4304
4489
  code: "custom",
4305
4490
  message: `cast target '${cast.type}' must match the declared type '${column.type}'`,
4306
- path: ["columns", name, "cast"]
4491
+ path: ["columns", name2, "cast"]
4307
4492
  });
4308
4493
  }
4309
4494
  }
4310
4495
  }
4311
4496
  function validateRenames(columns, names, ctx) {
4312
4497
  const renameSources = /* @__PURE__ */ new Map();
4313
- for (const name of names) {
4314
- const renamedFrom = columns[name]?.renamed_from;
4498
+ for (const name2 of names) {
4499
+ const renamedFrom = columns[name2]?.renamed_from;
4315
4500
  if (!renamedFrom) continue;
4316
- if (renamedFrom === name || names.includes(renamedFrom)) {
4501
+ if (renamedFrom === name2 || names.includes(renamedFrom)) {
4317
4502
  ctx.addIssue({
4318
4503
  code: "custom",
4319
4504
  message: "renamed_from must name a column that no longer exists",
4320
- path: ["columns", name, "renamed_from"]
4505
+ path: ["columns", name2, "renamed_from"]
4321
4506
  });
4322
4507
  }
4323
4508
  const claimed = renameSources.get(renamedFrom);
@@ -4325,10 +4510,10 @@ function validateRenames(columns, names, ctx) {
4325
4510
  ctx.addIssue({
4326
4511
  code: "custom",
4327
4512
  message: `renamed_from '${renamedFrom}' is already claimed by '${claimed}'`,
4328
- path: ["columns", name, "renamed_from"]
4513
+ path: ["columns", name2, "renamed_from"]
4329
4514
  });
4330
4515
  }
4331
- renameSources.set(renamedFrom, name);
4516
+ renameSources.set(renamedFrom, name2);
4332
4517
  }
4333
4518
  }
4334
4519
  function validateColumnTable(table, ctx) {
@@ -4338,27 +4523,27 @@ function validateColumnTable(table, ctx) {
4338
4523
  ctx.addIssue({ code: "custom", message: "a table must declare columns or a source", path: ["columns"] });
4339
4524
  return;
4340
4525
  }
4341
- const primaryKeys = names.filter((name) => columns[name]?.primary_key);
4526
+ const primaryKeys = names.filter((name2) => columns[name2]?.primary_key);
4342
4527
  if (primaryKeys.length !== 1) {
4343
4528
  ctx.addIssue({ code: "custom", message: "exactly one column must be primary_key", path: ["columns"] });
4344
4529
  }
4345
4530
  validateRenames(columns, names, ctx);
4346
- for (const name of names) {
4347
- const column = columns[name];
4531
+ for (const name2 of names) {
4532
+ const column = columns[name2];
4348
4533
  if (!column) continue;
4349
4534
  const cast = column.cast ? castParts(column.cast) : null;
4350
- if (column.cast && cast?.column !== name) {
4535
+ if (column.cast && cast?.column !== name2) {
4351
4536
  ctx.addIssue({
4352
4537
  code: "custom",
4353
4538
  message: "cast must reference the column it is declared on",
4354
- path: ["columns", name, "cast"]
4539
+ path: ["columns", name2, "cast"]
4355
4540
  });
4356
4541
  }
4357
4542
  if (cast && cast.type !== column.type) {
4358
4543
  ctx.addIssue({
4359
4544
  code: "custom",
4360
4545
  message: `cast target '${cast.type}' must match the declared type '${column.type}'`,
4361
- path: ["columns", name, "cast"]
4546
+ path: ["columns", name2, "cast"]
4362
4547
  });
4363
4548
  }
4364
4549
  }
@@ -4383,22 +4568,22 @@ function validateColumnTable(table, ctx) {
4383
4568
  }
4384
4569
  function validateLinks(table, ctx) {
4385
4570
  const columnNames = Object.keys(table.columns ?? {});
4386
- for (const [name, link] of Object.entries(table.links ?? {})) {
4571
+ for (const [name2, link] of Object.entries(table.links ?? {})) {
4387
4572
  if (columnNames.length > 0 && !columnNames.includes(link.on)) {
4388
- ctx.addIssue({ code: "custom", message: `link references unknown column '${link.on}'`, path: ["links", name, "on"] });
4573
+ ctx.addIssue({ code: "custom", message: `link references unknown column '${link.on}'`, path: ["links", name2, "on"] });
4389
4574
  }
4390
4575
  if (link.enforce && link.to.includes(".")) {
4391
4576
  ctx.addIssue({
4392
4577
  code: "custom",
4393
4578
  message: "enforce is only valid for links inside the namespace; cross-boundary links stay soft",
4394
- path: ["links", name, "enforce"]
4579
+ path: ["links", name2, "enforce"]
4395
4580
  });
4396
4581
  }
4397
4582
  if (link.enforce && table.source) {
4398
4583
  ctx.addIssue({
4399
4584
  code: "custom",
4400
4585
  message: "a synced table cannot enforce foreign keys \u2014 its DDL is owned by the sync",
4401
- path: ["links", name, "enforce"]
4586
+ path: ["links", name2, "enforce"]
4402
4587
  });
4403
4588
  }
4404
4589
  }
@@ -4413,32 +4598,32 @@ function validateDerivedNameLengths(table, ctx) {
4413
4598
  });
4414
4599
  }
4415
4600
  for (const [position, index3] of (table.indexes ?? []).entries()) {
4416
- const name = indexName(table.table, index3);
4417
- if (name.length > MAX_IDENTIFIER_LENGTH) {
4601
+ const name2 = indexName(table.table, index3);
4602
+ if (name2.length > MAX_IDENTIFIER_LENGTH) {
4418
4603
  ctx.addIssue({
4419
4604
  code: "custom",
4420
- message: `derived index name '${name}' exceeds Postgres's ${MAX_IDENTIFIER_LENGTH}-byte identifier limit \u2014 set a shorter explicit name`,
4605
+ message: `derived index name '${name2}' exceeds Postgres's ${MAX_IDENTIFIER_LENGTH}-byte identifier limit \u2014 set a shorter explicit name`,
4421
4606
  path: ["indexes", position]
4422
4607
  });
4423
4608
  }
4424
4609
  }
4425
- for (const [name, link] of Object.entries(table.links ?? {})) {
4426
- const constraint = foreignKeyName(table.table, name);
4610
+ for (const [name2, link] of Object.entries(table.links ?? {})) {
4611
+ const constraint = foreignKeyName(table.table, name2);
4427
4612
  if (link.enforce && constraint.length > MAX_IDENTIFIER_LENGTH) {
4428
4613
  ctx.addIssue({
4429
4614
  code: "custom",
4430
4615
  message: `derived foreign-key name '${constraint}' exceeds Postgres's ${MAX_IDENTIFIER_LENGTH}-byte identifier limit \u2014 shorten the link or table name`,
4431
- path: ["links", name]
4616
+ path: ["links", name2]
4432
4617
  });
4433
4618
  }
4434
4619
  }
4435
- for (const name of Object.keys(table.actions ?? {})) {
4436
- const fnName = `action_${name}`;
4620
+ for (const name2 of Object.keys(table.actions ?? {})) {
4621
+ const fnName = `action_${name2}`;
4437
4622
  if (fnName.length > MAX_IDENTIFIER_LENGTH) {
4438
4623
  ctx.addIssue({
4439
4624
  code: "custom",
4440
4625
  message: `derived action function name '${fnName}' exceeds Postgres's ${MAX_IDENTIFIER_LENGTH}-byte identifier limit \u2014 shorten the action name`,
4441
- path: ["actions", name]
4626
+ path: ["actions", name2]
4442
4627
  });
4443
4628
  }
4444
4629
  }
@@ -4531,7 +4716,7 @@ function policyStatements(schema, table) {
4531
4716
  const policyName2 = (suffix) => quoteIdentifier(policyName(table.table, suffix));
4532
4717
  const statements = POLICY_SUFFIXES.map((suffix) => `DROP POLICY IF EXISTS ${policyName2(suffix)} ON ${qualified}`);
4533
4718
  const columnTypes = Object.fromEntries(
4534
- Object.entries(table.columns ?? {}).map(([name, column]) => [name, column.type])
4719
+ Object.entries(table.columns ?? {}).map(([name2, column]) => [name2, column.type])
4535
4720
  );
4536
4721
  const read = table.policies?.read;
4537
4722
  if (read) {
@@ -4594,12 +4779,19 @@ function syncedViewStatements({
4594
4779
  const readPolicyIr = readPolicyIrByTable?.get(table.table);
4595
4780
  const readPolicy = table.policies?.read;
4596
4781
  const whereClause = readPolicyIr ? ` WHERE ${compilePredIrToSql(readPolicyIr, {
4782
+ namespace: definition.namespace,
4597
4783
  columnTypes,
4598
4784
  columnNames: columnNamesByTable?.get(table.table)
4599
4785
  })}` : readPolicy ? ` WHERE ${compilePredicate(readPolicy.ast, narrowToV1ColumnTypes(columnTypes))}` : " WHERE false";
4600
4786
  if (backingPrivileges === "grant") {
4601
4787
  statements.push(`GRANT USAGE ON SCHEMA ${quoteIdentifier(physical2.schema)} TO ${owner}`);
4602
4788
  statements.push(`GRANT SELECT ON ${physicalTarget} TO ${owner}`);
4789
+ statements.push(`DO ${quoteLiteral(`BEGIN
4790
+ IF NOT (pg_catalog.has_schema_privilege(${quoteLiteral(executionOwnerRole)}, ${quoteLiteral(physical2.schema)}, 'USAGE')
4791
+ AND pg_catalog.has_table_privilege(${quoteLiteral(executionOwnerRole)}, ${quoteLiteral(physicalTarget)}, 'SELECT')) THEN
4792
+ RAISE EXCEPTION 'Synced backing owner lacks effective USAGE/SELECT; repair managed serving reader access before ORM apply' USING ERRCODE = '42501';
4793
+ END IF;
4794
+ END`)}`);
4603
4795
  }
4604
4796
  statements.push(
4605
4797
  `CREATE OR REPLACE VIEW ${viewName} AS SELECT * FROM ${physicalTarget}${whereClause}`
@@ -4615,8 +4807,8 @@ function mergeSyncedViewColumnTypes({
4615
4807
  columnNames
4616
4808
  }) {
4617
4809
  const fromTable = {};
4618
- for (const [name, def] of Object.entries(table.columns ?? {})) {
4619
- if (def?.type) fromTable[name] = def.type;
4810
+ for (const [name2, def] of Object.entries(table.columns ?? {})) {
4811
+ if (def?.type) fromTable[name2] = def.type;
4620
4812
  }
4621
4813
  if (columnNames) {
4622
4814
  for (const [logical, physical2] of Object.entries(columnNames)) {
@@ -4670,21 +4862,21 @@ function syncedBackingRevokeStatements({
4670
4862
  return statements;
4671
4863
  }
4672
4864
  var FACTORIES = {
4673
- uuid: (name) => pgCore.uuid(name),
4674
- text: (name) => pgCore.text(name),
4675
- integer: (name) => pgCore.integer(name),
4865
+ uuid: (name2) => pgCore.uuid(name2),
4866
+ text: (name2) => pgCore.text(name2),
4867
+ integer: (name2) => pgCore.integer(name2),
4676
4868
  // Mode 'bigint' keeps int8 lossless — mode 'number' silently rounds past
4677
4869
  // 2^53. The read executor serializes BigInt to string for JSON.
4678
- bigint: (name) => pgCore.bigint(name, { mode: "bigint" }),
4679
- numeric: (name) => pgCore.numeric(name),
4680
- double: (name) => pgCore.doublePrecision(name),
4681
- boolean: (name) => pgCore.boolean(name),
4682
- timestamptz: (name) => pgCore.timestamp(name, { withTimezone: true }),
4683
- date: (name) => pgCore.date(name),
4684
- jsonb: (name) => pgCore.jsonb(name)
4870
+ bigint: (name2) => pgCore.bigint(name2, { mode: "bigint" }),
4871
+ numeric: (name2) => pgCore.numeric(name2),
4872
+ double: (name2) => pgCore.doublePrecision(name2),
4873
+ boolean: (name2) => pgCore.boolean(name2),
4874
+ timestamptz: (name2) => pgCore.timestamp(name2, { withTimezone: true }),
4875
+ date: (name2) => pgCore.date(name2),
4876
+ jsonb: (name2) => pgCore.jsonb(name2)
4685
4877
  };
4686
- function buildColumn(name, definition) {
4687
- let column = FACTORIES[definition.type](name);
4878
+ function buildColumn(name2, definition) {
4879
+ let column = FACTORIES[definition.type](name2);
4688
4880
  if (definition.primary_key) column = column.primaryKey();
4689
4881
  if (definition.nullable === false && !definition.primary_key) column = column.notNull();
4690
4882
  if (definition.unique && !definition.primary_key) column = column.unique();
@@ -4715,7 +4907,7 @@ function buildDrizzleEntities(definition) {
4715
4907
  }
4716
4908
  function buildTable(schema, table, built) {
4717
4909
  const columns = Object.fromEntries(
4718
- Object.entries(table.columns ?? {}).map(([name, column]) => [name, buildColumn(name, column)])
4910
+ Object.entries(table.columns ?? {}).map(([name2, column]) => [name2, buildColumn(name2, column)])
4719
4911
  );
4720
4912
  const drizzleTable = schema.table(table.table, columns, (self) => [
4721
4913
  ...buildIndexes(table, self),
@@ -4725,21 +4917,21 @@ function buildTable(schema, table, built) {
4725
4917
  }
4726
4918
  function buildIndexes(table, self) {
4727
4919
  return (table.indexes ?? []).map((definition) => {
4728
- const name = indexName(table.table, definition);
4729
- const factory = definition.unique ? pgCore.uniqueIndex(name) : pgCore.index(name);
4920
+ const name2 = indexName(table.table, definition);
4921
+ const factory = definition.unique ? pgCore.uniqueIndex(name2) : pgCore.index(name2);
4730
4922
  const columns = definition.columns.map((column) => self[column]);
4731
4923
  return factory.on(...columns);
4732
4924
  });
4733
4925
  }
4734
4926
  function buildForeignKeys(table, self, built) {
4735
- return Object.entries(table.links ?? {}).filter(([, link]) => link.enforce).map(([name, link]) => {
4927
+ return Object.entries(table.links ?? {}).filter(([, link]) => link.enforce).map(([name2, link]) => {
4736
4928
  const target = link.to === table.table ? self : built.get(link.to);
4737
4929
  const targetColumn = target && findPrimaryKeyColumn(target);
4738
4930
  if (!target || !targetColumn) {
4739
- throw new OrmDefinitionError(`enforced link '${name}' on '${table.table}' has no built target '${link.to}'`);
4931
+ throw new OrmDefinitionError(`enforced link '${name2}' on '${table.table}' has no built target '${link.to}'`);
4740
4932
  }
4741
4933
  return pgCore.foreignKey({
4742
- name: foreignKeyName(table.table, name),
4934
+ name: foreignKeyName(table.table, name2),
4743
4935
  columns: [self[link.on]],
4744
4936
  foreignColumns: [targetColumn]
4745
4937
  });
@@ -4796,21 +4988,21 @@ function diffStatements(previous, current) {
4796
4988
  function assertUnambiguousDiff(previous, current) {
4797
4989
  const previousTables = tablesOf(previous);
4798
4990
  const currentTables = tablesOf(current);
4799
- const removedTables = [...previousTables.keys()].filter((name) => !currentTables.has(name));
4800
- const addedTables = [...currentTables.keys()].filter((name) => !previousTables.has(name));
4991
+ const removedTables = [...previousTables.keys()].filter((name2) => !currentTables.has(name2));
4992
+ const addedTables = [...currentTables.keys()].filter((name2) => !previousTables.has(name2));
4801
4993
  if (removedTables.length > 0 && addedTables.length > 0) {
4802
4994
  throw new OrmDefinitionError(
4803
4995
  `ambiguous diff: table(s) added (${addedTables.join(", ")}) and removed (${removedTables.join(", ")}) in the same change \u2014 ship the add and the drop as separate changes`
4804
4996
  );
4805
4997
  }
4806
- for (const [name, previousColumns] of previousTables) {
4807
- const currentColumns = currentTables.get(name);
4998
+ for (const [name2, previousColumns] of previousTables) {
4999
+ const currentColumns = currentTables.get(name2);
4808
5000
  if (!currentColumns) continue;
4809
5001
  const removed = [...previousColumns].filter((column) => !currentColumns.has(column));
4810
5002
  const added = [...currentColumns].filter((column) => !previousColumns.has(column));
4811
5003
  if (removed.length > 0 && added.length > 0) {
4812
5004
  throw new OrmDefinitionError(
4813
- `ambiguous diff on '${name}': column(s) added (${added.join(", ")}) and removed (${removed.join(", ")}) in the same change \u2014 declare \`renamed_from\` for a rename, or ship the add and the drop as separate changes`
5005
+ `ambiguous diff on '${name2}': column(s) added (${added.join(", ")}) and removed (${removed.join(", ")}) in the same change \u2014 declare \`renamed_from\` for a rename, or ship the add and the drop as separate changes`
4814
5006
  );
4815
5007
  }
4816
5008
  }
@@ -4829,33 +5021,33 @@ function applyMigrationHints(previous, definition) {
4829
5021
  for (const table of columnTables(definition)) {
4830
5022
  const snapshotTable = findTable(adjusted, schemaName, table.table);
4831
5023
  if (!snapshotTable) continue;
4832
- for (const [name, column] of Object.entries(table.columns ?? {})) {
5024
+ for (const [name2, column] of Object.entries(table.columns ?? {})) {
4833
5025
  if (column.renamed_from) {
4834
5026
  const previousColumn = snapshotTable.columns[column.renamed_from];
4835
- if (previousColumn && snapshotTable.columns[name]) {
5027
+ if (previousColumn && snapshotTable.columns[name2]) {
4836
5028
  throw new OrmDefinitionError(
4837
- `'${table.table}.${name}' declares renamed_from '${column.renamed_from}', but both columns exist in the previous schema \u2014 a rename cannot overwrite a live column`
5029
+ `'${table.table}.${name2}' declares renamed_from '${column.renamed_from}', but both columns exist in the previous schema \u2014 a rename cannot overwrite a live column`
4838
5030
  );
4839
5031
  }
4840
5032
  if (previousColumn) {
4841
5033
  statements.push(
4842
- `ALTER TABLE ${qualified(table.table)} RENAME COLUMN ${quoteIdentifier(column.renamed_from)} TO ${quoteIdentifier(name)}`
5034
+ `ALTER TABLE ${qualified(table.table)} RENAME COLUMN ${quoteIdentifier(column.renamed_from)} TO ${quoteIdentifier(name2)}`
4843
5035
  );
4844
5036
  delete snapshotTable.columns[column.renamed_from];
4845
- snapshotTable.columns[name] = { ...previousColumn, name };
4846
- } else if (!snapshotTable.columns[name]) {
5037
+ snapshotTable.columns[name2] = { ...previousColumn, name: name2 };
5038
+ } else if (!snapshotTable.columns[name2]) {
4847
5039
  throw new OrmDefinitionError(
4848
- `'${table.table}.${name}' declares renamed_from '${column.renamed_from}', but the previous schema has neither column \u2014 check the declared source name`
5040
+ `'${table.table}.${name2}' declares renamed_from '${column.renamed_from}', but the previous schema has neither column \u2014 check the declared source name`
4849
5041
  );
4850
5042
  }
4851
5043
  }
4852
5044
  const cast = column.cast ? castParts(column.cast) : null;
4853
5045
  if (cast) {
4854
- const current = snapshotTable.columns[name];
5046
+ const current = snapshotTable.columns[name2];
4855
5047
  const targetType = sqlTypeName(column.type);
4856
5048
  if (current && current.type !== targetType) {
4857
5049
  statements.push(
4858
- `ALTER TABLE ${qualified(table.table)} ALTER COLUMN ${quoteIdentifier(name)} TYPE ${targetType} USING ${quoteIdentifier(name)}::${targetType}`
5050
+ `ALTER TABLE ${qualified(table.table)} ALTER COLUMN ${quoteIdentifier(name2)} TYPE ${targetType} USING ${quoteIdentifier(name2)}::${targetType}`
4859
5051
  );
4860
5052
  current.type = targetType;
4861
5053
  }
@@ -4896,8 +5088,8 @@ function materializedRefreshFunctions(canonical) {
4896
5088
  }
4897
5089
  return functions;
4898
5090
  }
4899
- function refreshFunctionSql({ schema, name, table, compute, columns, pk }) {
4900
- const fn = `${quoteIdentifier(schema)}.${quoteIdentifier(materializedRefreshFunctionName(name))}`;
5091
+ function refreshFunctionSql({ schema, name: name2, table, compute, columns, pk }) {
5092
+ const fn = `${quoteIdentifier(schema)}.${quoteIdentifier(materializedRefreshFunctionName(name2))}`;
4901
5093
  const target = `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;
4902
5094
  const source = `${quoteIdentifier(schema)}.${quoteIdentifier(compute)}`;
4903
5095
  const list = columns.map(quoteIdentifier).join(", ");
@@ -4906,7 +5098,7 @@ function refreshFunctionSql({ schema, name, table, compute, columns, pk }) {
4906
5098
  const matches = pk.map((column) => `c.${quoteIdentifier(column)} = m.${quoteIdentifier(column)}`).join(" AND ");
4907
5099
  const onConflict = others.length === 0 ? "DO NOTHING" : `DO UPDATE SET ${others.map((column) => `${quoteIdentifier(column)} = EXCLUDED.${quoteIdentifier(column)}`).join(", ")}
4908
5100
  WHERE (${others.map((column) => `m.${quoteIdentifier(column)}`).join(", ")}) IS DISTINCT FROM (${others.map((column) => `EXCLUDED.${quoteIdentifier(column)}`).join(", ")})`;
4909
- const lockKey = quoteLiteral(materializeLockKey(schema, name));
5101
+ const lockKey = quoteLiteral(materializeLockKey(schema, name2));
4910
5102
  return `CREATE OR REPLACE FUNCTION ${fn}(wait boolean DEFAULT false)
4911
5103
  RETURNS TABLE(upserted bigint, deleted bigint, locked boolean)
4912
5104
  LANGUAGE plpgsql
@@ -4944,12 +5136,12 @@ $orm_refresh$`;
4944
5136
  function refreshFunctionStatements({ namespace, previous, current }) {
4945
5137
  const schema = quoteIdentifier(ormSchemaName(namespace));
4946
5138
  const statements = [];
4947
- for (const name of Object.keys(previous).sort()) {
4948
- if (!current.has(name)) statements.push(`DROP FUNCTION IF EXISTS ${schema}.${quoteIdentifier(materializedRefreshFunctionName(name))}(boolean)`);
5139
+ for (const name2 of Object.keys(previous).sort()) {
5140
+ if (!current.has(name2)) statements.push(`DROP FUNCTION IF EXISTS ${schema}.${quoteIdentifier(materializedRefreshFunctionName(name2))}(boolean)`);
4949
5141
  }
4950
- for (const [name, create] of [...current].sort(([a], [b]) => a.localeCompare(b))) {
4951
- if (previous[name] === create) continue;
4952
- const fn = `${schema}.${quoteIdentifier(materializedRefreshFunctionName(name))}(boolean)`;
5142
+ for (const [name2, create] of [...current].sort(([a], [b]) => a.localeCompare(b))) {
5143
+ if (previous[name2] === create) continue;
5144
+ const fn = `${schema}.${quoteIdentifier(materializedRefreshFunctionName(name2))}(boolean)`;
4953
5145
  statements.push(create, `REVOKE ALL ON FUNCTION ${fn} FROM PUBLIC`);
4954
5146
  }
4955
5147
  return statements;
@@ -4957,21 +5149,21 @@ function refreshFunctionStatements({ namespace, previous, current }) {
4957
5149
 
4958
5150
  // src/engine/canonical2.ts
4959
5151
  var FACTORIES2 = {
4960
- uuid: (name) => pgCore.uuid(name),
4961
- text: (name) => pgCore.text(name),
4962
- integer: (name) => pgCore.integer(name),
5152
+ uuid: (name2) => pgCore.uuid(name2),
5153
+ text: (name2) => pgCore.text(name2),
5154
+ integer: (name2) => pgCore.integer(name2),
4963
5155
  // Mode 'bigint' keeps int8 lossless — mode 'number' silently rounds past
4964
5156
  // 2^53. The read executor serializes BigInt to string for JSON.
4965
- bigint: (name) => pgCore.bigint(name, { mode: "bigint" }),
4966
- numeric: (name) => pgCore.numeric(name),
4967
- double: (name) => pgCore.doublePrecision(name),
4968
- boolean: (name) => pgCore.boolean(name),
4969
- timestamptz: (name) => pgCore.timestamp(name, { withTimezone: true }),
4970
- date: (name) => pgCore.date(name),
4971
- jsonb: (name) => pgCore.jsonb(name)
5157
+ bigint: (name2) => pgCore.bigint(name2, { mode: "bigint" }),
5158
+ numeric: (name2) => pgCore.numeric(name2),
5159
+ double: (name2) => pgCore.doublePrecision(name2),
5160
+ boolean: (name2) => pgCore.boolean(name2),
5161
+ timestamptz: (name2) => pgCore.timestamp(name2, { withTimezone: true }),
5162
+ date: (name2) => pgCore.date(name2),
5163
+ jsonb: (name2) => pgCore.jsonb(name2)
4972
5164
  };
4973
5165
  var SCHEMA_IMPORT_KEY2 = "$schema";
4974
- var enumImportKey = (name) => `$enum_${name}`;
5166
+ var enumImportKey = (name2) => `$enum_${name2}`;
4975
5167
  var columnTablesV2 = (definition) => definition.tables.filter((table) => !table.source);
4976
5168
  function buildDrizzleEntitiesV2(definition, options = {}) {
4977
5169
  const schemaName = ormSchemaName(definition.namespace);
@@ -5273,9 +5465,9 @@ function buildTable2(schema, table, built, enums, byName, introspection) {
5273
5465
  throw new OrmDefinitionError(`table '${table.table}' declares no primaryKey`);
5274
5466
  }
5275
5467
  const columnNames = new Set(table.columns.map((column) => column.columnName));
5276
- for (const name of primaryKeyColumns) {
5277
- if (!columnNames.has(name)) {
5278
- throw new OrmDefinitionError(`primaryKey of '${table.table}' references unknown column '${name}'`);
5468
+ for (const name2 of primaryKeyColumns) {
5469
+ if (!columnNames.has(name2)) {
5470
+ throw new OrmDefinitionError(`primaryKey of '${table.table}' references unknown column '${name2}'`);
5279
5471
  }
5280
5472
  }
5281
5473
  const singlePrimaryKey = primaryKeyColumns.length === 1 ? primaryKeyColumns[0] : void 0;
@@ -5361,8 +5553,8 @@ function buildIndexes2(table, self) {
5361
5553
  throw new OrmDefinitionError(`index on '${table.table}' references unknown column '${column}'`);
5362
5554
  }
5363
5555
  }
5364
- const name = indexName(table.table, definition);
5365
- const factory = definition.unique ? pgCore.uniqueIndex(name) : pgCore.index(name);
5556
+ const name2 = indexName(table.table, definition);
5557
+ const factory = definition.unique ? pgCore.uniqueIndex(name2) : pgCore.index(name2);
5366
5558
  const columns = definition.columns.map((column) => self[column]);
5367
5559
  return factory.on(...columns);
5368
5560
  });
@@ -5441,33 +5633,33 @@ function applyMigrationHintsV2(previous, definition) {
5441
5633
  const snapshotTable = findTable2(adjusted, schemaName, table.table);
5442
5634
  if (!snapshotTable) continue;
5443
5635
  for (const column of table.columns) {
5444
- const name = column.columnName;
5636
+ const name2 = column.columnName;
5445
5637
  if (column.renamedFrom) {
5446
5638
  const previousColumn = snapshotTable.columns[column.renamedFrom];
5447
- if (previousColumn && snapshotTable.columns[name]) {
5639
+ if (previousColumn && snapshotTable.columns[name2]) {
5448
5640
  throw new OrmDefinitionError(
5449
- `'${table.table}.${name}' declares renamedFrom '${column.renamedFrom}', but both columns exist in the previous schema \u2014 a rename cannot overwrite a live column`
5641
+ `'${table.table}.${name2}' declares renamedFrom '${column.renamedFrom}', but both columns exist in the previous schema \u2014 a rename cannot overwrite a live column`
5450
5642
  );
5451
5643
  }
5452
5644
  if (previousColumn) {
5453
5645
  statements.push(
5454
- `ALTER TABLE ${qualified(table.table)} RENAME COLUMN ${quoteIdentifier(column.renamedFrom)} TO ${quoteIdentifier(name)}`
5646
+ `ALTER TABLE ${qualified(table.table)} RENAME COLUMN ${quoteIdentifier(column.renamedFrom)} TO ${quoteIdentifier(name2)}`
5455
5647
  );
5456
5648
  delete snapshotTable.columns[column.renamedFrom];
5457
- snapshotTable.columns[name] = { ...previousColumn, name };
5458
- } else if (!snapshotTable.columns[name]) {
5649
+ snapshotTable.columns[name2] = { ...previousColumn, name: name2 };
5650
+ } else if (!snapshotTable.columns[name2]) {
5459
5651
  throw new OrmDefinitionError(
5460
- `'${table.table}.${name}' declares renamedFrom '${column.renamedFrom}', but the previous schema has neither column \u2014 check the declared source name`
5652
+ `'${table.table}.${name2}' declares renamedFrom '${column.renamedFrom}', but the previous schema has neither column \u2014 check the declared source name`
5461
5653
  );
5462
5654
  }
5463
5655
  }
5464
5656
  const cast = column.cast ? castParts(column.cast) : null;
5465
5657
  if (cast) {
5466
- const current = snapshotTable.columns[name];
5658
+ const current = snapshotTable.columns[name2];
5467
5659
  const { snapshotType, sqlType } = castTargetTypes(column, enumsByName, schemaName, table.table);
5468
5660
  if (current && current.type !== snapshotType) {
5469
5661
  statements.push(
5470
- `ALTER TABLE ${qualified(table.table)} ALTER COLUMN ${quoteIdentifier(name)} TYPE ${sqlType} USING ${quoteIdentifier(name)}::${sqlType}`
5662
+ `ALTER TABLE ${qualified(table.table)} ALTER COLUMN ${quoteIdentifier(name2)} TYPE ${sqlType} USING ${quoteIdentifier(name2)}::${sqlType}`
5471
5663
  );
5472
5664
  current.type = snapshotType;
5473
5665
  }
@@ -5478,8 +5670,8 @@ function applyMigrationHintsV2(previous, definition) {
5478
5670
  }
5479
5671
  function castTargetTypes(column, enums, schemaName, table) {
5480
5672
  if (typeof column.type === "string") {
5481
- const name = sqlTypeName(column.type);
5482
- return { snapshotType: name, sqlType: name };
5673
+ const name2 = sqlTypeName(column.type);
5674
+ return { snapshotType: name2, sqlType: name2 };
5483
5675
  }
5484
5676
  const enumName = column.type.enum;
5485
5677
  if (!enums.has(enumName)) {
@@ -5564,11 +5756,11 @@ async function planWithViewRecreation({
5564
5756
  })
5565
5757
  });
5566
5758
  const dropOrder = topologicalViewNames(
5567
- new Set([...affected].filter((name) => previousViews.has(name))),
5759
+ new Set([...affected].filter((name2) => previousViews.has(name2))),
5568
5760
  previousDependencies
5569
5761
  ).reverse();
5570
5762
  const createOrder = topologicalViewNames(
5571
- new Set([...affected].filter((name) => currentViews.has(name))),
5763
+ new Set([...affected].filter((name2) => currentViews.has(name2))),
5572
5764
  currentDependencies
5573
5765
  );
5574
5766
  const dropDdl = await generatedViewStatements({
@@ -5585,14 +5777,14 @@ async function planWithViewRecreation({
5585
5777
  });
5586
5778
  const currentViewDefinitions = new Map((canonical.views ?? []).map((view) => [view.view, view]));
5587
5779
  const statements = [
5588
- ...dropOrder.map((name) => ({ kind: "ddl", sql: requiredViewStatement(dropDdl, name, schema, "DROP") })),
5780
+ ...dropOrder.map((name2) => ({ kind: "ddl", sql: requiredViewStatement(dropDdl, name2, schema, "DROP") })),
5589
5781
  ...hints.statements.map((statement) => ({ kind: "hint", sql: statement })),
5590
5782
  ...baseDdl.map((statement) => ({ kind: "ddl", sql: statement.replace(/;\s*$/, "") })),
5591
5783
  ...foreignKeyTimingStatements(canonical, previous, baseDdl).map((sql7) => ({ kind: "ddl", sql: sql7 })),
5592
- ...createOrder.map((name) => ({ kind: "ddl", sql: requiredViewStatement(createDdl, name, schema, "CREATE") })),
5593
- ...createOrder.map((name) => {
5594
- const view = currentViewDefinitions.get(name);
5595
- if (!view) throw new OrmDefinitionError(`missing canonical definition for view '${name}'`);
5784
+ ...createOrder.map((name2) => ({ kind: "ddl", sql: requiredViewStatement(createDdl, name2, schema, "CREATE") })),
5785
+ ...createOrder.map((name2) => {
5786
+ const view = currentViewDefinitions.get(name2);
5787
+ if (!view) throw new OrmDefinitionError(`missing canonical definition for view '${name2}'`);
5596
5788
  return { kind: "ddl", sql: validateViewCatalogStatement({ canonical, view, schema }) };
5597
5789
  }),
5598
5790
  ...refreshFunctionStatements({
@@ -5622,9 +5814,9 @@ function foreignKeyTimingStatements(canonical, previous, baseDdl) {
5622
5814
  }
5623
5815
  return result;
5624
5816
  }
5625
- function foreignKeyTimingSql(schema, table, name, timing) {
5817
+ function foreignKeyTimingSql(schema, table, name2, timing) {
5626
5818
  const clause = timing === void 0 ? "NOT DEFERRABLE" : timing === "initially-deferred" ? "DEFERRABLE INITIALLY DEFERRED" : "DEFERRABLE INITIALLY IMMEDIATE";
5627
- return `ALTER TABLE ${quoteIdentifier(schema)}.${quoteIdentifier(table)} ALTER CONSTRAINT ${quoteIdentifier(name)} ${clause}`;
5819
+ return `ALTER TABLE ${quoteIdentifier(schema)}.${quoteIdentifier(table)} ALTER CONSTRAINT ${quoteIdentifier(name2)} ${clause}`;
5628
5820
  }
5629
5821
  function validateViewCatalogStatement({
5630
5822
  canonical,
@@ -5766,7 +5958,7 @@ function viewReach({
5766
5958
  if (viewRecreation === "all-on-base-change") return "all";
5767
5959
  if (baseDdl.some((statement) => DROPS_TYPE.test(statement))) return "all";
5768
5960
  const dependencies = snapshotViewDependencies(adjusted);
5769
- if ([...snapshotViews(adjusted).keys()].some((name) => dependencies[name] === void 0)) return "all";
5961
+ if ([...snapshotViews(adjusted).keys()].some((name2) => dependencies[name2] === void 0)) return "all";
5770
5962
  return baseChangesReachingViews({ previous, adjusted, current });
5771
5963
  }
5772
5964
  var SNAPSHOT_BOOKKEEPING = /* @__PURE__ */ new Set(["id", "prevId", "version", "dialect", "_meta", "views", "_sequenceOrm", "enums"]);
@@ -5815,8 +6007,8 @@ function tableChangeReachesViews({ was, is: is2 }) {
5815
6007
  if (field === "columns" || VIEW_SAFE_TABLE_FIELDS.has(field)) continue;
5816
6008
  if (stableJson(was[field]) !== stableJson(is2[field])) return true;
5817
6009
  }
5818
- return Object.entries(was.columns).some(([name, column]) => {
5819
- const next = is2.columns[name];
6010
+ return Object.entries(was.columns).some(([name2, column]) => {
6011
+ const next = is2.columns[name2];
5820
6012
  if (!next) return true;
5821
6013
  return [.../* @__PURE__ */ new Set([...Object.keys(column), ...Object.keys(next)])].some(
5822
6014
  (field) => !VIEW_SAFE_COLUMN_FIELDS.has(field) && stableJson(column[field]) !== stableJson(next[field])
@@ -5842,22 +6034,22 @@ function affectedViewNames({
5842
6034
  }) {
5843
6035
  const allNames = /* @__PURE__ */ new Set([...previousViews.keys(), ...currentViews.keys()]);
5844
6036
  if (reach === "all") return allNames;
5845
- const dependenciesOf = (name) => /* @__PURE__ */ new Set([...previousDependencies[name] ?? [], ...currentDependencies[name] ?? []]);
6037
+ const dependenciesOf = (name2) => /* @__PURE__ */ new Set([...previousDependencies[name2] ?? [], ...currentDependencies[name2] ?? []]);
5846
6038
  const affected = new Set(
5847
- [...allNames].filter((name) => {
5848
- const before = previousViews.get(name);
5849
- const after = currentViews.get(name);
6039
+ [...allNames].filter((name2) => {
6040
+ const before = previousViews.get(name2);
6041
+ const after = currentViews.get(name2);
5850
6042
  if (before === void 0 || after === void 0 || stableJson(before) !== stableJson(after)) return true;
5851
- return [...dependenciesOf(name)].some((dependency) => reach.has(dependency));
6043
+ return [...dependenciesOf(name2)].some((dependency) => reach.has(dependency));
5852
6044
  })
5853
6045
  );
5854
6046
  let grew = true;
5855
6047
  while (grew) {
5856
6048
  grew = false;
5857
- for (const name of allNames) {
5858
- if (affected.has(name)) continue;
5859
- if ([...dependenciesOf(name)].some((dependency) => affected.has(dependency))) {
5860
- affected.add(name);
6049
+ for (const name2 of allNames) {
6050
+ if (affected.has(name2)) continue;
6051
+ if ([...dependenciesOf(name2)].some((dependency) => affected.has(dependency))) {
6052
+ affected.add(name2);
5861
6053
  grew = true;
5862
6054
  }
5863
6055
  }
@@ -5868,13 +6060,13 @@ function topologicalViewNames(names, dependencies) {
5868
6060
  const remaining = new Set(names);
5869
6061
  const ordered = [];
5870
6062
  while (remaining.size > 0) {
5871
- const ready = [...remaining].filter((name) => (dependencies[name] ?? []).every((dependency) => !remaining.has(dependency))).sort();
6063
+ const ready = [...remaining].filter((name2) => (dependencies[name2] ?? []).every((dependency) => !remaining.has(dependency))).sort();
5872
6064
  if (ready.length === 0) {
5873
6065
  throw new OrmDefinitionError(`view dependencies form a cycle among: ${[...remaining].sort().join(", ")}`);
5874
6066
  }
5875
- for (const name of ready) {
5876
- ordered.push(name);
5877
- remaining.delete(name);
6067
+ for (const name2 of ready) {
6068
+ ordered.push(name2);
6069
+ remaining.delete(name2);
5878
6070
  }
5879
6071
  }
5880
6072
  return ordered;
@@ -5892,18 +6084,18 @@ async function generatedViewStatements({
5892
6084
  holder.views = Object.fromEntries(Object.entries(views).filter(([, view]) => !names.has(view.name)));
5893
6085
  const generated = mode === "drop" ? await diffStatements(snapshot, without) : await diffStatements(without, snapshot);
5894
6086
  const statements = /* @__PURE__ */ new Map();
5895
- for (const name of names) {
5896
- const qualified = `${quoteIdentifier(schema)}.${quoteIdentifier(name)}`;
6087
+ for (const name2 of names) {
6088
+ const qualified = `${quoteIdentifier(schema)}.${quoteIdentifier(name2)}`;
5897
6089
  const prefix = mode === "drop" ? "DROP VIEW" : "CREATE VIEW";
5898
6090
  const statement = generated.find((candidate) => candidate.trimStart().startsWith(`${prefix} ${qualified}`));
5899
- if (statement) statements.set(name, statement.replace(/;\s*$/, ""));
6091
+ if (statement) statements.set(name2, statement.replace(/;\s*$/, ""));
5900
6092
  }
5901
6093
  return statements;
5902
6094
  }
5903
- function requiredViewStatement(statements, name, schema, operation) {
5904
- const statement = statements.get(name);
6095
+ function requiredViewStatement(statements, name2, schema, operation) {
6096
+ const statement = statements.get(name2);
5905
6097
  if (!statement) {
5906
- throw new OrmDefinitionError(`drizzle-kit did not generate ${operation} VIEW for '${schema}.${name}'`);
6098
+ throw new OrmDefinitionError(`drizzle-kit did not generate ${operation} VIEW for '${schema}.${name2}'`);
5907
6099
  }
5908
6100
  return statement;
5909
6101
  }
@@ -6149,9 +6341,13 @@ function renderOrmMigrationExport(exported) {
6149
6341
  if (Buffer.byteLength(text4, "utf8") > ORM_MIGRATION_EXPORT_MAX_BYTES) throw new Error("ORM migration export exceeds the size limit");
6150
6342
  return text4;
6151
6343
  }
6152
- var IR_VERSION = 2;
6344
+ var IR_VERSION = 5;
6153
6345
  var LEGACY_IR_VERSION = 1;
6154
- var irVersionSchema = zod.z.union([zod.z.literal(LEGACY_IR_VERSION), zod.z.literal(IR_VERSION)]);
6346
+ var GUARDED_IR_VERSION = 2;
6347
+ var COMPOSED_IR_VERSION = 3;
6348
+ var SQL_IR_VERSION = 4;
6349
+ var RUNTIME_SQL_IR_VERSION = 5;
6350
+ var irVersionSchema = zod.z.union([zod.z.literal(LEGACY_IR_VERSION), zod.z.literal(GUARDED_IR_VERSION), zod.z.literal(COMPOSED_IR_VERSION), zod.z.literal(SQL_IR_VERSION), zod.z.literal(RUNTIME_SQL_IR_VERSION)]);
6155
6351
  var operationVersionSchema = zod.z.object({ irVersion: irVersionSchema });
6156
6352
  function requiredArtifactIrVersion(operations) {
6157
6353
  let required = LEGACY_IR_VERSION;
@@ -6203,8 +6399,8 @@ var predIrSchema = zod.z.lazy(
6203
6399
  value: zod.z.number(),
6204
6400
  where: predIrSchema.optional()
6205
6401
  }),
6206
- zod.z.object({ kind: zod.z.literal("capability"), key: zod.z.string() }),
6207
- zod.z.object({ kind: zod.z.literal("role"), key: zod.z.string() }),
6402
+ zod.z.object({ kind: zod.z.literal("capability"), key: zod.z.string(), namespace: zod.z.string().optional() }),
6403
+ zod.z.object({ kind: zod.z.literal("role"), key: zod.z.string(), namespace: zod.z.string().optional() }),
6208
6404
  zod.z.object({ kind: zod.z.literal("dynamicFilter"), slot: zod.z.string() }),
6209
6405
  zod.z.object({ kind: zod.z.literal("const"), value: zod.z.boolean() })
6210
6406
  ])
@@ -6431,7 +6627,31 @@ var variableIrSchema = zod.z.object({
6431
6627
  /** Absent = no default declared; see {@link variableDefaultIrSchema}. */
6432
6628
  defaultValue: variableDefaultIrSchema.optional()
6433
6629
  });
6630
+ var sqlColumnSchema = zod.z.object({ name: zod.z.string(), type: zod.z.enum(["text", "boolean", "integer", "bigint", "numeric", "double", "uuid", "date", "timestamptz"]), nullable: zod.z.boolean() });
6434
6631
  var compiledOperationSchema = zod.z.object({
6632
+ language: zod.z.literal("sql").optional(),
6633
+ /** Server-compiled object catalog and permission ceiling, never caller SQL. */
6634
+ sqlQuery: zod.z.object({
6635
+ catalog: zod.z.object({
6636
+ identity: zod.z.string(),
6637
+ objects: zod.z.array(zod.z.object({
6638
+ ref: zod.z.string(),
6639
+ table: zod.z.string(),
6640
+ columns: zod.z.array(sqlColumnSchema.extend({ type: zod.z.string() })).min(1),
6641
+ scan: zod.z.string().min(1),
6642
+ read: zod.z.array(zod.z.string()).min(1)
6643
+ }).strict()).min(1).max(256)
6644
+ }).strict(),
6645
+ read: zod.z.array(zod.z.string()).min(1).max(256),
6646
+ maxRows: zod.z.number().int().min(1).max(1e4)
6647
+ }).strict().optional(),
6648
+ sql: zod.z.object({
6649
+ text: zod.z.string().min(1).max(1048576),
6650
+ columns: zod.z.array(sqlColumnSchema).min(1).max(256),
6651
+ parameters: zod.z.array(zod.z.string()).max(128),
6652
+ read: zod.z.array(zod.z.string()).min(1).max(256),
6653
+ maxRows: zod.z.number().int().min(1).max(1e4)
6654
+ }).strict().optional(),
6435
6655
  irVersion: irVersionSchema,
6436
6656
  name: zod.z.string(),
6437
6657
  opHash: zod.z.string().regex(/^sha256:[0-9a-f]{64}$/),
@@ -6443,8 +6663,16 @@ var compiledOperationSchema = zod.z.object({
6443
6663
  variables: zod.z.array(variableIrSchema),
6444
6664
  /** Every table the op touches — data-token scoping + audit. */
6445
6665
  tableSet: zod.z.array(zod.z.string()).min(1),
6446
- roots: zod.z.array(rootIrSchema).min(1)
6666
+ roots: zod.z.array(rootIrSchema)
6447
6667
  }).superRefine((operation, ctx) => {
6668
+ if (operation.language === "sql") {
6669
+ const validPlan = operation.sqlQuery ? !operation.sql && operation.irVersion === RUNTIME_SQL_IR_VERSION : !!operation.sql && operation.irVersion === SQL_IR_VERSION;
6670
+ if (!validPlan || operation.kind !== "query" || operation.roots.length !== 0 || !operation.requires?.capability) {
6671
+ ctx.addIssue({ code: "custom", message: "SQL operations require a query-only v4 plan or v5 runtime contract, capability, and no GraphQL roots" });
6672
+ }
6673
+ } else if (operation.sql || operation.sqlQuery || operation.roots.length === 0) {
6674
+ ctx.addIssue({ code: "custom", message: "GraphQL operations require roots and cannot carry SQL" });
6675
+ }
6448
6676
  for (const [index3, root] of operation.roots.entries()) {
6449
6677
  if (root.kind !== "mutation" || root.assertAffectedRows === void 0) continue;
6450
6678
  if (operation.irVersion < 2 || operation.kind !== "mutation" || root.includeIf !== void 0) {
@@ -6491,11 +6719,16 @@ var resolvedMetaIrSchema = zod.z.object({
6491
6719
  });
6492
6720
  var tableMetaIrSchema = zod.z.object({
6493
6721
  table: zod.z.string(),
6722
+ namespace: zod.z.string().optional(),
6723
+ dependencies: zod.z.array(zod.z.string()).optional(),
6724
+ foreignReferences: zod.z.array(zod.z.object({ column: zod.z.string(), target: zod.z.string(), targetColumn: zod.z.string() })).optional(),
6725
+ exportRead: zod.z.union([zod.z.literal(true), zod.z.object({ capability: zod.z.string() }), zod.z.object({ role: zod.z.string() })]).optional(),
6726
+ exportWrite: zod.z.union([zod.z.literal(true), zod.z.object({ capability: zod.z.string() }), zod.z.object({ role: zod.z.string() })]).optional(),
6494
6727
  schema: zod.z.string(),
6495
6728
  typename: zod.z.string(),
6496
6729
  /**
6497
6730
  * True when statements over this relation evaluate a claims-gated synced
6498
- * view: synced twins (`source: gold.*`) materialize as views whose baked
6731
+ * view: synced twins (`source: schema.table`) materialize as views whose baked
6499
6732
  * policy reads `current_setting('request.jwt.claims')`, and namespace views
6500
6733
  * inherit the gate transitively through their declared dependencies. The
6501
6734
  * executor must stamp that GUC (transaction-scoped) before any statement
@@ -6554,13 +6787,21 @@ var compiledArtifactSchema = zod.z.object({
6554
6787
  irVersion: irVersionSchema,
6555
6788
  namespace: zod.z.string(),
6556
6789
  schemaHash: zod.z.string(),
6790
+ ownSchemaHash: zod.z.string().optional(),
6791
+ dependencies: zod.z.record(zod.z.string(), zod.z.string()).optional(),
6792
+ readPolicies: zod.z.record(zod.z.string(), predIrSchema).optional(),
6557
6793
  opsHash: zod.z.string(),
6794
+ /** Apply-observed synced objects without a serving backing; not part of the authored schema hash. */
6795
+ unbackedTables: zod.z.array(zod.z.string()).optional(),
6558
6796
  tables: zod.z.record(zod.z.string(), tableMetaIrSchema),
6559
6797
  operations: zod.z.record(zod.z.string(), compiledOperationSchema)
6560
6798
  }).superRefine((artifact, ctx) => {
6561
- for (const [name, operation] of Object.entries(artifact.operations)) {
6799
+ if (Object.keys(artifact.dependencies ?? {}).length > 0 && artifact.irVersion < COMPOSED_IR_VERSION) {
6800
+ ctx.addIssue({ code: "custom", path: ["irVersion"], message: "cross-namespace dependencies require IR v3" });
6801
+ }
6802
+ for (const [name2, operation] of Object.entries(artifact.operations)) {
6562
6803
  if (operation.irVersion > artifact.irVersion) {
6563
- ctx.addIssue({ code: "custom", path: ["operations", name, "irVersion"], message: "operation requires a newer IR version than its artifact" });
6804
+ ctx.addIssue({ code: "custom", path: ["operations", name2, "irVersion"], message: "operation requires a newer IR version than its artifact" });
6564
6805
  }
6565
6806
  }
6566
6807
  });
@@ -6573,7 +6814,7 @@ var IrVersionError = class extends Error {
6573
6814
  function normalizeIr(raw) {
6574
6815
  if (!raw || typeof raw !== "object") throw new IrVersionError(void 0);
6575
6816
  const version = raw.irVersion;
6576
- if (version !== LEGACY_IR_VERSION && version !== IR_VERSION) throw new IrVersionError(version);
6817
+ if (!irVersionSchema.safeParse(version).success) throw new IrVersionError(version);
6577
6818
  return compiledArtifactSchema.parse(raw);
6578
6819
  }
6579
6820
  function indexByHash(artifact) {
@@ -6606,10 +6847,10 @@ function buildNamespaceDefinition(files, config) {
6606
6847
  }
6607
6848
  const actionsSeen = /* @__PURE__ */ new Map();
6608
6849
  for (const { file, table } of files) {
6609
- for (const name of Object.keys(table.actions ?? {})) {
6610
- const existing = actionsSeen.get(name);
6611
- if (existing) throw new OrmDefinitionError(`action '${name}' is already defined in ${existing}`, file);
6612
- actionsSeen.set(name, file);
6850
+ for (const name2 of Object.keys(table.actions ?? {})) {
6851
+ const existing = actionsSeen.get(name2);
6852
+ if (existing) throw new OrmDefinitionError(`action '${name2}' is already defined in ${existing}`, file);
6853
+ actionsSeen.set(name2, file);
6613
6854
  }
6614
6855
  }
6615
6856
  const capabilities = config?.capabilities ? { roles: config.capabilities.roles ?? EMPTY_CAPABILITIES.roles, uses: config.capabilities.uses ?? [] } : EMPTY_CAPABILITIES;
@@ -6652,12 +6893,12 @@ function validateActionValidates(files, byName) {
6652
6893
  }
6653
6894
  function validateIndexNames(files) {
6654
6895
  const seen = /* @__PURE__ */ new Map();
6655
- const claim = (name, label, file) => {
6656
- const existing = seen.get(name);
6896
+ const claim = (name2, label, file) => {
6897
+ const existing = seen.get(name2);
6657
6898
  if (existing) {
6658
- throw new OrmDefinitionError(`relation name '${name}' (${label}) collides with ${existing}`, file);
6899
+ throw new OrmDefinitionError(`relation name '${name2}' (${label}) collides with ${existing}`, file);
6659
6900
  }
6660
- seen.set(name, `${label} (${file})`);
6901
+ seen.set(name2, `${label} (${file})`);
6661
6902
  };
6662
6903
  for (const { file, table } of files) {
6663
6904
  claim(table.table, `table '${table.table}'`, file);
@@ -6665,9 +6906,9 @@ function validateIndexNames(files) {
6665
6906
  for (const { file, table } of files) {
6666
6907
  if (table.source) continue;
6667
6908
  claim(`${table.table}_pkey`, `implicit primary-key index of '${table.table}'`, file);
6668
- for (const [name, column] of Object.entries(table.columns ?? {})) {
6909
+ for (const [name2, column] of Object.entries(table.columns ?? {})) {
6669
6910
  if (column.unique && !column.primary_key) {
6670
- claim(`${table.table}_${name}_unique`, `implicit unique constraint of '${table.table}.${name}'`, file);
6911
+ claim(`${table.table}_${name2}_unique`, `implicit unique constraint of '${table.table}.${name2}'`, file);
6671
6912
  }
6672
6913
  }
6673
6914
  }
@@ -6679,20 +6920,20 @@ function validateIndexNames(files) {
6679
6920
  }
6680
6921
  function validateLocalLinks(files, byName) {
6681
6922
  for (const { file, table } of files) {
6682
- for (const [name, link] of Object.entries(table.links ?? {})) {
6923
+ for (const [name2, link] of Object.entries(table.links ?? {})) {
6683
6924
  if (isQualifiedReference(link.to)) continue;
6684
6925
  const target = byName.get(link.to);
6685
6926
  if (!target) {
6686
- throw new OrmDefinitionError(`link '${name}' references unknown table '${link.to}'`, file);
6927
+ throw new OrmDefinitionError(`link '${name2}' references unknown table '${link.to}'`, file);
6687
6928
  }
6688
6929
  if (link.enforce && target.source) {
6689
- throw new OrmDefinitionError(`link '${name}' cannot enforce a foreign key onto a synced table`, file);
6930
+ throw new OrmDefinitionError(`link '${name2}' cannot enforce a foreign key onto a synced table`, file);
6690
6931
  }
6691
6932
  const sourceType = table.columns?.[link.on]?.type;
6692
6933
  const targetPrimaryKey = Object.values(target.columns ?? {}).find((column) => column.primary_key);
6693
6934
  if (sourceType && targetPrimaryKey && columnTypeGroup(sourceType) !== columnTypeGroup(targetPrimaryKey.type)) {
6694
6935
  throw new OrmDefinitionError(
6695
- `link '${name}' can never join: '${link.on}' is ${sourceType} but '${link.to}' has a ${targetPrimaryKey.type} primary key`,
6936
+ `link '${name2}' can never join: '${link.on}' is ${sourceType} but '${link.to}' has a ${targetPrimaryKey.type} primary key`,
6696
6937
  file
6697
6938
  );
6698
6939
  }
@@ -6772,7 +7013,7 @@ function parseYaml(file, contents) {
6772
7013
  throw new OrmDefinitionError(error instanceof Error ? error.message : "invalid YAML", file);
6773
7014
  }
6774
7015
  }
6775
- var isDefinitionFile = (name) => DEFINITION_FILE_EXTENSIONS.some((extension) => path.extname(name) === extension);
7016
+ var isDefinitionFile = (name2) => DEFINITION_FILE_EXTENSIONS.some((extension) => path.extname(name2) === extension);
6776
7017
  async function listDefinitionFiles(dir) {
6777
7018
  const entries = await promises.readdir(dir, { withFileTypes: true });
6778
7019
  return entries.filter((entry) => entry.isFile() && isDefinitionFile(entry.name)).map((entry) => entry.name).sort();
@@ -6866,13 +7107,13 @@ async function readMigrationSql(dir, entry) {
6866
7107
  var checksumOf = (text4) => crypto.createHash("sha256").update(text4).digest("hex");
6867
7108
  var migrationName = (ordinal, contentHash) => `${pad(ordinal)}_${contentHash.slice(0, 12)}`;
6868
7109
  function renderMigrationSql({
6869
- name,
7110
+ name: name2,
6870
7111
  namespace,
6871
7112
  contentHash,
6872
7113
  plan
6873
7114
  }) {
6874
7115
  const header = [
6875
- `-- ${name}`,
7116
+ `-- ${name2}`,
6876
7117
  `-- namespace: ${namespace}`,
6877
7118
  `-- content hash: ${contentHash}`,
6878
7119
  "-- generated by `seq-studio orm diff` \u2014 review and commit, do not edit"
@@ -6888,13 +7129,13 @@ async function writeMigration({
6888
7129
  }) {
6889
7130
  const tip = workspace.journal.entries.at(-1);
6890
7131
  const ordinal = (tip?.ordinal ?? 0) + 1;
6891
- const name = migrationName(ordinal, contentHash);
6892
- const sql7 = renderMigrationSql({ name, namespace: workspace.journal.namespace, contentHash, plan });
7132
+ const name2 = migrationName(ordinal, contentHash);
7133
+ const sql7 = renderMigrationSql({ name: name2, namespace: workspace.journal.namespace, contentHash, plan });
6893
7134
  const metaDir = path.join(dir, MIGRATIONS_DIRNAME, META_DIRNAME);
6894
7135
  await promises.mkdir(metaDir, { recursive: true });
6895
7136
  const snapshotText = `${JSON.stringify(plan.snapshot, null, 2)}
6896
7137
  `;
6897
- await promises.writeFile(path.join(dir, MIGRATIONS_DIRNAME, `${name}.sql`), sql7);
7138
+ await promises.writeFile(path.join(dir, MIGRATIONS_DIRNAME, `${name2}.sql`), sql7);
6898
7139
  await promises.writeFile(path.join(metaDir, `${pad(ordinal)}.snapshot.json`), snapshotText);
6899
7140
  const journal = {
6900
7141
  ...workspace.journal,
@@ -6902,7 +7143,7 @@ async function writeMigration({
6902
7143
  ...workspace.journal.entries,
6903
7144
  {
6904
7145
  ordinal,
6905
- name,
7146
+ name: name2,
6906
7147
  content_hash: contentHash,
6907
7148
  previous_content_hash: tip?.content_hash ?? null,
6908
7149
  checksum: checksumOf(sql7),
@@ -6913,7 +7154,7 @@ async function writeMigration({
6913
7154
  };
6914
7155
  await promises.writeFile(path.join(metaDir, JOURNAL_FILENAME), `${JSON.stringify(journal, null, 2)}
6915
7156
  `);
6916
- return { name, ordinal, destructive };
7157
+ return { name: name2, ordinal, destructive };
6917
7158
  }
6918
7159
  var pad = (ordinal) => String(ordinal).padStart(4, "0");
6919
7160
  function parseJson(path, raw) {
@@ -7087,15 +7328,15 @@ function convertV1DefinitionToCanonical(definition) {
7087
7328
  }
7088
7329
  function convertTable(table) {
7089
7330
  const columns = Object.entries(table.columns ?? {});
7090
- const primaryKey2 = columns.filter(([, column]) => column.primary_key).map(([name]) => name);
7331
+ const primaryKey2 = columns.filter(([, column]) => column.primary_key).map(([name2]) => name2);
7091
7332
  return {
7092
7333
  table: table.table,
7093
7334
  description: table.description,
7094
7335
  source: table.source,
7095
- columns: columns.map(([name, column]) => convertColumn(name, column)),
7336
+ columns: columns.map(([name2, column]) => convertColumn(name2, column)),
7096
7337
  // Synced tables may declare a typed column/PK contract; untyped remain empty.
7097
7338
  primaryKey: primaryKey2.length > 0 ? primaryKey2 : void 0,
7098
- links: Object.entries(table.links ?? {}).map(([name, link]) => convertLink(table.table, name, link)),
7339
+ links: Object.entries(table.links ?? {}).map(([name2, link]) => convertLink(table.table, name2, link)),
7099
7340
  indexes: (table.indexes ?? []).map((index3) => ({
7100
7341
  columns: [...index3.columns],
7101
7342
  unique: index3.unique ?? false,
@@ -7112,11 +7353,11 @@ function convertTable(table) {
7112
7353
  actions: []
7113
7354
  };
7114
7355
  }
7115
- function convertColumn(name, column) {
7356
+ function convertColumn(name2, column) {
7116
7357
  const isDefaultFn = column.default !== void 0 && isFunctionDefault(column.default, column.type);
7117
7358
  return {
7118
- name,
7119
- columnName: name,
7359
+ name: name2,
7360
+ columnName: name2,
7120
7361
  type: column.type,
7121
7362
  nullable: column.primary_key ? false : column.nullable !== false,
7122
7363
  unique: column.unique === true,
@@ -7130,14 +7371,14 @@ function convertColumn(name, column) {
7130
7371
  deprecated: column.deprecated === true
7131
7372
  };
7132
7373
  }
7133
- function convertLink(table, name, link) {
7374
+ function convertLink(table, name2, link) {
7134
7375
  if (link.to.includes(".")) {
7135
7376
  throw new OrmDefinitionError(
7136
- `link '${name}' on '${table}' targets '${link.to}' \u2014 cross-namespace links have no canonical v2 representation (links are namespace-local in v2)`
7377
+ `link '${name2}' on '${table}' targets '${link.to}' \u2014 cross-namespace links have no canonical v2 representation (links are namespace-local in v2)`
7137
7378
  );
7138
7379
  }
7139
7380
  return {
7140
- name,
7381
+ name: name2,
7141
7382
  kind: "toOne",
7142
7383
  target: link.to,
7143
7384
  on: link.on,
@@ -7166,29 +7407,29 @@ function buildRebaseJournalEntry({ namespace, previousHash, newHash, ordinal, sn
7166
7407
  if (!Number.isInteger(ordinal) || ordinal < 2) {
7167
7408
  throw new OrmDefinitionError(`rebase ordinal must be an integer \u2265 2 (a rebase sits on an existing journal tip); got ${ordinal}`);
7168
7409
  }
7169
- const name = migrationName(ordinal, newHash);
7170
- const sql7 = renderRebaseMigrationSql({ name, namespace, previousHash, newHash });
7410
+ const name2 = migrationName(ordinal, newHash);
7411
+ const sql7 = renderRebaseMigrationSql({ name: name2, namespace, previousHash, newHash });
7171
7412
  const snapshotText = `${JSON.stringify(snapshot, null, 2)}
7172
7413
  `;
7173
7414
  const entry = {
7174
7415
  ordinal,
7175
- name,
7416
+ name: name2,
7176
7417
  content_hash: newHash,
7177
7418
  previous_content_hash: previousHash,
7178
7419
  checksum: checksumOf(sql7),
7179
7420
  snapshot_checksum: checksumOf(snapshotText),
7180
7421
  destructive: false
7181
7422
  };
7182
- return { name, entry, sql: sql7, snapshotText };
7423
+ return { name: name2, entry, sql: sql7, snapshotText };
7183
7424
  }
7184
7425
  function renderRebaseMigrationSql({
7185
- name,
7426
+ name: name2,
7186
7427
  namespace,
7187
7428
  previousHash,
7188
7429
  newHash
7189
7430
  }) {
7190
7431
  return [
7191
- `-- ${name}`,
7432
+ `-- ${name2}`,
7192
7433
  `-- namespace: ${namespace}`,
7193
7434
  `-- content hash: ${newHash}`,
7194
7435
  `-- rebase: v1 definitions (${previousHash}) converted to canonical v2 \u2014 verified no-op, zero statements`,
@@ -7262,8 +7503,8 @@ function canonicalActions(value) {
7262
7503
  const entries = Object.entries(value);
7263
7504
  if (entries.length === 0) return void 0;
7264
7505
  return Object.fromEntries(
7265
- entries.map(([name, action]) => [
7266
- name,
7506
+ entries.map(([name2, action]) => [
7507
+ name2,
7267
7508
  {
7268
7509
  description: action["description"] ?? void 0,
7269
7510
  requires: action["requires"] ?? void 0,
@@ -7276,6 +7517,526 @@ function canonicalActions(value) {
7276
7517
  ])
7277
7518
  );
7278
7519
  }
7520
+ var IMPORT_CONFLICT_MODES = ["error", "skip", "update"];
7521
+ var columnMapSchema = zod.z.object({
7522
+ /** ORM property name or Postgres column name. */
7523
+ target: zod.z.string().min(1).max(63),
7524
+ /** Column on the source relation. Identifiers only — never an expression. */
7525
+ source: zod.z.string().min(1).max(63),
7526
+ /**
7527
+ * Used when the source value is NULL. Required columns without a database
7528
+ * default fail the load if the source contains nulls and this is omitted.
7529
+ */
7530
+ nullDefault: zod.z.union([zod.z.string().max(1e4), zod.z.number(), zod.z.boolean()]).optional()
7531
+ }).strict();
7532
+ var importSpecSchema = zod.z.object({
7533
+ table: zod.z.string().min(1).max(63),
7534
+ from: zod.z.string().regex(QUALIFIED_TABLE_PATTERN),
7535
+ columns: zod.z.array(columnMapSchema).min(1).max(500),
7536
+ onConflict: zod.z.enum(IMPORT_CONFLICT_MODES).default("skip"),
7537
+ batchSize: zod.z.number().int().min(1).max(2e4).default(5e3)
7538
+ }).strict();
7539
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
7540
+ var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
7541
+ var TIMESTAMPTZ_RE = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})$/;
7542
+ var INTEGER_RE = /^-?\d+$/;
7543
+ var NUMERIC_RE = /^-?\d+(\.\d+)?$/;
7544
+ function sourceSchemaAllowed(schema) {
7545
+ return schema !== "information_schema" && !schema.startsWith("pg_");
7546
+ }
7547
+ function isRelationIdentifier(value) {
7548
+ return value.length <= 63 && IDENTIFIER_PATTERN.test(value);
7549
+ }
7550
+ function isSourceColumn(value) {
7551
+ return value.length <= 63 && COLUMN_IDENTIFIER_PATTERN.test(value);
7552
+ }
7553
+ function splitQualifiedRelation(from) {
7554
+ const dot = from.indexOf(".");
7555
+ if (dot <= 0 || dot !== from.lastIndexOf(".")) return null;
7556
+ const schema = from.slice(0, dot);
7557
+ const table = from.slice(dot + 1);
7558
+ if (!isRelationIdentifier(schema) || !isRelationIdentifier(table)) return null;
7559
+ return { schema, table };
7560
+ }
7561
+ function postgresTypeName(type) {
7562
+ if (type === "double") return "double precision";
7563
+ if (type === "timestamptz") return "timestamp with time zone";
7564
+ return type;
7565
+ }
7566
+ function columnPostgresType(column, schemaName, enums) {
7567
+ if (typeof column.type === "string") return postgresTypeName(column.type);
7568
+ if (!enums.has(column.type.enum)) return null;
7569
+ return `${quoteIdentifier(schemaName)}.${quoteIdentifier(column.type.enum)}`;
7570
+ }
7571
+ function quoteQualified(schema, table) {
7572
+ return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;
7573
+ }
7574
+ var INT4_MIN = -2147483648;
7575
+ var INT4_MAX = 2147483647;
7576
+ function resumeLiteralSql({
7577
+ column,
7578
+ after,
7579
+ schemaName,
7580
+ enums
7581
+ }) {
7582
+ const coerced = coerceResumeValue(column, after);
7583
+ if (!coerced.ok) return coerced;
7584
+ return literalSql({ column, value: coerced.value, schemaName, enums });
7585
+ }
7586
+ function coerceResumeValue(column, after) {
7587
+ const type = typeof column.type === "string" ? column.type : null;
7588
+ if (type === "integer") {
7589
+ if (!INTEGER_RE.test(after)) return { ok: false, error: `${column.name}: after must be an integer` };
7590
+ const parsed = Number(after);
7591
+ if (!Number.isSafeInteger(parsed) || parsed < INT4_MIN || parsed > INT4_MAX) {
7592
+ return { ok: false, error: `${column.name}: after must be an integer` };
7593
+ }
7594
+ return { ok: true, value: parsed };
7595
+ }
7596
+ if (type === "boolean") {
7597
+ if (after !== "true" && after !== "false") return { ok: false, error: `${column.name}: after must be true or false` };
7598
+ return { ok: true, value: after === "true" };
7599
+ }
7600
+ return { ok: true, value: after };
7601
+ }
7602
+ function literalSql({
7603
+ column,
7604
+ value,
7605
+ schemaName,
7606
+ enums
7607
+ }) {
7608
+ const label = column.name;
7609
+ if (typeof value === "string" && value.includes("\0")) {
7610
+ return { ok: false, error: `${label}: null default contains a NUL character` };
7611
+ }
7612
+ if (typeof column.type !== "string") {
7613
+ const enumDef = enums.get(column.type.enum);
7614
+ if (!enumDef) return { ok: false, error: `${label}: enum '${column.type.enum}' is not declared` };
7615
+ if (typeof value !== "string" || !enumDef.values.includes(value)) {
7616
+ return { ok: false, error: `${label}: null default must be one of ${enumDef.values.join(", ")}` };
7617
+ }
7618
+ const typeName = columnPostgresType(column, schemaName, enums);
7619
+ return { ok: true, sql: `${quoteLiteral(value)}::${typeName}` };
7620
+ }
7621
+ return scalarLiteral2({ column, type: column.type, value, label });
7622
+ }
7623
+ var SCALAR_LITERALS = {
7624
+ text: (value, label) => typeof value === "string" ? { ok: true, sql: quoteLiteral(value) } : { ok: false, error: `${label}: null default must be a string` },
7625
+ uuid: (value, label) => typeof value === "string" && UUID_RE.test(value) ? { ok: true, sql: `${quoteLiteral(value)}::uuid` } : { ok: false, error: `${label}: null default must be a UUID` },
7626
+ boolean: (value, label) => typeof value === "boolean" ? { ok: true, sql: value ? "TRUE" : "FALSE" } : { ok: false, error: `${label}: null default must be true or false` },
7627
+ integer: (value, label) => typeof value === "number" && Number.isSafeInteger(value) ? { ok: true, sql: String(value) } : { ok: false, error: `${label}: null default must be an integer` },
7628
+ bigint: (value, label) => typeof value === "string" && INTEGER_RE.test(value) ? { ok: true, sql: `${value}::bigint` } : { ok: false, error: `${label}: null default must be a base-10 integer string` },
7629
+ numeric: numericLiteral,
7630
+ double: numericLiteral,
7631
+ date: (value, label) => typeof value === "string" && DATE_RE.test(value) ? { ok: true, sql: `${quoteLiteral(value)}::date` } : { ok: false, error: `${label}: null default must be a YYYY-MM-DD date` },
7632
+ timestamptz: (value, label) => typeof value === "string" && TIMESTAMPTZ_RE.test(value) ? { ok: true, sql: `${quoteLiteral(value)}::${postgresTypeName("timestamptz")}` } : { ok: false, error: `${label}: null default must be an ISO-8601 timestamp` },
7633
+ jsonb: jsonbLiteral
7634
+ };
7635
+ function numericLiteral(value, label) {
7636
+ if (typeof value === "number" && Number.isFinite(value)) return { ok: true, sql: String(value) };
7637
+ if (typeof value === "string" && NUMERIC_RE.test(value)) return { ok: true, sql: value };
7638
+ return { ok: false, error: `${label}: null default must be a finite number` };
7639
+ }
7640
+ function scalarLiteral2({
7641
+ column,
7642
+ type,
7643
+ value,
7644
+ label
7645
+ }) {
7646
+ const encode = SCALAR_LITERALS[type];
7647
+ if (!encode) return { ok: false, error: `${column.name}: unsupported type '${type}'` };
7648
+ return encode(value, label);
7649
+ }
7650
+ function jsonbLiteral(value, label) {
7651
+ if (typeof value !== "string") return { ok: false, error: `${label}: null default must be a JSON string` };
7652
+ try {
7653
+ JSON.parse(value);
7654
+ } catch {
7655
+ return { ok: false, error: `${label}: null default must be valid JSON` };
7656
+ }
7657
+ return { ok: true, sql: `${quoteLiteral(value)}::jsonb` };
7658
+ }
7659
+ function dollarQuote(body) {
7660
+ const digest = crypto.createHash("sha256").update(body).digest("hex");
7661
+ const candidates = ["seq_orm_import", `seq_orm_${digest.slice(0, 16)}`, `seq_orm_${digest}`];
7662
+ const tag = candidates.find((candidate) => !body.includes(`$${candidate}$`)) ?? `seq_orm_${digest}_body`;
7663
+ return `$${tag}$${body}$${tag}$`;
7664
+ }
7665
+
7666
+ // src/import/script.ts
7667
+ function renderImportScript({
7668
+ namespace,
7669
+ schemaName,
7670
+ table,
7671
+ source,
7672
+ mapped,
7673
+ primaryKey: primaryKey2,
7674
+ onConflict,
7675
+ batchSize,
7676
+ omitted,
7677
+ resume
7678
+ }) {
7679
+ const sourceSql = `${quoteQualified(source.schema, source.table)} AS src`;
7680
+ const targetSql = quoteQualified(schemaName, table.table);
7681
+ const keys = primaryKey2.map((name2) => mapped.find((column) => column.column.columnName === name2)).filter((column) => column !== void 0);
7682
+ const probeSql = renderProbe({ sourceSql, keys, mapped });
7683
+ const procedure = renderProcedure({ targetSql, sourceSql, mapped, keys, onConflict, batchSize });
7684
+ const call = `CALL pg_temp.seq_orm_import(${resume.join(", ")});`;
7685
+ const omittedLine = omitted.length > 0 ? `-- Omitted columns keep their database default or NULL: ${omitted.join(", ")}` : "-- Every column is mapped.";
7686
+ const text4 = [
7687
+ "-- Sequence ORM data import",
7688
+ `-- namespace: ${namespace}`,
7689
+ `-- target: ${schemaName}.${table.table}`,
7690
+ `-- source: ${source.schema}.${source.table}`,
7691
+ `-- conflict: ${onConflict}`,
7692
+ `-- batch size: ${batchSize}`,
7693
+ "--",
7694
+ "-- Runs as the namespace owner. Does not evaluate insert or update policies,",
7695
+ "-- capability gates, or the operation journal. Sync the warehouse table into",
7696
+ "-- this Postgres relation first, review the probe, then run the load.",
7697
+ "-- skip and update are safe to re-run from the start after a failure. error stops on an existing key.",
7698
+ "-- Each batch commits. Do not resume from the maximum key in the target:",
7699
+ "-- a higher key that was already there would skip source rows this run never copied.",
7700
+ "-- --after is only the last key this procedure committed. This script does not print it.",
7701
+ omittedLine,
7702
+ "-- cast_* columns force every mapped value through the target type. An invalid value aborts before any insert.",
7703
+ "",
7704
+ probeSql,
7705
+ "",
7706
+ procedure,
7707
+ call,
7708
+ ""
7709
+ ].join("\n");
7710
+ return { probeSql, text: text4 };
7711
+ }
7712
+ function renderProbe({
7713
+ sourceSql,
7714
+ keys,
7715
+ mapped
7716
+ }) {
7717
+ const nullKey = keys.map((key) => `${key.expression} IS NULL`).join(" OR ");
7718
+ const distinct = keys.length === 1 ? keys[0].expression : `(${keys.map((key) => key.expression).join(", ")})`;
7719
+ const requiredNulls = nullChecked(mapped, keys).map((column) => `count(*) FILTER (WHERE src.${quoteIdentifier(column.source)} IS NULL) AS ${quoteIdentifier(`null_${column.column.columnName}`)}`);
7720
+ const selects = [
7721
+ "count(*) AS source_rows",
7722
+ `count(*) FILTER (WHERE ${nullKey}) AS null_primary_key`,
7723
+ `count(*) FILTER (WHERE NOT (${nullKey})) - count(DISTINCT ${distinct}) AS duplicate_primary_key`,
7724
+ ...requiredNulls,
7725
+ ...mapped.map((column) => `count(${column.expression}) AS ${quoteIdentifier(`cast_${column.column.columnName}`)}`)
7726
+ ];
7727
+ return `SELECT
7728
+ ${selects.join(",\n ")}
7729
+ FROM ${sourceSql};`;
7730
+ }
7731
+ function renderProcedure({
7732
+ targetSql,
7733
+ sourceSql,
7734
+ mapped,
7735
+ keys,
7736
+ onConflict,
7737
+ batchSize
7738
+ }) {
7739
+ const args = keys.map((key, index3) => `IN start_${index3} ${key.pgType} DEFAULT NULL`).join(", ");
7740
+ const declarations = [
7741
+ "DECLARE",
7742
+ " batch_scanned integer;",
7743
+ " batch_affected integer;",
7744
+ " total_rows bigint;",
7745
+ " null_keys bigint;",
7746
+ " distinct_keys bigint;",
7747
+ ...keys.map((key, index3) => ` watermark_${index3} ${key.pgType};`),
7748
+ ...requiredNullDeclarations(mapped, keys),
7749
+ ...mapped.map((column) => ` cast_${column.column.columnName} bigint;`)
7750
+ ];
7751
+ const body = [
7752
+ "BEGIN",
7753
+ ...keys.map((_, index3) => ` watermark_${index3} := start_${index3};`),
7754
+ ` ${renderGuard({ sourceSql, keys, mapped })}`,
7755
+ " LOOP",
7756
+ ` ${renderPage({ targetSql, sourceSql, mapped, keys, onConflict, batchSize })}`,
7757
+ " EXIT WHEN batch_scanned = 0;",
7758
+ " RAISE NOTICE 'orm import scanned % affected %', batch_scanned, batch_affected;",
7759
+ " COMMIT;",
7760
+ " END LOOP;",
7761
+ "END"
7762
+ ].join("\n");
7763
+ return [
7764
+ `CREATE OR REPLACE PROCEDURE pg_temp.seq_orm_import(${args})`,
7765
+ "LANGUAGE plpgsql",
7766
+ `AS ${dollarQuote(`
7767
+ ${declarations.join("\n")}
7768
+ ${body}
7769
+ `)}`,
7770
+ ";",
7771
+ ""
7772
+ ].join("\n");
7773
+ }
7774
+ function nullChecked(mapped, keys) {
7775
+ return mapped.filter((column) => !column.fillsNull && column.column.nullable === false && !keys.includes(column));
7776
+ }
7777
+ function requiredNullDeclarations(mapped, keys) {
7778
+ return nullChecked(mapped, keys).map((column) => ` null_${column.column.columnName} bigint;`);
7779
+ }
7780
+ function renderGuard({
7781
+ sourceSql,
7782
+ keys,
7783
+ mapped
7784
+ }) {
7785
+ const nullKey = keys.map((key) => `${key.expression} IS NULL`).join(" OR ");
7786
+ const distinct = keys.length === 1 ? keys[0].expression : `(${keys.map((key) => key.expression).join(", ")})`;
7787
+ const nullColumns = nullChecked(mapped, keys);
7788
+ const into = [
7789
+ "total_rows",
7790
+ "null_keys",
7791
+ "distinct_keys",
7792
+ ...nullColumns.map((column) => `null_${column.column.columnName}`),
7793
+ ...mapped.map((column) => `cast_${column.column.columnName}`)
7794
+ ];
7795
+ const selects = [
7796
+ "count(*)::bigint",
7797
+ `count(*) FILTER (WHERE ${nullKey})::bigint`,
7798
+ `count(DISTINCT ${distinct})::bigint`,
7799
+ ...nullColumns.map((column) => `count(*) FILTER (WHERE src.${quoteIdentifier(column.source)} IS NULL)::bigint`),
7800
+ ...mapped.map((column) => `count(${column.expression})::bigint`)
7801
+ ];
7802
+ const checks = [
7803
+ "IF null_keys > 0 THEN RAISE EXCEPTION 'import refused: source primary key has % null values', null_keys; END IF;",
7804
+ "IF total_rows <> distinct_keys THEN RAISE EXCEPTION 'import refused: source primary key has % duplicate values', total_rows - distinct_keys; END IF;",
7805
+ ...nullColumns.map(
7806
+ (column) => `IF null_${column.column.columnName} > 0 THEN RAISE EXCEPTION 'import refused: source column ${column.source} is null on % rows and ${column.column.columnName} is required', null_${column.column.columnName}; END IF;`
7807
+ )
7808
+ ];
7809
+ return [`SELECT ${selects.join(", ")}`, ` INTO ${into.join(", ")}`, ` FROM ${sourceSql};`, ...checks.map((check) => ` ${check}`)].join("\n");
7810
+ }
7811
+ function renderPage({
7812
+ targetSql,
7813
+ sourceSql,
7814
+ mapped,
7815
+ keys,
7816
+ onConflict,
7817
+ batchSize
7818
+ }) {
7819
+ const keyExprs = keys.map((key) => key.expression);
7820
+ const where = `watermark_0 IS NULL OR (${keyExprs.join(", ")}) > (${keys.map((_, index3) => `watermark_${index3}`).join(", ")})`;
7821
+ const order = keyExprs.join(", ");
7822
+ const pageColumns = mapped.map((column) => `${column.expression} AS ${quoteIdentifier(column.column.columnName)}`);
7823
+ const insertColumns = mapped.map((column) => quoteIdentifier(column.column.columnName)).join(", ");
7824
+ const conflict = conflictClause(onConflict, keys, mapped);
7825
+ const keyOrder = keys.map((key) => `${quoteIdentifier(key.column.columnName)} DESC`).join(", ");
7826
+ const lastKeys = keys.map((key) => `(SELECT ${quoteIdentifier(key.column.columnName)} FROM page ORDER BY ${keyOrder} LIMIT 1)`).join(", ");
7827
+ const watermarkTargets = keys.map((_, index3) => `watermark_${index3}`).join(", ");
7828
+ return [
7829
+ "WITH page AS (",
7830
+ ` SELECT ${pageColumns.join(", ")}`,
7831
+ ` FROM ${sourceSql}`,
7832
+ ` WHERE ${where}`,
7833
+ ` ORDER BY ${order}`,
7834
+ ` LIMIT ${batchSize}`,
7835
+ " ),",
7836
+ " ins AS (",
7837
+ ` INSERT INTO ${targetSql} (${insertColumns})`,
7838
+ ` SELECT ${insertColumns} FROM page`,
7839
+ ` ${conflict}`,
7840
+ " RETURNING 1",
7841
+ " )",
7842
+ ` SELECT (SELECT count(*)::int FROM page), (SELECT count(*)::int FROM ins), ${lastKeys}`,
7843
+ ` INTO batch_scanned, batch_affected, ${watermarkTargets};`
7844
+ ].join("\n");
7845
+ }
7846
+ function conflictClause(onConflict, keys, mapped) {
7847
+ if (onConflict === "error") return "";
7848
+ const target = keys.map((key) => quoteIdentifier(key.column.columnName)).join(", ");
7849
+ if (onConflict === "skip") return `ON CONFLICT (${target}) DO NOTHING`;
7850
+ const assignments = mapped.filter((column) => !keys.includes(column)).map((column) => `${quoteIdentifier(column.column.columnName)} = EXCLUDED.${quoteIdentifier(column.column.columnName)}`);
7851
+ return `ON CONFLICT (${target}) DO UPDATE SET ${assignments.join(", ")}`;
7852
+ }
7853
+
7854
+ // src/import/plan.ts
7855
+ function planTableImport({
7856
+ definition,
7857
+ spec,
7858
+ after
7859
+ }) {
7860
+ const parsedDefinition = canonicalDefinitionSchema.safeParse(definition);
7861
+ if (!parsedDefinition.success) return { ok: false, errors: ["namespace definition is not canonical ORM v2"] };
7862
+ const parsedSpec = importSpecSchema.safeParse(spec);
7863
+ if (!parsedSpec.success) {
7864
+ return { ok: false, errors: parsedSpec.error.issues.map((issue) => `${issue.path.join(".") || "spec"}: ${issue.message}`) };
7865
+ }
7866
+ return planParsed({ definition: parsedDefinition.data, spec: parsedSpec.data, after });
7867
+ }
7868
+ function planParsed({
7869
+ definition,
7870
+ spec,
7871
+ after
7872
+ }) {
7873
+ const source = splitQualifiedRelation(spec.from);
7874
+ const target = resolveTarget(definition, spec.table);
7875
+ const errors = [];
7876
+ if (!source) errors.push(`from '${spec.from}' is not a schema.table identifier`);
7877
+ else if (!sourceSchemaAllowed(source.schema)) errors.push(`from schema '${source.schema}' is not a warehouse relation`);
7878
+ if (!target.table) errors.push(...target.errors);
7879
+ if (!source || !target.table) return { ok: false, errors };
7880
+ const schemaName = ormSchemaName(definition.namespace);
7881
+ if (source.schema === schemaName && source.table === target.table.table) {
7882
+ errors.push(`from '${spec.from}' is the import target`);
7883
+ }
7884
+ const enums = new Map(definition.enums.map((entry) => [entry.name, entry]));
7885
+ const mapped = mapColumns({ table: target.table, spec, schemaName, enums, errors });
7886
+ const primaryKey2 = target.table.primaryKey ?? [];
7887
+ if (primaryKey2.length === 0) errors.push(`table '${target.table.table}' needs a primary key`);
7888
+ for (const key of primaryKey2) {
7889
+ if (!mapped.some((column) => column.column.columnName === key)) {
7890
+ errors.push(`primary key column '${key}' must be mapped so existing identities are preserved`);
7891
+ }
7892
+ }
7893
+ collectUnmapped({ table: target.table, mapped, errors });
7894
+ if (spec.onConflict === "update" && mapped.every((column) => primaryKey2.includes(column.column.columnName))) {
7895
+ errors.push('onConflict "update" needs a mapped column that is not part of the primary key');
7896
+ }
7897
+ const resume = resumeArguments({ mapped, primaryKey: primaryKey2, after, schemaName, enums, errors });
7898
+ if (errors.length > 0) return { ok: false, errors };
7899
+ const omitted = omittedColumns(target.table, mapped);
7900
+ const script = renderImportScript({
7901
+ namespace: definition.namespace,
7902
+ schemaName,
7903
+ table: target.table,
7904
+ source,
7905
+ mapped,
7906
+ primaryKey: primaryKey2,
7907
+ onConflict: spec.onConflict,
7908
+ batchSize: spec.batchSize,
7909
+ omitted,
7910
+ resume
7911
+ });
7912
+ const warnings = [
7913
+ "This load runs as the namespace owner. It does not evaluate insert or update policies.",
7914
+ ...spec.onConflict === "error" ? ['onConflict "error" is not safe to re-run: the first existing key aborts the batch.'] : []
7915
+ ];
7916
+ return {
7917
+ ok: true,
7918
+ plan: { probeSql: script.probeSql, script: script.text, batchSize: spec.batchSize, onConflict: spec.onConflict, warnings }
7919
+ };
7920
+ }
7921
+ function resolveTarget(definition, name2) {
7922
+ const table = definition.tables.find((candidate) => candidate.table === name2);
7923
+ if (!table) {
7924
+ const view = definition.views?.find((candidate) => candidate.view === name2);
7925
+ return { table: null, errors: [view ? `'${name2}' is a view, not an owned table` : `table '${name2}' is not in this namespace`] };
7926
+ }
7927
+ if (table.source !== void 0) return { table: null, errors: [`'${name2}' is a synced reflection and cannot be imported into`] };
7928
+ if (table.internal || table.materializes !== void 0) {
7929
+ return { table: null, errors: [`'${name2}' is an internal relation, not an import target`] };
7930
+ }
7931
+ return { table, errors: [] };
7932
+ }
7933
+ function mapColumns({
7934
+ table,
7935
+ spec,
7936
+ schemaName,
7937
+ enums,
7938
+ errors
7939
+ }) {
7940
+ const mapped = [];
7941
+ const seen = /* @__PURE__ */ new Set();
7942
+ for (const entry of spec.columns) {
7943
+ const column = findColumn(table, entry.target);
7944
+ if (column === "ambiguous") {
7945
+ errors.push(`target '${entry.target}' matches more than one column`);
7946
+ continue;
7947
+ }
7948
+ if (!column) {
7949
+ errors.push(`target '${entry.target}' is not a column of '${table.table}'`);
7950
+ continue;
7951
+ }
7952
+ if (column.cell !== void 0) {
7953
+ errors.push(`target '${entry.target}' is cell metadata and cannot be imported`);
7954
+ continue;
7955
+ }
7956
+ if (seen.has(column.columnName)) {
7957
+ errors.push(`column '${column.columnName}' is mapped more than once`);
7958
+ continue;
7959
+ }
7960
+ if (!isSourceColumn(entry.source)) {
7961
+ errors.push(`source '${entry.source}' is not a column identifier`);
7962
+ continue;
7963
+ }
7964
+ seen.add(column.columnName);
7965
+ const pgType = columnPostgresType(column, schemaName, enums);
7966
+ if (!pgType) {
7967
+ errors.push(`column '${column.name}' references undeclared enum '${typeof column.type === "string" ? column.type : column.type.enum}'`);
7968
+ continue;
7969
+ }
7970
+ const expression = valueExpression({ column, source: entry.source, pgType, nullDefault: entry.nullDefault, schemaName, enums, errors });
7971
+ if (expression) mapped.push({ column, source: entry.source, expression, pgType, fillsNull: entry.nullDefault !== void 0 });
7972
+ }
7973
+ return mapped;
7974
+ }
7975
+ function findColumn(table, target) {
7976
+ const matches = table.columns.filter((column) => column.name === target || column.columnName === target);
7977
+ if (matches.length > 1) return "ambiguous";
7978
+ return matches[0];
7979
+ }
7980
+ function valueExpression({
7981
+ column,
7982
+ source,
7983
+ pgType,
7984
+ nullDefault,
7985
+ schemaName,
7986
+ enums,
7987
+ errors
7988
+ }) {
7989
+ const cast = `CAST(src.${quoteIdentifier(source)} AS ${pgType})`;
7990
+ if (nullDefault === void 0) return cast;
7991
+ const literal2 = literalSql({ column, value: nullDefault, schemaName, enums });
7992
+ if (!literal2.ok) {
7993
+ errors.push(literal2.error);
7994
+ return null;
7995
+ }
7996
+ return `COALESCE(${cast}, ${literal2.sql})`;
7997
+ }
7998
+ function collectUnmapped({
7999
+ table,
8000
+ mapped,
8001
+ errors
8002
+ }) {
8003
+ const mappedNames = new Set(mapped.map((column) => column.column.columnName));
8004
+ const primaryKey2 = new Set(table.primaryKey ?? []);
8005
+ for (const column of table.columns) {
8006
+ if (mappedNames.has(column.columnName) || column.cell !== void 0) continue;
8007
+ const hasDefault = column.default !== void 0 && column.default !== null || column.defaultFn !== void 0;
8008
+ const required = column.nullable === false && !hasDefault && !primaryKey2.has(column.columnName);
8009
+ if (required) {
8010
+ errors.push(`column '${column.name}' is required and has no default \u2014 map it or set a database default before importing`);
8011
+ }
8012
+ }
8013
+ }
8014
+ function omittedColumns(table, mapped) {
8015
+ const mappedNames = new Set(mapped.map((column) => column.column.columnName));
8016
+ return table.columns.filter((column) => column.cell === void 0 && !mappedNames.has(column.columnName)).map((column) => column.columnName);
8017
+ }
8018
+ function resumeArguments({
8019
+ mapped,
8020
+ primaryKey: primaryKey2,
8021
+ after,
8022
+ schemaName,
8023
+ enums,
8024
+ errors
8025
+ }) {
8026
+ if (after === void 0) return primaryKey2.map(() => "NULL");
8027
+ if (primaryKey2.length !== 1) {
8028
+ errors.push("after resumes a single-column primary key; re-run from the start for a composite key (skip and update are idempotent)");
8029
+ return [];
8030
+ }
8031
+ const key = mapped.find((column) => column.column.columnName === primaryKey2[0]);
8032
+ if (!key) return [];
8033
+ const literal2 = resumeLiteralSql({ column: key.column, after, schemaName, enums });
8034
+ if (!literal2.ok) {
8035
+ errors.push(`after: ${literal2.error}`);
8036
+ return [];
8037
+ }
8038
+ return [literal2.sql];
8039
+ }
7279
8040
 
7280
8041
  Object.defineProperty(exports, "capabilityPinsSchema", {
7281
8042
  enumerable: true,
@@ -7315,14 +8076,17 @@ exports.COLUMN_DEFAULT_FNS = COLUMN_DEFAULT_FNS;
7315
8076
  exports.COLUMN_IDENTIFIER_PATTERN = COLUMN_IDENTIFIER_PATTERN;
7316
8077
  exports.COLUMN_TYPES = COLUMN_TYPES2;
7317
8078
  exports.COMPARE_OPS = COMPARE_OPS;
8079
+ exports.COMPOSED_IR_VERSION = COMPOSED_IR_VERSION;
7318
8080
  exports.CONSUMER_ROLE_SUFFIX = CONSUMER_ROLE_SUFFIX;
7319
8081
  exports.ColumnBuilder = ColumnBuilder;
7320
8082
  exports.DATE_BUCKETS = DATE_BUCKETS;
7321
8083
  exports.DEFINITION_FILE_EXTENSIONS = DEFINITION_FILE_EXTENSIONS;
7322
8084
  exports.ENUM_BRAND = ENUM_BRAND;
8085
+ exports.GUARDED_IR_VERSION = GUARDED_IR_VERSION;
7323
8086
  exports.HASH_DOMAIN = HASH_DOMAIN;
7324
8087
  exports.IDENTIFIER_PATTERN = IDENTIFIER_PATTERN;
7325
8088
  exports.IDENTIFIER_RE = IDENTIFIER_RE;
8089
+ exports.IMPORT_CONFLICT_MODES = IMPORT_CONFLICT_MODES;
7326
8090
  exports.INPUT_REF_KINDS = INPUT_REF_KINDS;
7327
8091
  exports.IR_VERSION = IR_VERSION;
7328
8092
  exports.IrVersionError = IrVersionError;
@@ -7352,7 +8116,9 @@ exports.QUALIFIED_TABLE_PATTERN = QUALIFIED_TABLE_PATTERN;
7352
8116
  exports.RESERVED_COLUMN_NAMES = RESERVED_COLUMN_NAMES;
7353
8117
  exports.RESERVED_TABLE_NAMES = RESERVED_TABLE_NAMES;
7354
8118
  exports.ROLES_CLAIM_KEY = ROLES_CLAIM_KEY;
8119
+ exports.RUNTIME_SQL_IR_VERSION = RUNTIME_SQL_IR_VERSION;
7355
8120
  exports.SCHEMA_DIR = SCHEMA_DIR;
8121
+ exports.SQL_IR_VERSION = SQL_IR_VERSION;
7356
8122
  exports.STATEMENT_KINDS = STATEMENT_KINDS;
7357
8123
  exports.SYNCED_CONTRACT_HASH_DOMAIN = SYNCED_CONTRACT_HASH_DOMAIN;
7358
8124
  exports.SYNCED_SOURCE_PATTERN = SYNCED_SOURCE_PATTERN;
@@ -7413,6 +8179,7 @@ exports.custom = custom;
7413
8179
  exports.declaredCapabilityKeys = declaredCapabilityKeys;
7414
8180
  exports.defineEnum = defineEnum;
7415
8181
  exports.defineNamespace = defineNamespace;
8182
+ exports.defineOperation = defineOperation;
7416
8183
  exports.defineResolvedTable = defineResolvedTable;
7417
8184
  exports.defineSyncedTable = defineSyncedTable;
7418
8185
  exports.defineTable = defineTable;
@@ -7431,6 +8198,7 @@ exports.generateSnapshot = generateSnapshot;
7431
8198
  exports.generateSnapshotV2 = generateSnapshotV2;
7432
8199
  exports.highest = highest;
7433
8200
  exports.identifierSchema = identifierSchema;
8201
+ exports.importSpecSchema = importSpecSchema;
7434
8202
  exports.indexByHash = indexByHash;
7435
8203
  exports.isColumnBuilder = isColumnBuilder;
7436
8204
  exports.isEnumRef = isEnumRef;
@@ -7460,6 +8228,8 @@ exports.nonNullFirst = nonNullFirst;
7460
8228
  exports.normalizeCanonical = normalizeCanonical;
7461
8229
  exports.normalizeIr = normalizeIr;
7462
8230
  exports.normalizeSnapshot = normalizeSnapshot;
8231
+ exports.objectRef = objectRef;
8232
+ exports.ontologyContractSchema = ontologyContractSchema;
7463
8233
  exports.orderIrSchema = orderIrSchema;
7464
8234
  exports.ormMigrationExportSchema = ormMigrationExportSchema;
7465
8235
  exports.ormSchemaName = ormSchemaName;
@@ -7476,6 +8246,7 @@ exports.pendingKitStatementsV2 = pendingKitStatementsV2;
7476
8246
  exports.planCommittedMigrationV2 = planCommittedMigrationV2;
7477
8247
  exports.planMigration = planMigration;
7478
8248
  exports.planMigrationV2 = planMigrationV2;
8249
+ exports.planTableImport = planTableImport;
7479
8250
  exports.policyExpressionSchema = policyExpressionSchema;
7480
8251
  exports.policyVariantSchema = policyVariantSchema;
7481
8252
  exports.predIrSchema = predIrSchema;
@@ -7487,6 +8258,7 @@ exports.quoteIdentifier = quoteIdentifier;
7487
8258
  exports.quoteLiteral = quoteLiteral;
7488
8259
  exports.readMigrationSql = readMigrationSql;
7489
8260
  exports.readMigrationWorkspace = readMigrationWorkspace;
8261
+ exports.readOntologyContract = readOntologyContract;
7490
8262
  exports.readSnapshot = readSnapshot;
7491
8263
  exports.rebaseViolations = rebaseViolations;
7492
8264
  exports.referencedCapabilities = referencedCapabilities;
@@ -7518,6 +8290,7 @@ exports.toMany = toMany;
7518
8290
  exports.toOne = toOne;
7519
8291
  exports.toPlatformUser = toPlatformUser;
7520
8292
  exports.typesInterfaceName = typesInterfaceName;
8293
+ exports.validateNamespaceCatalog = validateNamespaceCatalog;
7521
8294
  exports.validateViewCatalogStatement = validateViewCatalogStatement;
7522
8295
  exports.valueIrSchema = valueIrSchema;
7523
8296
  exports.variableDefaultIrSchema = variableDefaultIrSchema;