@sequenceholdings/orm 0.1.1 → 0.1.2

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 (63) hide show
  1. package/README.md +1 -1
  2. package/dist/authoring.cjs +794 -0
  3. package/dist/authoring.cjs.map +1 -0
  4. package/dist/authoring.d.cts +274 -0
  5. package/dist/authoring.d.ts +274 -0
  6. package/dist/authoring.js +763 -0
  7. package/dist/authoring.js.map +1 -0
  8. package/dist/canonical.cjs +146 -0
  9. package/dist/canonical.cjs.map +1 -0
  10. package/dist/canonical.d.cts +369 -0
  11. package/dist/canonical.d.ts +369 -0
  12. package/dist/canonical.js +131 -0
  13. package/dist/canonical.js.map +1 -0
  14. package/dist/cli.cjs +6172 -1683
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.d.cts +8 -1
  17. package/dist/cli.d.ts +8 -1
  18. package/dist/cli.js +6172 -1685
  19. package/dist/cli.js.map +1 -1
  20. package/dist/client.cjs +120 -0
  21. package/dist/client.cjs.map +1 -1
  22. package/dist/client.d.cts +74 -2
  23. package/dist/client.d.ts +74 -2
  24. package/dist/client.js +116 -1
  25. package/dist/client.js.map +1 -1
  26. package/dist/compiler.cjs +3001 -0
  27. package/dist/compiler.cjs.map +1 -0
  28. package/dist/compiler.d.cts +581 -0
  29. package/dist/compiler.d.ts +581 -0
  30. package/dist/compiler.js +2947 -0
  31. package/dist/compiler.js.map +1 -0
  32. package/dist/index.cjs +1705 -326
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +117 -56
  35. package/dist/index.d.ts +117 -56
  36. package/dist/index.js +1619 -323
  37. package/dist/index.js.map +1 -1
  38. package/dist/ir.cjs +407 -0
  39. package/dist/ir.cjs.map +1 -0
  40. package/dist/ir.d.cts +1179 -0
  41. package/dist/ir.d.ts +1179 -0
  42. package/dist/ir.js +388 -0
  43. package/dist/ir.js.map +1 -0
  44. package/dist/naming-CTvWSRTf.d.ts +79 -0
  45. package/dist/naming-DRyinU4u.d.cts +79 -0
  46. package/dist/sdl.cjs +833 -0
  47. package/dist/sdl.cjs.map +1 -0
  48. package/dist/sdl.d.cts +96 -0
  49. package/dist/sdl.d.ts +96 -0
  50. package/dist/sdl.js +809 -0
  51. package/dist/sdl.js.map +1 -0
  52. package/package.json +36 -3
  53. package/src/codegen-gql/apollo-hooks.cjs +98 -0
  54. package/src/codegen-gql/server-fns.cjs +101 -0
  55. package/templates/README.md +13 -0
  56. package/templates/orm-namespace/CLAUDE.md +81 -0
  57. package/templates/orm-namespace/codegen.ts +22 -0
  58. package/templates/orm-namespace/gitignore +5 -0
  59. package/templates/orm-namespace/graphql/example/queries.ts +56 -0
  60. package/templates/orm-namespace/package.json +24 -0
  61. package/templates/orm-namespace/schema/tables.ts +71 -0
  62. package/templates/orm-namespace/sequence.config.ts +32 -0
  63. package/templates/orm-namespace/tsconfig.json +15 -0
package/dist/index.cjs CHANGED
@@ -1,13 +1,865 @@
1
1
  'use strict';
2
2
 
3
+ var crypto = require('crypto');
3
4
  var zod = require('zod');
5
+ var jiti = require('jiti');
6
+ var promises = require('fs/promises');
7
+ var module$1 = require('module');
8
+ var path = require('path');
4
9
  var api = require('drizzle-kit/api');
5
10
  var pgCore = require('drizzle-orm/pg-core');
6
11
  var drizzleOrm = require('drizzle-orm');
7
- var crypto = require('crypto');
8
- var promises = require('fs/promises');
9
- var path = require('path');
10
12
  var jsYaml = require('js-yaml');
13
+ var customRolesManifest = require('@sequenceholdings/custom-roles-manifest');
14
+
15
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
16
+ // src/authoring/columns.ts
17
+ var COLUMN_BRAND = "seq-column";
18
+ var ENUM_BRAND = "seq-enum";
19
+ function isEnumRef(value) {
20
+ return typeof value === "object" && value !== null && value.kind === ENUM_BRAND;
21
+ }
22
+ var COLUMN_DEFAULT_FNS = ["gen_random_uuid()", "now()"];
23
+ function deriveColumnName(propertyName) {
24
+ return propertyName.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toLowerCase();
25
+ }
26
+ var ColumnBuilder = class {
27
+ kind = COLUMN_BRAND;
28
+ state;
29
+ constructor(type, columnName) {
30
+ this.state = {
31
+ type,
32
+ columnName,
33
+ primaryKey: false,
34
+ notNull: false,
35
+ unique: false,
36
+ hasDefault: false,
37
+ defaultValue: void 0,
38
+ defaultFn: void 0,
39
+ description: void 0,
40
+ renamedFrom: void 0,
41
+ cast: void 0,
42
+ deprecated: false
43
+ };
44
+ }
45
+ /** Marks this column as (part of) the primary key. Implies NOT NULL. */
46
+ primaryKey() {
47
+ this.state.primaryKey = true;
48
+ return this;
49
+ }
50
+ notNull() {
51
+ this.state.notNull = true;
52
+ return this;
53
+ }
54
+ unique() {
55
+ this.state.unique = true;
56
+ return this;
57
+ }
58
+ /**
59
+ * Column default: a literal, or one of the allowlisted SQL functions
60
+ * (`'gen_random_uuid()'` / `'now()'`), which serialize as `defaultFn`.
61
+ */
62
+ default(value) {
63
+ if (value === "gen_random_uuid()" || value === "now()") {
64
+ this.state.defaultFn = value;
65
+ this.state.hasDefault = false;
66
+ this.state.defaultValue = void 0;
67
+ return this;
68
+ }
69
+ this.state.hasDefault = true;
70
+ this.state.defaultValue = value;
71
+ this.state.defaultFn = void 0;
72
+ return this;
73
+ }
74
+ description(text3) {
75
+ this.state.description = text3;
76
+ return this;
77
+ }
78
+ /** Migration rename hint: the previous Postgres column name. */
79
+ renamedFrom(previousColumnName) {
80
+ this.state.renamedFrom = previousColumnName;
81
+ return this;
82
+ }
83
+ /** Migration cast hint: the `USING` SQL applied when this column changes type. */
84
+ cast(usingSql) {
85
+ this.state.cast = usingSql;
86
+ return this;
87
+ }
88
+ /** Emits `@deprecated` in the generated SDL; the column stays queryable. */
89
+ deprecated() {
90
+ this.state.deprecated = true;
91
+ return this;
92
+ }
93
+ /** Whether `.primaryKey()` was called — collected into the table-level PK. */
94
+ get isPrimaryKey() {
95
+ return this.state.primaryKey;
96
+ }
97
+ /** The enum name when this is an enum column, else undefined. */
98
+ get enumName() {
99
+ return typeof this.state.type === "object" ? this.state.type.enum : void 0;
100
+ }
101
+ /** Postgres column name: explicit override, else snake_case of the property name. */
102
+ columnNameFor(propertyName) {
103
+ return this.state.columnName ?? deriveColumnName(propertyName);
104
+ }
105
+ /** Serialize to a canonical v2 column. Validation happens in serializeNamespace. */
106
+ toCanonicalColumn(propertyName) {
107
+ const column = {
108
+ name: propertyName,
109
+ columnName: this.columnNameFor(propertyName),
110
+ type: typeof this.state.type === "object" ? { enum: this.state.type.enum } : this.state.type,
111
+ nullable: !(this.state.notNull || this.state.primaryKey),
112
+ unique: this.state.unique,
113
+ deprecated: this.state.deprecated
114
+ };
115
+ if (this.state.hasDefault) column.default = this.state.defaultValue ?? null;
116
+ if (this.state.defaultFn !== void 0) column.defaultFn = this.state.defaultFn;
117
+ if (this.state.description !== void 0) column.description = this.state.description;
118
+ if (this.state.renamedFrom !== void 0) column.renamedFrom = this.state.renamedFrom;
119
+ if (this.state.cast !== void 0) column.cast = this.state.cast;
120
+ return column;
121
+ }
122
+ };
123
+ function isColumnBuilder(value) {
124
+ return typeof value === "object" && value !== null && value.kind === COLUMN_BRAND;
125
+ }
126
+ var scalar = (type) => (columnName) => new ColumnBuilder(type, columnName);
127
+ var t = {
128
+ uuid: scalar("uuid"),
129
+ text: scalar("text"),
130
+ integer: scalar("integer"),
131
+ bigint: scalar("bigint"),
132
+ numeric: scalar("numeric"),
133
+ double: scalar("double"),
134
+ boolean: scalar("boolean"),
135
+ timestamptz: scalar("timestamptz"),
136
+ date: scalar("date"),
137
+ jsonb: scalar("jsonb"),
138
+ enum: (ref, columnName) => new ColumnBuilder({ enum: ref.name }, columnName)
139
+ };
140
+
141
+ // src/constants.ts
142
+ var NAMESPACE_PATTERN = /^[a-z][a-z0-9_]{0,40}$/;
143
+ var IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
144
+ var MAX_IDENTIFIER_LENGTH = 63;
145
+ var ORM_DATA_TOKEN_HEADER = "x-sequence-data-token";
146
+ var ORM_SERVICE_DATA_TOKEN_HEADER = "x-sequence-data-token-service";
147
+ var CAPABILITY_KEY_PATTERN = /^(?:org\/)?[a-z0-9-]{1,64}$/;
148
+ var CLAIM_KEY_PATTERN = /^[a-z][a-z0-9_]*$/;
149
+ var QUALIFIED_TABLE_PATTERN = /^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$/;
150
+ var SYNCED_SOURCE_PATTERN = /^gold\.[a-z][a-z0-9_]*$/;
151
+ var ORM_SCHEMA_PREFIX = "orm_";
152
+ var CONSUMER_ROLE_SUFFIX = "_consumer";
153
+ var ormSchemaName = (namespace) => `${ORM_SCHEMA_PREFIX}${namespace}`;
154
+ var consumerRoleName = (namespace) => `${ORM_SCHEMA_PREFIX}${namespace}${CONSUMER_ROLE_SUFFIX}`;
155
+ var DEFINITION_FILE_EXTENSIONS = [".yml", ".yaml"];
156
+ var NAMESPACE_CONFIG_FILENAMES = /* @__PURE__ */ new Set(["namespace.yaml", "namespace.yml"]);
157
+ var HASH_DOMAIN = "sequence-orm-definitions\0";
158
+ var MAX_DEFINITION_FILE_BYTES = 1024 * 1024;
159
+ var RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set(["actions", "query"]);
160
+ var RESERVED_COLUMN_NAMES = /* @__PURE__ */ new Set(["select", "order", "limit", "offset"]);
161
+
162
+ // src/errors.ts
163
+ var OrmDefinitionError = class extends Error {
164
+ constructor(message, file) {
165
+ super(file ? `${file}: ${message}` : message);
166
+ this.file = file;
167
+ }
168
+ name = "OrmDefinitionError";
169
+ };
170
+ var PredicateParseError = class extends Error {
171
+ constructor(message, position) {
172
+ super(`${message} (at position ${position})`);
173
+ this.position = position;
174
+ }
175
+ name = "PredicateParseError";
176
+ };
177
+
178
+ // src/authoring/registry.ts
179
+ var CONTEXT_STACK_KEY = Symbol.for("sequence.orm.authoring.context-stack.v2");
180
+ function contextStack() {
181
+ const holder = globalThis;
182
+ const existing = holder[CONTEXT_STACK_KEY];
183
+ if (Array.isArray(existing)) {
184
+ return existing;
185
+ }
186
+ const created = [];
187
+ holder[CONTEXT_STACK_KEY] = created;
188
+ return created;
189
+ }
190
+ function beginAuthoringContext() {
191
+ const context = { currentFile: void 0, tables: [], enums: [], configs: [] };
192
+ contextStack().push(context);
193
+ return context;
194
+ }
195
+ function endAuthoringContext(context) {
196
+ const stack = contextStack();
197
+ const top = stack[stack.length - 1];
198
+ if (top !== context) {
199
+ throw new Error("endAuthoringContext: the given context is not the active one \u2014 begin/end calls are mismatched");
200
+ }
201
+ stack.pop();
202
+ }
203
+ function activeAuthoringContext() {
204
+ const stack = contextStack();
205
+ return stack[stack.length - 1];
206
+ }
207
+ function register(bucket, value) {
208
+ const context = activeAuthoringContext();
209
+ if (!context) return;
210
+ context[bucket].push({ value, file: context.currentFile });
211
+ }
212
+ function registerTable(value) {
213
+ register("tables", value);
214
+ }
215
+ function registerEnum(value) {
216
+ register("enums", value);
217
+ }
218
+ function registerNamespaceConfig(value) {
219
+ register("configs", value);
220
+ }
221
+
222
+ // src/authoring/table.ts
223
+ var TABLE_BRAND = "seq-table";
224
+ var LINK_BRAND = "seq-link";
225
+ function toOne(target, options) {
226
+ return {
227
+ kind: LINK_BRAND,
228
+ linkKind: "toOne",
229
+ target,
230
+ on: options.on,
231
+ references: options.references,
232
+ enforce: options.enforce ?? false,
233
+ description: options.description
234
+ };
235
+ }
236
+ function toMany(target, options) {
237
+ return {
238
+ kind: LINK_BRAND,
239
+ linkKind: "toMany",
240
+ target,
241
+ on: options.on,
242
+ references: options.references,
243
+ enforce: false,
244
+ description: options.description
245
+ };
246
+ }
247
+ function toPlatformUser(options) {
248
+ return {
249
+ kind: LINK_BRAND,
250
+ linkKind: "toPlatformUser",
251
+ target: void 0,
252
+ on: options.on,
253
+ references: options.references,
254
+ enforce: false,
255
+ description: options.description
256
+ };
257
+ }
258
+ function isSeqLink(value) {
259
+ return typeof value === "object" && value !== null && value.kind === LINK_BRAND;
260
+ }
261
+ function isSeqTable(value) {
262
+ return typeof value === "object" && value !== null && value.kind === TABLE_BRAND;
263
+ }
264
+ function assertIdentifier({ value, what, file }) {
265
+ if (!IDENTIFIER_PATTERN.test(value) || value.length > MAX_IDENTIFIER_LENGTH) {
266
+ throw new OrmDefinitionError(
267
+ `${what} "${value}" must match ${IDENTIFIER_PATTERN} and be at most ${MAX_IDENTIFIER_LENGTH} characters`,
268
+ file
269
+ );
270
+ }
271
+ }
272
+ function defineTable(name, columns, config = {}) {
273
+ const file = activeAuthoringContext()?.currentFile;
274
+ assertIdentifier({ value: name, what: "table name", file });
275
+ const entries = Object.entries(columns);
276
+ if (entries.length === 0) {
277
+ throw new OrmDefinitionError(`table "${name}" declares no columns`, file);
278
+ }
279
+ const seenColumnNames = /* @__PURE__ */ new Map();
280
+ for (const [propertyName, builder] of entries) {
281
+ if (!isColumnBuilder(builder)) {
282
+ throw new OrmDefinitionError(
283
+ `table "${name}": column "${propertyName}" is not a column builder \u2014 use the t.* factories (t.uuid(), t.text(), \u2026)`,
284
+ file
285
+ );
286
+ }
287
+ const columnName = builder.columnNameFor(propertyName);
288
+ assertIdentifier({ value: columnName, what: `table "${name}": column "${propertyName}" column name`, file });
289
+ const existing = seenColumnNames.get(columnName);
290
+ if (existing !== void 0) {
291
+ throw new OrmDefinitionError(
292
+ `table "${name}": columns "${existing}" and "${propertyName}" both map to Postgres column "${columnName}"`,
293
+ file
294
+ );
295
+ }
296
+ seenColumnNames.set(columnName, propertyName);
297
+ }
298
+ const table = { kind: TABLE_BRAND, tableName: name, columns, config, source: void 0, file };
299
+ registerTable(table);
300
+ return table;
301
+ }
302
+ function defineSyncedTable(name, config) {
303
+ const file = activeAuthoringContext()?.currentFile;
304
+ assertIdentifier({ value: name, what: "table name", file });
305
+ if (!SYNCED_SOURCE_PATTERN.test(config.source)) {
306
+ throw new OrmDefinitionError(
307
+ `synced table "${name}": source "${config.source}" must match ${SYNCED_SOURCE_PATTERN} (gold layer only)`,
308
+ file
309
+ );
310
+ }
311
+ const table = {
312
+ kind: TABLE_BRAND,
313
+ tableName: name,
314
+ columns: {},
315
+ config: config.description !== void 0 ? { description: config.description } : {},
316
+ source: config.source,
317
+ file
318
+ };
319
+ registerTable(table);
320
+ return table;
321
+ }
322
+ function defineEnum(name, values) {
323
+ const file = activeAuthoringContext()?.currentFile;
324
+ assertIdentifier({ value: name, what: "enum name", file });
325
+ if (values.length === 0 || values.length > 100) {
326
+ throw new OrmDefinitionError(`enum "${name}" must declare between 1 and 100 values`, file);
327
+ }
328
+ const seen = /* @__PURE__ */ new Set();
329
+ for (const value of values) {
330
+ if (value.length === 0 || value.length > MAX_IDENTIFIER_LENGTH) {
331
+ throw new OrmDefinitionError(
332
+ `enum "${name}": value ${JSON.stringify(value)} must be 1-${MAX_IDENTIFIER_LENGTH} characters`,
333
+ file
334
+ );
335
+ }
336
+ if (seen.has(value)) {
337
+ throw new OrmDefinitionError(`enum "${name}" declares duplicate value "${value}"`, file);
338
+ }
339
+ seen.add(value);
340
+ }
341
+ const ref = { kind: ENUM_BRAND, name, values: [...values] };
342
+ registerEnum(ref);
343
+ return ref;
344
+ }
345
+ var CANONICAL_FORMAT = 2;
346
+ var IDENTIFIER_RE = /^[a-z][a-z0-9_]*$/;
347
+ var identifier = zod.z.string().min(1).max(63).regex(IDENTIFIER_RE);
348
+ var COLUMN_TYPES = [
349
+ "uuid",
350
+ "text",
351
+ "integer",
352
+ "bigint",
353
+ "numeric",
354
+ "double",
355
+ "boolean",
356
+ "timestamptz",
357
+ "date",
358
+ "jsonb"
359
+ ];
360
+ var columnTypeSchema = zod.z.enum(COLUMN_TYPES);
361
+ var canonicalEnumSchema = zod.z.object({
362
+ name: identifier,
363
+ values: zod.z.array(zod.z.string().min(1).max(63)).min(1).max(100)
364
+ });
365
+ var canonicalColumnSchema = zod.z.object({
366
+ /** Property name in TS (camelCase); columnName is the Postgres name. */
367
+ name: zod.z.string().min(1).max(63),
368
+ columnName: identifier,
369
+ type: zod.z.union([columnTypeSchema, zod.z.object({ enum: identifier })]),
370
+ nullable: zod.z.boolean().default(true),
371
+ unique: zod.z.boolean().default(false),
372
+ /** Literal default, or one of the allowlisted SQL functions. */
373
+ default: zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.null()]).optional(),
374
+ defaultFn: zod.z.enum(["gen_random_uuid()", "now()"]).optional(),
375
+ description: zod.z.string().max(500).optional(),
376
+ /** Migration hints — same semantics as v1. */
377
+ renamedFrom: identifier.optional(),
378
+ cast: zod.z.string().max(200).optional(),
379
+ deprecated: zod.z.boolean().default(false)
380
+ });
381
+ var canonicalLinkSchema = zod.z.object({
382
+ name: zod.z.string().min(1).max(63),
383
+ kind: zod.z.enum(["toOne", "toMany", "toPlatformUser"]),
384
+ /** Target table name (namespace-local). Absent for toPlatformUser. */
385
+ target: identifier.optional(),
386
+ /** FK column on the owning side (toOne/toPlatformUser: on this table; toMany: on the target). */
387
+ on: identifier,
388
+ /** Referenced column on the target (default: target's PK / platform user `sub`). */
389
+ references: identifier.optional(),
390
+ /** enforce: true emits a real FK constraint (same-namespace toOne only). */
391
+ enforce: zod.z.boolean().default(false),
392
+ description: zod.z.string().max(500).optional()
393
+ });
394
+ var canonicalIndexSchema = zod.z.object({
395
+ columns: zod.z.array(identifier).min(1),
396
+ unique: zod.z.boolean().default(false),
397
+ name: identifier.optional()
398
+ });
399
+ var policyVariantSchema = zod.z.object({
400
+ /** Claims-only guard (capability()/role()/claim() comparisons — no columns). */
401
+ when: zod.z.string().min(1).max(1e3),
402
+ /** Exactly one of: allow-all bypass, or a row predicate. */
403
+ allow: zod.z.literal(true).optional(),
404
+ policy: zod.z.string().min(1).max(2e3).optional()
405
+ }).refine((v) => v.allow === true !== (typeof v.policy === "string"), {
406
+ message: "A variant declares exactly one of allow: true or policy"
407
+ });
408
+ var policyExpressionSchema = zod.z.union([
409
+ zod.z.string().min(1).max(2e3),
410
+ zod.z.object({
411
+ default: zod.z.string().min(1).max(2e3),
412
+ variants: zod.z.array(policyVariantSchema).max(10).default([])
413
+ })
414
+ ]);
415
+ var canonicalPoliciesSchema = zod.z.object({
416
+ read: policyExpressionSchema.optional(),
417
+ write: policyExpressionSchema.optional()
418
+ });
419
+ var canonicalActionSchema = zod.z.object({
420
+ name: identifier,
421
+ requires: zod.z.string().max(1e3).optional(),
422
+ params: zod.z.record(zod.z.string(), zod.z.object({
423
+ type: columnTypeSchema,
424
+ nullable: zod.z.boolean().default(false)
425
+ })).default({}),
426
+ executes: zod.z.string().min(1).max(1e4),
427
+ returns: zod.z.enum(["rows", "rowsAffected", "scalar"]).default("rowsAffected"),
428
+ audit: zod.z.object({ action: zod.z.string(), resource: zod.z.string() }).optional()
429
+ });
430
+ var canonicalTableSchema = zod.z.object({
431
+ table: identifier,
432
+ description: zod.z.string().max(2e3).optional(),
433
+ /** Table-level rename hint (new in v2). */
434
+ renamedFrom: identifier.optional(),
435
+ /** Synced/reflected read-only tables (`source: gold.*`) — v1 semantics. */
436
+ source: zod.z.string().regex(/^gold\.[a-z][a-z0-9_]*$/).optional(),
437
+ columns: zod.z.array(canonicalColumnSchema).default([]),
438
+ primaryKey: zod.z.array(identifier).min(1).max(8).optional(),
439
+ links: zod.z.array(canonicalLinkSchema).default([]),
440
+ indexes: zod.z.array(canonicalIndexSchema).default([]),
441
+ policies: canonicalPoliciesSchema.default({}),
442
+ actions: zod.z.array(canonicalActionSchema).default([])
443
+ });
444
+ var canonicalDefinitionSchema = zod.z.object({
445
+ definition_format: zod.z.literal(CANONICAL_FORMAT),
446
+ namespace: identifier.max(41),
447
+ description: zod.z.string().max(2e3).optional(),
448
+ enums: zod.z.array(canonicalEnumSchema).default([]),
449
+ tables: zod.z.array(canonicalTableSchema).min(0).max(500),
450
+ /** Verbatim custom-roles grammar (@sequenceholdings/custom-roles-manifest). */
451
+ capabilities: zod.z.object({
452
+ roles: zod.z.unknown().optional(),
453
+ uses: zod.z.array(zod.z.string()).default([])
454
+ }).default({ uses: [] })
455
+ });
456
+ function normalizeCanonical(definition) {
457
+ const sortByName = (items) => [...items].sort((a, b) => a.name.localeCompare(b.name));
458
+ return {
459
+ ...definition,
460
+ enums: sortByName(definition.enums),
461
+ tables: [...definition.tables].sort((a, b) => a.table.localeCompare(b.table)).map((t2) => ({
462
+ ...t2,
463
+ links: sortByName(t2.links),
464
+ indexes: [...t2.indexes].sort((a, b) => (a.name ?? a.columns.join("_")).localeCompare(b.name ?? b.columns.join("_"))),
465
+ actions: sortByName(t2.actions)
466
+ }))
467
+ };
468
+ }
469
+ function stableJson(value) {
470
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
471
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
472
+ const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([a], [b]) => a < b ? -1 : 1).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableJson(entryValue)}`);
473
+ return `{${entries.join(",")}}`;
474
+ }
475
+ function emptyToNull(value) {
476
+ if (value == null) return null;
477
+ if (Array.isArray(value)) return value.length === 0 ? null : value;
478
+ if (typeof value === "object" && Object.keys(value).length === 0) return null;
479
+ return value;
480
+ }
481
+ function canonicalTable(table) {
482
+ return {
483
+ table: table.table,
484
+ description: table.description ?? null,
485
+ columns: table.columns ?? null,
486
+ source: table.source ?? null,
487
+ links: emptyToNull(table.links),
488
+ indexes: emptyToNull(table.indexes),
489
+ policies: {
490
+ read: table.policies?.read?.source ?? null,
491
+ write: table.policies?.write?.source ?? null
492
+ },
493
+ actions: emptyToNull(
494
+ Object.fromEntries(
495
+ Object.entries(table.actions ?? {}).map(([name, action]) => [
496
+ name,
497
+ {
498
+ description: action.description ?? null,
499
+ requires: action.requires?.source ?? null,
500
+ params: emptyToNull(action.params),
501
+ validates: emptyToNull(action.validates?.map((entry) => entry.source)),
502
+ executes: action.executes,
503
+ returns: emptyToNull(action.returns),
504
+ audit: action.audit ?? null
505
+ }
506
+ ])
507
+ )
508
+ )
509
+ };
510
+ }
511
+ function canonicalCapabilities(capabilities) {
512
+ const { definitions, capabilities: declared } = capabilities.roles;
513
+ const isEmpty = Object.keys(definitions).length === 0 && Object.keys(declared).length === 0 && capabilities.uses.length === 0;
514
+ if (isEmpty) return null;
515
+ return {
516
+ roles: {
517
+ definitions: Object.fromEntries(
518
+ Object.entries(definitions).map(([key, def]) => [
519
+ key,
520
+ {
521
+ ...def.description !== void 0 ? { description: def.description } : {},
522
+ default: def.default,
523
+ inherits: [...def.inherits].sort(),
524
+ grants: [...def.grants].sort()
525
+ }
526
+ ])
527
+ ),
528
+ capabilities: Object.fromEntries(
529
+ Object.entries(declared).map(([key, cap]) => [
530
+ key,
531
+ cap.description !== void 0 ? { description: cap.description } : {}
532
+ ])
533
+ )
534
+ },
535
+ uses: [...capabilities.uses].sort()
536
+ };
537
+ }
538
+ function canonicalizeDefinition(definition) {
539
+ return {
540
+ namespace: definition.namespace,
541
+ description: definition.description,
542
+ capabilities: canonicalCapabilities(definition.capabilities),
543
+ tables: definition.tables.map(canonicalTable)
544
+ };
545
+ }
546
+ function computeDefinitionHash(definition) {
547
+ return crypto.createHash("sha256").update(HASH_DOMAIN).update(stableJson(canonicalizeDefinition(definition))).digest("hex");
548
+ }
549
+
550
+ // src/authoring/namespace.ts
551
+ var NAMESPACE_CONFIG_BRAND = "seq-namespace-config";
552
+ function isSeqNamespaceConfig(value) {
553
+ return typeof value === "object" && value !== null && value.kind === NAMESPACE_CONFIG_BRAND;
554
+ }
555
+ function defineNamespace(input) {
556
+ const file = activeAuthoringContext()?.currentFile;
557
+ if (!NAMESPACE_PATTERN.test(input.namespace)) {
558
+ throw new OrmDefinitionError(`namespace "${input.namespace}" must match ${NAMESPACE_PATTERN}`, file);
559
+ }
560
+ const config = {
561
+ kind: NAMESPACE_CONFIG_BRAND,
562
+ namespace: input.namespace,
563
+ description: input.description,
564
+ capabilities: input.capabilities ?? {},
565
+ file
566
+ };
567
+ registerNamespaceConfig(config);
568
+ return config;
569
+ }
570
+ function serializeNamespace(input) {
571
+ const { config, tables } = input;
572
+ const enums = input.enums ?? [];
573
+ const tablesByName = /* @__PURE__ */ new Map();
574
+ for (const table of tables) {
575
+ const existing = tablesByName.get(table.tableName);
576
+ if (existing) {
577
+ throw new OrmDefinitionError(
578
+ `duplicate table "${table.tableName}" (defined in ${describeFile(existing)} and ${describeFile(table)})`,
579
+ table.file
580
+ );
581
+ }
582
+ tablesByName.set(table.tableName, table);
583
+ }
584
+ const enumsByName = /* @__PURE__ */ new Map();
585
+ for (const ref of enums) {
586
+ if (enumsByName.has(ref.name)) {
587
+ throw new OrmDefinitionError(`duplicate enum "${ref.name}"`, config.file);
588
+ }
589
+ enumsByName.set(ref.name, ref);
590
+ }
591
+ const canonicalTables = tables.map((table) => buildCanonicalTable({ table, tablesByName, enumsByName }));
592
+ const canonicalEnums = [...enumsByName.values()].map((ref) => ({
593
+ name: ref.name,
594
+ values: [...ref.values]
595
+ }));
596
+ const candidate = {
597
+ definition_format: CANONICAL_FORMAT,
598
+ namespace: config.namespace,
599
+ enums: canonicalEnums,
600
+ tables: canonicalTables,
601
+ capabilities: {
602
+ ...config.capabilities.roles !== void 0 ? { roles: config.capabilities.roles } : {},
603
+ uses: [...config.capabilities.uses ?? []]
604
+ }
605
+ };
606
+ if (config.description !== void 0) candidate.description = config.description;
607
+ let parsed;
608
+ try {
609
+ parsed = canonicalDefinitionSchema.parse(candidate);
610
+ } catch (error) {
611
+ if (error instanceof zod.z.ZodError) {
612
+ throw new OrmDefinitionError(`namespace "${config.namespace}": ${formatZodIssues(error)}`, config.file);
613
+ }
614
+ throw error;
615
+ }
616
+ return normalizeCanonical(parsed);
617
+ }
618
+ function computeCanonicalHash(definition) {
619
+ return crypto.createHash("sha256").update(HASH_DOMAIN).update(stableJson(definition)).digest("hex");
620
+ }
621
+ function buildCanonicalTable({ table, tablesByName, enumsByName }) {
622
+ const candidate = {
623
+ table: table.tableName,
624
+ columns: [],
625
+ links: [],
626
+ indexes: [],
627
+ policies: {},
628
+ actions: []
629
+ };
630
+ if (table.config.description !== void 0) candidate.description = table.config.description;
631
+ if (table.config.renamedFrom !== void 0) candidate.renamedFrom = table.config.renamedFrom;
632
+ if (table.source !== void 0) candidate.source = table.source;
633
+ const columnLevelPk = [];
634
+ for (const [propertyName, builder] of Object.entries(table.columns)) {
635
+ const column = builder.toCanonicalColumn(propertyName);
636
+ const enumName = builder.enumName;
637
+ if (enumName !== void 0 && !enumsByName.has(enumName)) {
638
+ throw new OrmDefinitionError(
639
+ `table "${table.tableName}": column "${propertyName}" references enum "${enumName}" which is not passed to serializeNamespace \u2014 declare it with defineEnum and include it`,
640
+ table.file
641
+ );
642
+ }
643
+ if (builder.isPrimaryKey) columnLevelPk.push(column.columnName);
644
+ candidate.columns?.push(column);
645
+ }
646
+ if (table.config.primaryKey !== void 0) {
647
+ if (columnLevelPk.length > 0) {
648
+ throw new OrmDefinitionError(
649
+ `table "${table.tableName}": declare the primary key either with .primaryKey() on columns or with config.primaryKey \u2014 not both`,
650
+ table.file
651
+ );
652
+ }
653
+ candidate.primaryKey = table.config.primaryKey.map(
654
+ (ref) => resolveColumnRef({ table, ref, role: "primaryKey" })
655
+ );
656
+ } else if (columnLevelPk.length > 0) {
657
+ candidate.primaryKey = columnLevelPk;
658
+ }
659
+ for (const index3 of table.config.indexes ?? []) {
660
+ const entry = {
661
+ columns: index3.columns.map((ref) => resolveColumnRef({ table, ref, role: "index" }))
662
+ };
663
+ if (index3.unique !== void 0) entry.unique = index3.unique;
664
+ if (index3.name !== void 0) entry.name = index3.name;
665
+ candidate.indexes?.push(entry);
666
+ }
667
+ for (const [linkName, link] of Object.entries(table.config.links ?? {})) {
668
+ candidate.links?.push(buildCanonicalLink({ table, linkName, link, tablesByName }));
669
+ }
670
+ const policies = {};
671
+ if (table.config.policies?.read !== void 0) policies.read = toCanonicalPolicy(table.config.policies.read);
672
+ if (table.config.policies?.write !== void 0) policies.write = toCanonicalPolicy(table.config.policies.write);
673
+ candidate.policies = policies;
674
+ for (const action of table.config.actions ?? []) {
675
+ candidate.actions?.push({
676
+ name: action.name,
677
+ ...action.requires !== void 0 ? { requires: action.requires } : {},
678
+ params: Object.fromEntries(
679
+ Object.entries(action.params ?? {}).map(([name, param]) => [
680
+ name,
681
+ { type: param.type, nullable: param.nullable ?? false }
682
+ ])
683
+ ),
684
+ executes: action.executes,
685
+ returns: action.returns ?? "rowsAffected",
686
+ ...action.audit !== void 0 ? { audit: action.audit } : {}
687
+ });
688
+ }
689
+ try {
690
+ return canonicalTableSchema.parse(candidate);
691
+ } catch (error) {
692
+ if (error instanceof zod.z.ZodError) {
693
+ throw new OrmDefinitionError(`table "${table.tableName}": ${formatZodIssues(error)}`, table.file);
694
+ }
695
+ throw error;
696
+ }
697
+ }
698
+ function buildCanonicalLink({
699
+ table,
700
+ linkName,
701
+ link,
702
+ tablesByName
703
+ }) {
704
+ const fail = (message) => {
705
+ throw new OrmDefinitionError(`table "${table.tableName}": link "${linkName}" ${message}`, table.file);
706
+ };
707
+ if (link.enforce && link.linkKind !== "toOne") {
708
+ return fail("sets enforce: true, which is only supported on toOne links");
709
+ }
710
+ if (link.linkKind === "toPlatformUser") {
711
+ if (link.target !== void 0) return fail("is toPlatformUser and must not declare a target table");
712
+ return {
713
+ name: linkName,
714
+ kind: "toPlatformUser",
715
+ on: resolveColumnRef({ table, ref: link.on, role: `link "${linkName}" on` }),
716
+ ...link.references !== void 0 ? { references: deriveColumnName(link.references) } : {},
717
+ enforce: false,
718
+ ...link.description !== void 0 ? { description: link.description } : {}
719
+ };
720
+ }
721
+ const target = resolveTableRef({ ref: link.target, fail });
722
+ if (!tablesByName.has(target.tableName)) {
723
+ return fail(`targets table "${target.tableName}" which is not part of this namespace`);
724
+ }
725
+ const owningSide = link.linkKind === "toOne" ? table : target;
726
+ return {
727
+ name: linkName,
728
+ kind: link.linkKind,
729
+ target: target.tableName,
730
+ on: resolveColumnRef({ table: owningSide, ref: link.on, role: `link "${linkName}" on` }),
731
+ ...link.references !== void 0 ? { references: resolveColumnRef({ table: target, ref: link.references, role: `link "${linkName}" references` }) } : {},
732
+ enforce: link.enforce,
733
+ ...link.description !== void 0 ? { description: link.description } : {}
734
+ };
735
+ }
736
+ function resolveTableRef({ ref, fail }) {
737
+ if (ref === void 0) return fail("declares no target table");
738
+ if (typeof ref !== "function") return ref;
739
+ let resolved;
740
+ try {
741
+ resolved = ref();
742
+ } catch (error) {
743
+ return fail(
744
+ `target thunk threw (${error instanceof Error ? error.message : String(error)}) \u2014 lazy refs resolve at serialize time; make sure the target module ran`
745
+ );
746
+ }
747
+ if (!isSeqTable(resolved)) return fail("target thunk did not return a table defined with defineTable");
748
+ return resolved;
749
+ }
750
+ function resolveColumnRef({ table, ref, role }) {
751
+ const direct = table.columns[ref];
752
+ if (direct) return direct.columnNameFor(ref);
753
+ for (const [propertyName, builder] of Object.entries(table.columns)) {
754
+ if (builder.columnNameFor(propertyName) === ref) return ref;
755
+ }
756
+ const known = Object.keys(table.columns).join(", ");
757
+ throw new OrmDefinitionError(
758
+ `table "${table.tableName}": ${role} references unknown column "${ref}" (known columns: ${known || "none"})`,
759
+ table.file
760
+ );
761
+ }
762
+ function toCanonicalPolicy(policy) {
763
+ if (typeof policy === "string") return policy;
764
+ return {
765
+ default: policy.default,
766
+ variants: (policy.variants ?? []).map((variant) => ({
767
+ when: variant.when,
768
+ ...variant.allow === true ? { allow: true } : {},
769
+ ...variant.policy !== void 0 ? { policy: variant.policy } : {}
770
+ }))
771
+ };
772
+ }
773
+ function describeFile(table) {
774
+ return table.file ?? "<unknown file>";
775
+ }
776
+ function formatZodIssues(error) {
777
+ return error.issues.map((issue) => issue.path.length > 0 ? `${issue.path.join(".")}: ${issue.message}` : issue.message).join("; ");
778
+ }
779
+ var NAMESPACE_CONFIG_FILE = "sequence.config.ts";
780
+ var SCHEMA_DIR = "schema";
781
+ async function loadNamespaceFromDir(dir, options = {}) {
782
+ const root = await promises.realpath(dir).catch(() => {
783
+ throw new OrmDefinitionError(`namespace directory not found: ${dir}`);
784
+ });
785
+ const configPath = path.join(root, NAMESPACE_CONFIG_FILE);
786
+ const configStat = await promises.stat(configPath).catch(() => void 0);
787
+ if (!configStat?.isFile()) {
788
+ throw new OrmDefinitionError(`${NAMESPACE_CONFIG_FILE} not found in ${dir}`);
789
+ }
790
+ const schemaFiles = await listSchemaFiles(root);
791
+ const files = [NAMESPACE_CONFIG_FILE, ...schemaFiles];
792
+ purgeModuleCache(root);
793
+ const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)), {
794
+ interopDefault: true,
795
+ fsCache: false,
796
+ ...options.ormModulePath !== void 0 ? { alias: { "@sequenceholdings/orm": options.ormModulePath } } : {}
797
+ });
798
+ const context = beginAuthoringContext();
799
+ try {
800
+ for (const file of files) {
801
+ context.currentFile = file;
802
+ try {
803
+ await jiti$1.import(path.join(root, file));
804
+ } catch (error) {
805
+ if (error instanceof Error && error.name === "OrmDefinitionError") throw error;
806
+ throw new OrmDefinitionError(
807
+ `failed to load: ${error instanceof Error ? error.message : String(error)}`,
808
+ file
809
+ );
810
+ }
811
+ }
812
+ } finally {
813
+ context.currentFile = void 0;
814
+ endAuthoringContext(context);
815
+ }
816
+ const configs = [];
817
+ for (const entry of context.configs) {
818
+ if (isSeqNamespaceConfig(entry.value)) configs.push({ value: entry.value, file: entry.file });
819
+ }
820
+ const configEntry = configs[0];
821
+ if (!configEntry) {
822
+ throw new OrmDefinitionError(
823
+ "no namespace config registered \u2014 sequence.config.ts must call defineNamespace(...) at import time",
824
+ NAMESPACE_CONFIG_FILE
825
+ );
826
+ }
827
+ if (configs.length > 1) {
828
+ const where = configs.map((entry) => entry.file ?? "<unknown file>").join(", ");
829
+ throw new OrmDefinitionError(
830
+ `defineNamespace called ${configs.length} times (${where}) \u2014 declare exactly one namespace config`
831
+ );
832
+ }
833
+ const tables = [];
834
+ for (const entry of context.tables) {
835
+ if (isSeqTable(entry.value)) tables.push(entry.value);
836
+ }
837
+ if (tables.length === 0) {
838
+ throw new OrmDefinitionError(
839
+ `no tables registered \u2014 ${SCHEMA_DIR}/*.ts modules must call defineTable(...) at import time`
840
+ );
841
+ }
842
+ const enums = [];
843
+ for (const entry of context.enums) {
844
+ if (isEnumRef(entry.value)) enums.push(entry.value);
845
+ }
846
+ const canonical = serializeNamespace({ config: configEntry.value, tables, enums });
847
+ return { canonical, hash: computeCanonicalHash(canonical), files };
848
+ }
849
+ async function listSchemaFiles(root) {
850
+ const schemaDir = path.join(root, SCHEMA_DIR);
851
+ const entries = await promises.readdir(schemaDir, { withFileTypes: true }).catch(() => []);
852
+ return entries.filter(
853
+ (entry) => entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts") && !entry.name.startsWith(".")
854
+ ).map((entry) => path.join(SCHEMA_DIR, entry.name)).sort();
855
+ }
856
+ function purgeModuleCache(root) {
857
+ const require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
858
+ const prefix = root.endsWith(path.sep) ? root : `${root}${path.sep}`;
859
+ for (const key of Object.keys(require2.cache)) {
860
+ if (key.startsWith(prefix)) delete require2.cache[key];
861
+ }
862
+ }
11
863
 
12
864
  // src/codegen/types.ts
13
865
  var WIRE_TYPES = {
@@ -86,43 +938,6 @@ function columnWireType(column) {
86
938
  return notNull || base === "unknown" ? base : `${base} | null`;
87
939
  }
88
940
 
89
- // src/constants.ts
90
- var NAMESPACE_PATTERN = /^[a-z][a-z0-9_]{0,40}$/;
91
- var IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
92
- var MAX_IDENTIFIER_LENGTH = 63;
93
- var ORM_DATA_TOKEN_HEADER = "x-sequence-data-token";
94
- var ORM_SERVICE_DATA_TOKEN_HEADER = "x-sequence-data-token-service";
95
- var CAPABILITY_KEY_PATTERN = /^(?:org\/)?[a-z0-9-]{1,64}$/;
96
- var CLAIM_KEY_PATTERN = /^[a-z][a-z0-9_]*$/;
97
- var QUALIFIED_TABLE_PATTERN = /^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$/;
98
- var SYNCED_SOURCE_PATTERN = /^gold\.[a-z][a-z0-9_]*$/;
99
- var ORM_SCHEMA_PREFIX = "orm_";
100
- var CONSUMER_ROLE_SUFFIX = "_consumer";
101
- var ormSchemaName = (namespace) => `${ORM_SCHEMA_PREFIX}${namespace}`;
102
- var consumerRoleName = (namespace) => `${ORM_SCHEMA_PREFIX}${namespace}${CONSUMER_ROLE_SUFFIX}`;
103
- var DEFINITION_FILE_EXTENSIONS = [".yml", ".yaml"];
104
- var NAMESPACE_CONFIG_FILENAMES = /* @__PURE__ */ new Set(["namespace.yaml", "namespace.yml"]);
105
- var HASH_DOMAIN = "sequence-orm-definitions\0";
106
- var MAX_DEFINITION_FILE_BYTES = 1024 * 1024;
107
- var RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set(["actions", "query"]);
108
- var RESERVED_COLUMN_NAMES = /* @__PURE__ */ new Set(["select", "order", "limit", "offset"]);
109
-
110
- // src/errors.ts
111
- var OrmDefinitionError = class extends Error {
112
- constructor(message, file) {
113
- super(file ? `${file}: ${message}` : message);
114
- this.file = file;
115
- }
116
- name = "OrmDefinitionError";
117
- };
118
- var PredicateParseError = class extends Error {
119
- constructor(message, position) {
120
- super(`${message} (at position ${position})`);
121
- this.position = position;
122
- }
123
- name = "PredicateParseError";
124
- };
125
-
126
941
  // src/predicate/ast.ts
127
942
  var COMPARE_OPS = ["=", "!=", "<", "<=", ">", ">="];
128
943
  function walkPredicate(predicate, visit) {
@@ -161,7 +976,7 @@ var tableReferenceSchema = zod.z.string().refine(
161
976
  var isQualifiedReference = (reference) => reference.includes(".");
162
977
 
163
978
  // src/schema/columns.ts
164
- var COLUMN_TYPES = [
979
+ var COLUMN_TYPES2 = [
165
980
  "uuid",
166
981
  "text",
167
982
  "integer",
@@ -173,7 +988,7 @@ var COLUMN_TYPES = [
173
988
  "date",
174
989
  "jsonb"
175
990
  ];
176
- var columnTypeSchema = zod.z.enum(COLUMN_TYPES);
991
+ var columnTypeSchema2 = zod.z.enum(COLUMN_TYPES2);
177
992
  var FUNCTION_DEFAULTS = {
178
993
  "gen_random_uuid()": ["uuid"],
179
994
  "now()": ["timestamptz", "date"]
@@ -202,7 +1017,7 @@ function defaultIssue(value, type) {
202
1017
  return null;
203
1018
  }
204
1019
  var columnSchema = zod.z.strictObject({
205
- type: columnTypeSchema,
1020
+ type: columnTypeSchema2,
206
1021
  primary_key: zod.z.boolean().optional(),
207
1022
  nullable: zod.z.boolean().optional(),
208
1023
  unique: zod.z.boolean().optional(),
@@ -469,7 +1284,7 @@ var NAMED_PARAM_PATTERN = /(?<!:):([a-z][a-z0-9_]*)/g;
469
1284
  var QUOTED_STRING_PATTERN = /'(?:[^']|'')*'/g;
470
1285
  var SQL_COMMENT_PATTERN = /--|\/\*/;
471
1286
  var actionParamSchema = zod.z.strictObject({
472
- type: columnTypeSchema,
1287
+ type: columnTypeSchema2,
473
1288
  optional: zod.z.boolean().optional(),
474
1289
  description: zod.z.string().optional()
475
1290
  });
@@ -502,7 +1317,7 @@ var actionSchema = zod.z.strictObject({
502
1317
  // function returns those rows (typed in the client); absent → the action
503
1318
  // reports rows_affected only. The column names/types must match the
504
1319
  // RETURNING list, which Postgres enforces at CREATE FUNCTION.
505
- returns: zod.z.record(identifierSchema, columnTypeSchema).optional(),
1320
+ returns: zod.z.record(identifierSchema, columnTypeSchema2).optional(),
506
1321
  audit: auditSchema.optional()
507
1322
  }).superRefine((action, ctx) => {
508
1323
  const params = Object.keys(action.params ?? {});
@@ -519,18 +1334,18 @@ var actionSchema = zod.z.strictObject({
519
1334
  if (action.returns && Object.keys(action.returns).length === 0) {
520
1335
  ctx.addIssue({ code: "custom", message: "returns must declare at least one column", path: ["returns"] });
521
1336
  }
522
- for (const [index2, entry] of (action.validates ?? []).entries()) {
1337
+ for (const [index3, entry] of (action.validates ?? []).entries()) {
523
1338
  if (!params.includes(entry.param)) {
524
1339
  ctx.addIssue({
525
1340
  code: "custom",
526
1341
  message: `validates references undeclared param '${entry.param}'`,
527
- path: ["validates", index2]
1342
+ path: ["validates", index3]
528
1343
  });
529
1344
  }
530
1345
  }
531
1346
  });
532
- function extractNamedParams(sql2) {
533
- const withoutStrings = sql2.replace(QUOTED_STRING_PATTERN, "''");
1347
+ function extractNamedParams(sql3) {
1348
+ const withoutStrings = sql3.replace(QUOTED_STRING_PATTERN, "''");
534
1349
  const names = [...withoutStrings.matchAll(NAMED_PARAM_PATTERN)].map((match) => match[1]);
535
1350
  return [...new Set(names)];
536
1351
  }
@@ -563,9 +1378,9 @@ function actionWriteTargets(action) {
563
1378
  function executesIssues(executes, declaredParams, hasReturns) {
564
1379
  const issues = [];
565
1380
  const statements = actionStatementSources(executes);
566
- statements.forEach((statement, index2) => {
1381
+ statements.forEach((statement, index3) => {
567
1382
  const withoutStrings = statement.replace(QUOTED_STRING_PATTERN, "''");
568
- const at = statements.length > 1 ? ` (statement ${index2 + 1})` : "";
1383
+ const at = statements.length > 1 ? ` (statement ${index3 + 1})` : "";
569
1384
  if (!EXECUTES_VERB_PATTERN.test(statement)) issues.push(`executes must be INSERT, UPDATE, or DELETE${at}`);
570
1385
  if (withoutStrings.replace(/;\s*$/, "").includes(";")) issues.push(`each executes entry must be a single statement${at}`);
571
1386
  if (SQL_COMMENT_PATTERN.test(withoutStrings)) issues.push(`executes must not contain SQL comments${at}`);
@@ -575,7 +1390,7 @@ function executesIssues(executes, declaredParams, hasReturns) {
575
1390
  if (BARE_CLAIM_CALL_PATTERN.test(withoutStrings.replace(MASKED_CLAIM_CALL_PATTERN, ""))) {
576
1391
  issues.push(`executes has a malformed claim()/capability() call \u2014 use e.g. claim('sub')${at}`);
577
1392
  }
578
- if (RETURNING_PATTERN.test(withoutStrings) && !(hasReturns && index2 === statements.length - 1)) {
1393
+ if (RETURNING_PATTERN.test(withoutStrings) && !(hasReturns && index3 === statements.length - 1)) {
579
1394
  issues.push(
580
1395
  hasReturns ? `only the last executes statement may use RETURNING${at}` : `executes must not use RETURNING unless the action declares returns${at}`
581
1396
  );
@@ -685,8 +1500,8 @@ var actionParamArg = (name) => `p_${name}`;
685
1500
  function compileActionStatements(action, renderParam = actionParamArg) {
686
1501
  return actionStatementSources(action.executes).map((statement) => compileStatement(statement, renderParam));
687
1502
  }
688
- function compileStatement(sql2, renderParam) {
689
- const compiled = sql2.replace(TOKEN_PATTERN, (token, claimKey, capabilityKey, paramName) => {
1503
+ function compileStatement(sql3, renderParam) {
1504
+ const compiled = sql3.replace(TOKEN_PATTERN, (token, claimKey, capabilityKey, paramName) => {
690
1505
  if (claimKey !== void 0) {
691
1506
  if (!CLAIM_KEY_PATTERN.test(claimKey)) throw new OrmDefinitionError(`invalid claim key in executes: ${token}`);
692
1507
  return claimExpression(claimKey);
@@ -739,9 +1554,9 @@ function actionPrepareChecks(definition) {
739
1554
  const order = actionParamOrder(action);
740
1555
  const signature = order.length > 0 ? ` (${order.map((param) => sqlTypeName(action.params[param].type)).join(", ")})` : "";
741
1556
  const compiled = compileActionStatements(action, (param) => `$${order.indexOf(param) + 1}`);
742
- compiled.forEach((sql2, index2) => {
743
- const checked = action.returns && index2 === compiled.length - 1 ? returnProjection(action.returns, sql2) : sql2;
744
- statements.push(`PREPARE ${quoteIdentifier(`orm_check_${name}_${index2}`)}${signature} AS ${checked}`);
1557
+ compiled.forEach((sql3, index3) => {
1558
+ const checked = action.returns && index3 === compiled.length - 1 ? returnProjection(action.returns, sql3) : sql3;
1559
+ statements.push(`PREPARE ${quoteIdentifier(`orm_check_${name}_${index3}`)}${signature} AS ${checked}`);
745
1560
  });
746
1561
  }
747
1562
  return statements;
@@ -856,7 +1671,7 @@ var indexSchema = zod.z.union([
856
1671
  unique: zod.z.boolean().optional(),
857
1672
  name: identifierSchema.optional()
858
1673
  })
859
- ]).transform((index2) => Array.isArray(index2) ? { columns: index2 } : index2);
1674
+ ]).transform((index3) => Array.isArray(index3) ? { columns: index3 } : index3);
860
1675
  var policiesSchema = zod.z.strictObject({
861
1676
  read: parsedPredicateSchema.optional(),
862
1677
  write: parsedPredicateSchema.optional()
@@ -960,15 +1775,15 @@ function validateColumnTable(table, ctx) {
960
1775
  });
961
1776
  }
962
1777
  }
963
- for (const [position, index2] of (table.indexes ?? []).entries()) {
964
- if (new Set(index2.columns).size !== index2.columns.length) {
1778
+ for (const [position, index3] of (table.indexes ?? []).entries()) {
1779
+ if (new Set(index3.columns).size !== index3.columns.length) {
965
1780
  ctx.addIssue({
966
1781
  code: "custom",
967
1782
  message: "index names a column more than once",
968
1783
  path: ["indexes", position]
969
1784
  });
970
1785
  }
971
- for (const column of index2.columns) {
1786
+ for (const column of index3.columns) {
972
1787
  if (!names.includes(column)) {
973
1788
  ctx.addIssue({
974
1789
  code: "custom",
@@ -1010,8 +1825,8 @@ function validateDerivedNameLengths(table, ctx) {
1010
1825
  path: ["table"]
1011
1826
  });
1012
1827
  }
1013
- for (const [position, index2] of (table.indexes ?? []).entries()) {
1014
- const name = indexName(table.table, index2);
1828
+ for (const [position, index3] of (table.indexes ?? []).entries()) {
1829
+ const name = indexName(table.table, index3);
1015
1830
  if (name.length > MAX_IDENTIFIER_LENGTH) {
1016
1831
  ctx.addIssue({
1017
1832
  code: "custom",
@@ -1251,9 +2066,9 @@ function sortByEnforcedLinks(tables) {
1251
2066
  var enforcedTargets = (table) => Object.values(table.links ?? {}).filter((link) => link.enforce && !isQualifiedReference(link.to) && link.to !== table.table).map((link) => link.to);
1252
2067
 
1253
2068
  // src/engine/snapshot.ts
1254
- function generateSnapshot(definition, previousId2) {
2069
+ function generateSnapshot(definition, previousId3) {
1255
2070
  const { imports, schemaName } = buildDrizzleEntities(definition);
1256
- return api.generateDrizzleJson(imports, previousId2, [schemaName]);
2071
+ return api.generateDrizzleJson(imports, previousId3, [schemaName]);
1257
2072
  }
1258
2073
  var emptySnapshot = (namespace) => api.generateDrizzleJson({}, void 0, [ormSchemaName(namespace)]);
1259
2074
  var CURRENT_SNAPSHOT_VERSION = api.generateDrizzleJson({}).version;
@@ -1410,259 +2225,591 @@ async function guardedRun(run) {
1410
2225
  var STATEMENT_KINDS = ["hint", "ddl", "security", "function"];
1411
2226
  async function planMigration({
1412
2227
  definition,
1413
- previousSnapshot
1414
- }) {
1415
- const schema = ormSchemaName(definition.namespace);
1416
- const previous = previousSnapshot ? normalizeSnapshot(previousSnapshot) : emptySnapshot(definition.namespace);
1417
- const hints = applyMigrationHints(previous, definition);
1418
- const snapshot = generateSnapshot(definition, previousId(previous));
1419
- const ddl = await diffStatements(hints.adjusted, snapshot);
1420
- const policyDrops = policyDropStatements(schema, snapshotTableNames(previous, schema));
1421
- const statements = [
1422
- ...policyDrops.map((sql2) => ({ kind: "security", sql: sql2 })),
1423
- ...hints.statements.map((sql2) => ({ kind: "hint", sql: sql2 })),
1424
- ...ddl.map((sql2) => ({ kind: "ddl", sql: sql2.replace(/;\s*$/, "") })),
1425
- ...securityStatements(definition).map((sql2) => ({ kind: "security", sql: sql2 })),
1426
- // PREPARE each action's executes first (plpgsql bodies don't check columns
1427
- // at CREATE), then create the functions. Both reference the tables the DDL
1428
- // above creates, so they close the plan.
1429
- ...actionPrepareChecks(definition).map((sql2) => ({ kind: "function", sql: sql2 })),
1430
- ...actionFunctionStatements(definition).map((sql2) => ({ kind: "function", sql: sql2 }))
1431
- ];
1432
- return { namespace: definition.namespace, schema, statements, snapshot };
1433
- }
1434
- var compileNamespace = (definition) => planMigration({ definition });
1435
- var previousId = (snapshot) => snapshot.id;
1436
- function stableJson(value) {
1437
- if (value === null || typeof value !== "object") return JSON.stringify(value);
1438
- if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
1439
- const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([a], [b]) => a < b ? -1 : 1).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableJson(entryValue)}`);
1440
- return `{${entries.join(",")}}`;
1441
- }
1442
- function emptyToNull(value) {
1443
- if (value == null) return null;
1444
- if (Array.isArray(value)) return value.length === 0 ? null : value;
1445
- if (typeof value === "object" && Object.keys(value).length === 0) return null;
1446
- return value;
1447
- }
1448
- function canonicalTable(table) {
1449
- return {
1450
- table: table.table,
1451
- description: table.description ?? null,
1452
- columns: table.columns ?? null,
1453
- source: table.source ?? null,
1454
- links: emptyToNull(table.links),
1455
- indexes: emptyToNull(table.indexes),
1456
- policies: {
1457
- read: table.policies?.read?.source ?? null,
1458
- write: table.policies?.write?.source ?? null
1459
- },
1460
- actions: emptyToNull(
1461
- Object.fromEntries(
1462
- Object.entries(table.actions ?? {}).map(([name, action]) => [
1463
- name,
1464
- {
1465
- description: action.description ?? null,
1466
- requires: action.requires?.source ?? null,
1467
- params: emptyToNull(action.params),
1468
- validates: emptyToNull(action.validates?.map((entry) => entry.source)),
1469
- executes: action.executes,
1470
- returns: emptyToNull(action.returns),
1471
- audit: action.audit ?? null
1472
- }
1473
- ])
1474
- )
1475
- )
1476
- };
1477
- }
1478
- function canonicalCapabilities(capabilities) {
1479
- const { definitions, capabilities: declared } = capabilities.roles;
1480
- const isEmpty = Object.keys(definitions).length === 0 && Object.keys(declared).length === 0 && capabilities.uses.length === 0;
1481
- if (isEmpty) return null;
1482
- return {
1483
- roles: {
1484
- definitions: Object.fromEntries(
1485
- Object.entries(definitions).map(([key, def]) => [
1486
- key,
1487
- {
1488
- ...def.description !== void 0 ? { description: def.description } : {},
1489
- default: def.default,
1490
- inherits: [...def.inherits].sort(),
1491
- grants: [...def.grants].sort()
1492
- }
1493
- ])
1494
- ),
1495
- capabilities: Object.fromEntries(
1496
- Object.entries(declared).map(([key, cap]) => [
1497
- key,
1498
- cap.description !== void 0 ? { description: cap.description } : {}
1499
- ])
1500
- )
1501
- },
1502
- uses: [...capabilities.uses].sort()
1503
- };
2228
+ previousSnapshot
2229
+ }) {
2230
+ const schema = ormSchemaName(definition.namespace);
2231
+ const previous = previousSnapshot ? normalizeSnapshot(previousSnapshot) : emptySnapshot(definition.namespace);
2232
+ const hints = applyMigrationHints(previous, definition);
2233
+ const snapshot = generateSnapshot(definition, previousId(previous));
2234
+ const ddl = await diffStatements(hints.adjusted, snapshot);
2235
+ const policyDrops = policyDropStatements(schema, snapshotTableNames(previous, schema));
2236
+ const statements = [
2237
+ ...policyDrops.map((sql3) => ({ kind: "security", sql: sql3 })),
2238
+ ...hints.statements.map((sql3) => ({ kind: "hint", sql: sql3 })),
2239
+ ...ddl.map((sql3) => ({ kind: "ddl", sql: sql3.replace(/;\s*$/, "") })),
2240
+ ...securityStatements(definition).map((sql3) => ({ kind: "security", sql: sql3 })),
2241
+ // PREPARE each action's executes first (plpgsql bodies don't check columns
2242
+ // at CREATE), then create the functions. Both reference the tables the DDL
2243
+ // above creates, so they close the plan.
2244
+ ...actionPrepareChecks(definition).map((sql3) => ({ kind: "function", sql: sql3 })),
2245
+ ...actionFunctionStatements(definition).map((sql3) => ({ kind: "function", sql: sql3 }))
2246
+ ];
2247
+ return { namespace: definition.namespace, schema, statements, snapshot };
1504
2248
  }
1505
- function canonicalizeDefinition(definition) {
1506
- return {
1507
- namespace: definition.namespace,
1508
- description: definition.description,
1509
- capabilities: canonicalCapabilities(definition.capabilities),
1510
- tables: definition.tables.map(canonicalTable)
1511
- };
2249
+ var compileNamespace = (definition) => planMigration({ definition });
2250
+ var previousId = (snapshot) => snapshot.id;
2251
+ var FACTORIES2 = {
2252
+ uuid: (name) => pgCore.uuid(name),
2253
+ text: (name) => pgCore.text(name),
2254
+ integer: (name) => pgCore.integer(name),
2255
+ // Mode 'bigint' keeps int8 lossless — mode 'number' silently rounds past
2256
+ // 2^53. The read executor serializes BigInt to string for JSON.
2257
+ bigint: (name) => pgCore.bigint(name, { mode: "bigint" }),
2258
+ numeric: (name) => pgCore.numeric(name),
2259
+ double: (name) => pgCore.doublePrecision(name),
2260
+ boolean: (name) => pgCore.boolean(name),
2261
+ timestamptz: (name) => pgCore.timestamp(name, { withTimezone: true }),
2262
+ date: (name) => pgCore.date(name),
2263
+ jsonb: (name) => pgCore.jsonb(name)
2264
+ };
2265
+ var SCHEMA_IMPORT_KEY2 = "$schema";
2266
+ var enumImportKey = (name) => `$enum_${name}`;
2267
+ var columnTablesV2 = (definition) => definition.tables.filter((table) => !table.source);
2268
+ function buildDrizzleEntitiesV2(definition) {
2269
+ const schemaName = ormSchemaName(definition.namespace);
2270
+ const schema = pgCore.pgSchema(schemaName);
2271
+ const imports = { [SCHEMA_IMPORT_KEY2]: schema };
2272
+ const tables = {};
2273
+ const built = /* @__PURE__ */ new Map();
2274
+ const enums = /* @__PURE__ */ new Map();
2275
+ for (const enumDefinition of definition.enums) {
2276
+ const values = enumDefinition.values;
2277
+ const builtEnum = schema.enum(enumDefinition.name, values);
2278
+ enums.set(enumDefinition.name, builtEnum);
2279
+ imports[enumImportKey(enumDefinition.name)] = builtEnum;
2280
+ }
2281
+ const byName = new Map(definition.tables.map((table) => [table.table, table]));
2282
+ for (const table of sortByEnforcedLinks2(columnTablesV2(definition))) {
2283
+ const drizzleTable = buildTable2(schema, table, built, enums, byName);
2284
+ built.set(table.table, drizzleTable);
2285
+ imports[table.table] = drizzleTable;
2286
+ tables[table.table] = drizzleTable;
2287
+ }
2288
+ return { imports, tables, schemaName };
1512
2289
  }
1513
- function computeDefinitionHash(definition) {
1514
- return crypto.createHash("sha256").update(HASH_DOMAIN).update(stableJson(canonicalizeDefinition(definition))).digest("hex");
2290
+ function generateSnapshotV2(definition, previousId3) {
2291
+ const { imports, schemaName } = buildDrizzleEntitiesV2(definition);
2292
+ return api.generateDrizzleJson(imports, previousId3, [schemaName]);
1515
2293
  }
1516
- var CUSTOM_ROLE_KEY_RE = /^[a-z0-9-]+$/;
1517
- var customRoleKeySchema = zod.z.string().min(1).max(64).regex(
1518
- CUSTOM_ROLE_KEY_RE,
1519
- "Role and capability keys must match [a-z0-9-]+"
1520
- );
1521
- var MAX_CUSTOM_ROLE_DEFINITIONS = 50;
1522
- var MAX_CUSTOM_ROLE_CAPABILITIES = 100;
1523
- var customRoleCapabilityDeclarationSchema = zod.z.object({
1524
- description: zod.z.string().max(500).optional()
1525
- });
1526
- var customRoleDefinitionSchema = zod.z.object({
1527
- description: zod.z.string().max(500).optional(),
1528
- /**
1529
- * Grants this role to the host's entire runtime audience. Resolved at the
1530
- * app layer at claim time — every caller who passes the host floor
1531
- * (`end_user`) holds the default roles; no tuple is written for it.
1532
- */
1533
- default: zod.z.boolean().default(false),
1534
- /** Role keys whose grants this role also receives (privilege waterfall). */
1535
- inherits: zod.z.array(customRoleKeySchema).default([]),
1536
- /** Capability keys this role grants directly. */
1537
- grants: zod.z.array(customRoleKeySchema).default([])
1538
- });
1539
- var customRolesBlockSchema = zod.z.object({
1540
- /** Roles grantable to principals, keyed by role key. */
1541
- definitions: zod.z.record(customRoleKeySchema, customRoleDefinitionSchema).default({}),
1542
- /** Leaf capability keys the host's code checks, keyed by capability key. */
1543
- capabilities: zod.z.record(customRoleKeySchema, customRoleCapabilityDeclarationSchema).default({})
1544
- }).superRefine((block, ctx) => {
1545
- const roleKeys = Object.keys(block.definitions);
1546
- const capabilityKeys = new Set(Object.keys(block.capabilities));
1547
- if (roleKeys.length > MAX_CUSTOM_ROLE_DEFINITIONS) {
1548
- ctx.addIssue({
1549
- code: "custom",
1550
- message: `At most ${MAX_CUSTOM_ROLE_DEFINITIONS} role definitions are allowed`,
1551
- path: ["definitions"]
1552
- });
2294
+ function buildTable2(schema, table, built, enums, byName) {
2295
+ const primaryKeyColumns = table.primaryKey ?? [];
2296
+ if (primaryKeyColumns.length === 0) {
2297
+ throw new OrmDefinitionError(`table '${table.table}' declares no primaryKey`);
1553
2298
  }
1554
- if (capabilityKeys.size > MAX_CUSTOM_ROLE_CAPABILITIES) {
1555
- ctx.addIssue({
1556
- code: "custom",
1557
- message: `At most ${MAX_CUSTOM_ROLE_CAPABILITIES} capabilities are allowed`,
1558
- path: ["capabilities"]
1559
- });
2299
+ const columnNames = new Set(table.columns.map((column) => column.columnName));
2300
+ for (const name of primaryKeyColumns) {
2301
+ if (!columnNames.has(name)) {
2302
+ throw new OrmDefinitionError(`primaryKey of '${table.table}' references unknown column '${name}'`);
2303
+ }
1560
2304
  }
1561
- for (const key of roleKeys) {
1562
- if (capabilityKeys.has(key)) {
1563
- ctx.addIssue({
1564
- code: "custom",
1565
- message: `Key "${key}" is declared as both a role and a capability`,
1566
- path: ["definitions", key]
1567
- });
2305
+ const singlePrimaryKey = primaryKeyColumns.length === 1 ? primaryKeyColumns[0] : void 0;
2306
+ const compositeMembers = new Set(singlePrimaryKey === void 0 ? primaryKeyColumns : []);
2307
+ const columns = Object.fromEntries(
2308
+ table.columns.map((column) => [
2309
+ column.columnName,
2310
+ buildColumnV2({ table: table.table, column, singlePrimaryKey, compositeMembers, enums })
2311
+ ])
2312
+ );
2313
+ const drizzleTable = schema.table(table.table, columns, (self) => [
2314
+ ...buildCompositePrimaryKey(table, primaryKeyColumns, self),
2315
+ ...buildIndexes2(table, self),
2316
+ ...buildForeignKeys2(table, self, built, byName)
2317
+ ]);
2318
+ return drizzleTable.enableRLS();
2319
+ }
2320
+ function resolveColumnFactory(table, column, enums) {
2321
+ if (typeof column.type === "string") return FACTORIES2[column.type];
2322
+ const enumFactory = enums.get(column.type.enum);
2323
+ if (!enumFactory) {
2324
+ throw new OrmDefinitionError(`column '${table}.${column.columnName}' references undeclared enum '${column.type.enum}'`);
2325
+ }
2326
+ return enumFactory;
2327
+ }
2328
+ function buildColumnV2({
2329
+ table,
2330
+ column,
2331
+ singlePrimaryKey,
2332
+ compositeMembers,
2333
+ enums
2334
+ }) {
2335
+ const factory = resolveColumnFactory(table, column, enums);
2336
+ let builder = factory(column.columnName);
2337
+ const isSinglePrimaryKey = column.columnName === singlePrimaryKey;
2338
+ if (isSinglePrimaryKey) builder = builder.primaryKey();
2339
+ if ((column.nullable === false || compositeMembers.has(column.columnName)) && !isSinglePrimaryKey) {
2340
+ builder = builder.notNull();
2341
+ }
2342
+ if (column.unique && !isSinglePrimaryKey) builder = builder.unique();
2343
+ if (column.defaultFn !== void 0 && column.default !== void 0) {
2344
+ throw new OrmDefinitionError(`column '${table}.${column.columnName}' declares both default and defaultFn`);
2345
+ }
2346
+ if (column.defaultFn !== void 0) {
2347
+ if (typeof column.type !== "string" || !isFunctionDefault(column.defaultFn, column.type)) {
2348
+ throw new OrmDefinitionError(
2349
+ `column '${table}.${column.columnName}' declares defaultFn '${column.defaultFn}' which is invalid for its type`
2350
+ );
1568
2351
  }
2352
+ builder = builder.default(drizzleOrm.sql.raw(column.defaultFn));
2353
+ } else if (column.default !== void 0 && column.default !== null) {
2354
+ builder = builder.default(column.default);
1569
2355
  }
1570
- const roleKeySet = new Set(roleKeys);
1571
- for (const [roleKey, definition] of Object.entries(block.definitions)) {
1572
- const seenInherits = /* @__PURE__ */ new Set();
1573
- for (const inherited of definition.inherits) {
1574
- if (seenInherits.has(inherited)) {
1575
- ctx.addIssue({
1576
- code: "custom",
1577
- message: `Role "${roleKey}" lists "${inherited}" in inherits more than once`,
1578
- path: ["definitions", roleKey, "inherits"]
1579
- });
1580
- }
1581
- seenInherits.add(inherited);
1582
- if (!roleKeySet.has(inherited)) {
1583
- ctx.addIssue({
1584
- code: "custom",
1585
- message: `Role "${roleKey}" inherits unknown role "${inherited}"`,
1586
- path: ["definitions", roleKey, "inherits"]
1587
- });
2356
+ return builder;
2357
+ }
2358
+ function buildCompositePrimaryKey(table, primaryKeyColumns, self) {
2359
+ if (primaryKeyColumns.length < 2) return [];
2360
+ return [
2361
+ pgCore.primaryKey({
2362
+ name: `${table.table}_pkey`,
2363
+ columns: primaryKeyColumns.map((column) => self[column])
2364
+ })
2365
+ ];
2366
+ }
2367
+ function buildIndexes2(table, self) {
2368
+ return table.indexes.map((definition) => {
2369
+ for (const column of definition.columns) {
2370
+ if (!(column in self)) {
2371
+ throw new OrmDefinitionError(`index on '${table.table}' references unknown column '${column}'`);
1588
2372
  }
1589
2373
  }
1590
- const seenGrants = /* @__PURE__ */ new Set();
1591
- for (const granted of definition.grants) {
1592
- if (seenGrants.has(granted)) {
1593
- ctx.addIssue({
1594
- code: "custom",
1595
- message: `Role "${roleKey}" lists "${granted}" in grants more than once`,
1596
- path: ["definitions", roleKey, "grants"]
1597
- });
1598
- }
1599
- seenGrants.add(granted);
1600
- if (!capabilityKeys.has(granted)) {
1601
- ctx.addIssue({
1602
- code: "custom",
1603
- message: `Role "${roleKey}" grants unknown capability "${granted}"`,
1604
- path: ["definitions", roleKey, "grants"]
1605
- });
1606
- }
2374
+ const name = indexName(table.table, definition);
2375
+ const factory = definition.unique ? pgCore.uniqueIndex(name) : pgCore.index(name);
2376
+ const columns = definition.columns.map((column) => self[column]);
2377
+ return factory.on(...columns);
2378
+ });
2379
+ }
2380
+ function buildForeignKeys2(table, self, built, byName) {
2381
+ return table.links.filter((link) => link.enforce).map((link) => {
2382
+ if (link.kind !== "toOne" || !link.target) {
2383
+ throw new OrmDefinitionError(
2384
+ `enforced link '${link.name}' on '${table.table}' must be a toOne link with a namespace-local target`
2385
+ );
1607
2386
  }
1608
- }
1609
- const state = /* @__PURE__ */ new Map();
1610
- const visit = (key, path) => {
1611
- if (state.get(key) === "done") return null;
1612
- if (state.get(key) === "visiting") return [...path, key];
1613
- state.set(key, "visiting");
1614
- const definition = block.definitions[key];
1615
- for (const inherited of definition?.inherits ?? []) {
1616
- if (!roleKeySet.has(inherited)) continue;
1617
- const cycle = visit(inherited, [...path, key]);
1618
- if (cycle) return cycle;
2387
+ const targetTable = byName.get(link.target);
2388
+ const target = link.target === table.table ? self : built.get(link.target);
2389
+ if (!targetTable || !target) {
2390
+ throw new OrmDefinitionError(`enforced link '${link.name}' on '${table.table}' has no built target '${link.target}'`);
1619
2391
  }
1620
- state.set(key, "done");
1621
- return null;
1622
- };
1623
- for (const roleKey of roleKeys) {
1624
- const cycle = visit(roleKey, []);
1625
- if (cycle) {
1626
- ctx.addIssue({
1627
- code: "custom",
1628
- message: `Role inheritance cycle: ${cycle.join(" -> ")}`,
1629
- path: ["definitions"]
1630
- });
1631
- break;
2392
+ const referencedColumn = link.references ?? singlePrimaryKeyOf(targetTable);
2393
+ if (!referencedColumn) {
2394
+ throw new OrmDefinitionError(
2395
+ `enforced link '${link.name}' on '${table.table}' targets '${link.target}' whose primary key is composite \u2014 declare 'references'`
2396
+ );
2397
+ }
2398
+ const targetColumn = target[referencedColumn];
2399
+ const sourceColumn = self[link.on];
2400
+ if (!targetColumn || !sourceColumn) {
2401
+ throw new OrmDefinitionError(
2402
+ `enforced link '${link.name}' on '${table.table}' references unknown column '${targetColumn ? link.on : referencedColumn}'`
2403
+ );
2404
+ }
2405
+ return pgCore.foreignKey({
2406
+ name: foreignKeyName(table.table, link.name),
2407
+ columns: [sourceColumn],
2408
+ foreignColumns: [targetColumn]
2409
+ });
2410
+ });
2411
+ }
2412
+ var singlePrimaryKeyOf = (table) => table.primaryKey?.length === 1 ? table.primaryKey[0] : void 0;
2413
+ function sortByEnforcedLinks2(tables) {
2414
+ const remaining = new Map(tables.map((table) => [table.table, table]));
2415
+ const sorted = [];
2416
+ const placed = /* @__PURE__ */ new Set();
2417
+ while (remaining.size > 0) {
2418
+ const ready = [...remaining.values()].filter(
2419
+ (table) => enforcedTargets2(table).every((target) => placed.has(target) || !remaining.has(target))
2420
+ );
2421
+ if (ready.length === 0) {
2422
+ throw new OrmDefinitionError(`enforced links form a cycle among: ${[...remaining.keys()].join(", ")}`);
2423
+ }
2424
+ for (const table of ready) {
2425
+ sorted.push(table);
2426
+ placed.add(table.table);
2427
+ remaining.delete(table.table);
1632
2428
  }
1633
2429
  }
1634
- });
1635
- function customRolesDeclared(block) {
1636
- if (!block) return false;
1637
- return Object.keys(block.definitions).length > 0 || Object.keys(block.capabilities).length > 0;
1638
- }
1639
- var CUSTOM_CAPABILITY_PIN_RE = /^(?:org\/)?[a-z0-9-]+$/;
1640
- var MAX_CAPABILITY_PINS = 100;
1641
- var capabilityPinsSchema = zod.z.array(
1642
- zod.z.string().min(1).max(68).regex(
1643
- CUSTOM_CAPABILITY_PIN_RE,
1644
- 'Pins must be "org/<key>" or a bare "<key>" matching [a-z0-9-]+'
2430
+ return sorted;
2431
+ }
2432
+ var enforcedTargets2 = (table) => table.links.flatMap(
2433
+ (link) => (
2434
+ // A self-target is not an ordering dependency — the FK builds inline.
2435
+ link.enforce && link.target !== void 0 && link.target !== table.table ? [link.target] : []
1645
2436
  )
1646
- ).max(MAX_CAPABILITY_PINS).default([]);
1647
- function parseCapabilityPin(pin) {
1648
- return pin.startsWith("org/") ? { scope: "org", key: pin.slice("org/".length) } : { scope: "host", key: pin };
2437
+ );
2438
+ function applyMigrationHintsV2(previous, definition) {
2439
+ const adjusted = structuredClone(previous);
2440
+ const statements = [];
2441
+ const schemaName = ormSchemaName(definition.namespace);
2442
+ const qualified = (table) => `${quoteIdentifier(schemaName)}.${quoteIdentifier(table)}`;
2443
+ const enumsByName = new Map(definition.enums.map((entry) => [entry.name, entry]));
2444
+ for (const table of columnTablesV2(definition)) {
2445
+ if (table.renamedFrom) {
2446
+ applyTableRename({ adjusted, schemaName, table, renamedFrom: table.renamedFrom, statements, qualified });
2447
+ }
2448
+ const snapshotTable = findTable2(adjusted, schemaName, table.table);
2449
+ if (!snapshotTable) continue;
2450
+ for (const column of table.columns) {
2451
+ const name = column.columnName;
2452
+ if (column.renamedFrom) {
2453
+ const previousColumn = snapshotTable.columns[column.renamedFrom];
2454
+ if (previousColumn && snapshotTable.columns[name]) {
2455
+ throw new OrmDefinitionError(
2456
+ `'${table.table}.${name}' declares renamedFrom '${column.renamedFrom}', but both columns exist in the previous schema \u2014 a rename cannot overwrite a live column`
2457
+ );
2458
+ }
2459
+ if (previousColumn) {
2460
+ statements.push(
2461
+ `ALTER TABLE ${qualified(table.table)} RENAME COLUMN ${quoteIdentifier(column.renamedFrom)} TO ${quoteIdentifier(name)}`
2462
+ );
2463
+ delete snapshotTable.columns[column.renamedFrom];
2464
+ snapshotTable.columns[name] = { ...previousColumn, name };
2465
+ } else if (!snapshotTable.columns[name]) {
2466
+ throw new OrmDefinitionError(
2467
+ `'${table.table}.${name}' declares renamedFrom '${column.renamedFrom}', but the previous schema has neither column \u2014 check the declared source name`
2468
+ );
2469
+ }
2470
+ }
2471
+ const cast = column.cast ? castParts(column.cast) : null;
2472
+ if (cast) {
2473
+ const current = snapshotTable.columns[name];
2474
+ const { snapshotType, sqlType } = castTargetTypes(column, enumsByName, schemaName, table.table);
2475
+ if (current && current.type !== snapshotType) {
2476
+ statements.push(
2477
+ `ALTER TABLE ${qualified(table.table)} ALTER COLUMN ${quoteIdentifier(name)} TYPE ${sqlType} USING ${quoteIdentifier(name)}::${sqlType}`
2478
+ );
2479
+ current.type = snapshotType;
2480
+ }
2481
+ }
2482
+ }
2483
+ }
2484
+ return { statements, adjusted };
2485
+ }
2486
+ function castTargetTypes(column, enums, schemaName, table) {
2487
+ if (typeof column.type === "string") {
2488
+ const name = sqlTypeName(column.type);
2489
+ return { snapshotType: name, sqlType: name };
2490
+ }
2491
+ const enumName = column.type.enum;
2492
+ if (!enums.has(enumName)) {
2493
+ throw new OrmDefinitionError(`column '${table}.${column.columnName}' casts to undeclared enum '${enumName}'`);
2494
+ }
2495
+ return { snapshotType: enumName, sqlType: `${quoteIdentifier(schemaName)}.${quoteIdentifier(enumName)}` };
1649
2496
  }
1650
- function validateCapabilityPins({
1651
- uses,
1652
- roles
2497
+ function applyTableRename({
2498
+ adjusted,
2499
+ schemaName,
2500
+ table,
2501
+ renamedFrom,
2502
+ statements,
2503
+ qualified
1653
2504
  }) {
1654
- const errors = [];
1655
- const seen = /* @__PURE__ */ new Set();
1656
- const roleKeys = new Set(Object.keys(roles?.definitions ?? {}));
1657
- for (const pin of uses) {
1658
- if (seen.has(pin)) errors.push(`Pin "${pin}" is listed more than once`);
1659
- seen.add(pin);
1660
- const parsed = parseCapabilityPin(pin);
1661
- if (parsed.scope === "host" && roleKeys.has(parsed.key)) {
1662
- errors.push(`Pin "${pin}" references a role \u2014 roles are never pinned`);
1663
- }
2505
+ const tables = adjusted.tables ?? {};
2506
+ const previousEntry = Object.entries(tables).find(
2507
+ ([, entry]) => entry.schema === schemaName && entry.name === renamedFrom
2508
+ );
2509
+ const currentTable = findTable2(adjusted, schemaName, table.table);
2510
+ if (previousEntry && currentTable) {
2511
+ throw new OrmDefinitionError(
2512
+ `'${table.table}' declares renamedFrom '${renamedFrom}', but both tables exist in the previous schema \u2014 a rename cannot overwrite a live table`
2513
+ );
2514
+ }
2515
+ if (!previousEntry) {
2516
+ if (currentTable) return;
2517
+ throw new OrmDefinitionError(
2518
+ `'${table.table}' declares renamedFrom '${renamedFrom}', but the previous schema has neither table \u2014 check the declared source name`
2519
+ );
2520
+ }
2521
+ statements.push(`ALTER TABLE ${qualified(renamedFrom)} RENAME TO ${quoteIdentifier(table.table)}`);
2522
+ const [previousKey, previousTable] = previousEntry;
2523
+ delete tables[previousKey];
2524
+ tables[`${schemaName}.${table.table}`] = { ...previousTable, name: table.table };
2525
+ }
2526
+ function findTable2(snapshot, schema, table) {
2527
+ const tables = snapshot.tables ?? {};
2528
+ return Object.values(tables).find((entry) => entry.schema === schema && entry.name === table);
2529
+ }
2530
+ async function planMigrationV2({
2531
+ canonical,
2532
+ previousSnapshot
2533
+ }) {
2534
+ const schema = ormSchemaName(canonical.namespace);
2535
+ const previous = previousSnapshot ? normalizeSnapshot(previousSnapshot) : emptySnapshot(canonical.namespace);
2536
+ const hints = applyMigrationHintsV2(previous, canonical);
2537
+ const snapshot = generateSnapshotV2(canonical, previousId2(previous));
2538
+ const ddl = await diffStatements(hints.adjusted, snapshot);
2539
+ const statements = [
2540
+ ...hints.statements.map((statement) => ({ kind: "hint", sql: statement })),
2541
+ ...ddl.map((statement) => ({ kind: "ddl", sql: statement.replace(/;\s*$/, "") }))
2542
+ ];
2543
+ return { namespace: canonical.namespace, schema, statements, snapshot };
2544
+ }
2545
+ var previousId2 = (snapshot) => snapshot.id;
2546
+ var IR_VERSION = 1;
2547
+ var CLAIMS_CONTRACT = {
2548
+ sub: "string",
2549
+ org: "string?",
2550
+ roles: "string[]",
2551
+ capabilities: "string[]"
2552
+ };
2553
+ var scalarLiteral = zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.null()]);
2554
+ var valueIrSchema = zod.z.discriminatedUnion("kind", [
2555
+ zod.z.object({ kind: zod.z.literal("literal"), value: zod.z.union([scalarLiteral, zod.z.array(scalarLiteral)]) }),
2556
+ zod.z.object({ kind: zod.z.literal("variable"), name: zod.z.string() }),
2557
+ zod.z.object({ kind: zod.z.literal("claim"), key: zod.z.enum(["sub", "org"]) })
2558
+ ]);
2559
+ var CMP_OPS = [
2560
+ "eq",
2561
+ "neq",
2562
+ "gt",
2563
+ "gte",
2564
+ "lt",
2565
+ "lte",
2566
+ "in",
2567
+ "nin",
2568
+ "like",
2569
+ "ilike",
2570
+ "isNull",
2571
+ "contains",
2572
+ "hasKey"
2573
+ ];
2574
+ var predIrSchema = zod.z.lazy(
2575
+ () => zod.z.discriminatedUnion("kind", [
2576
+ zod.z.object({ kind: zod.z.literal("and"), operands: zod.z.array(predIrSchema).min(1) }),
2577
+ zod.z.object({ kind: zod.z.literal("or"), operands: zod.z.array(predIrSchema).min(1) }),
2578
+ zod.z.object({ kind: zod.z.literal("not"), operand: predIrSchema }),
2579
+ zod.z.object({ kind: zod.z.literal("cmp"), op: zod.z.enum(CMP_OPS), column: zod.z.string(), value: valueIrSchema }),
2580
+ zod.z.object({ kind: zod.z.literal("exists"), link: zod.z.string(), where: predIrSchema }),
2581
+ zod.z.object({
2582
+ kind: zod.z.literal("aggPredicate"),
2583
+ link: zod.z.string(),
2584
+ fn: zod.z.literal("count"),
2585
+ op: zod.z.enum(["eq", "neq", "gt", "gte", "lt", "lte"]),
2586
+ value: zod.z.number(),
2587
+ where: predIrSchema.optional()
2588
+ }),
2589
+ zod.z.object({ kind: zod.z.literal("capability"), key: zod.z.string() }),
2590
+ zod.z.object({ kind: zod.z.literal("role"), key: zod.z.string() }),
2591
+ zod.z.object({ kind: zod.z.literal("dynamicFilter"), slot: zod.z.string() }),
2592
+ zod.z.object({ kind: zod.z.literal("const"), value: zod.z.boolean() })
2593
+ ])
2594
+ );
2595
+ var orderIrSchema = zod.z.discriminatedUnion("kind", [
2596
+ zod.z.object({
2597
+ kind: zod.z.literal("column"),
2598
+ column: zod.z.string(),
2599
+ /** Order through a to-one link: `link` is set and `column` is on the target. */
2600
+ link: zod.z.string().optional(),
2601
+ direction: zod.z.enum(["asc", "desc"]),
2602
+ nulls: zod.z.enum(["first", "last"]).optional()
2603
+ }),
2604
+ /** §4f: `$orderBy: [FooOrderBy!]` variable — validated + lowered at runtime. */
2605
+ zod.z.object({ kind: zod.z.literal("dynamic"), slot: zod.z.string() })
2606
+ ]);
2607
+ var limitIrSchema = zod.z.object({
2608
+ /** Fixed value or a variable, clamped to [1, max]; absent → default. */
2609
+ variable: zod.z.string().optional(),
2610
+ value: zod.z.number().int().positive().optional(),
2611
+ default: zod.z.number().int().positive(),
2612
+ max: zod.z.number().int().positive()
2613
+ });
2614
+ var selectionIrSchema = zod.z.lazy(
2615
+ () => zod.z.object({
2616
+ typename: zod.z.string(),
2617
+ columns: zod.z.array(zod.z.object({ alias: zod.z.string(), column: zod.z.string() })),
2618
+ relations: zod.z.array(zod.z.object({
2619
+ alias: zod.z.string(),
2620
+ link: zod.z.string(),
2621
+ selection: selectionIrSchema,
2622
+ where: predIrSchema.optional(),
2623
+ orderBy: zod.z.array(orderIrSchema).optional(),
2624
+ limit: limitIrSchema.optional(),
2625
+ offset: zod.z.object({ variable: zod.z.string().optional(), value: zod.z.number().int().optional() }).optional()
2626
+ })),
2627
+ aggregates: zod.z.array(zod.z.object({
2628
+ alias: zod.z.string(),
2629
+ link: zod.z.string().optional(),
2630
+ where: predIrSchema.optional(),
2631
+ count: zod.z.object({ columns: zod.z.array(zod.z.string()).optional(), distinct: zod.z.boolean().optional() }).optional(),
2632
+ sum: zod.z.array(zod.z.string()).optional(),
2633
+ avg: zod.z.array(zod.z.string()).optional(),
2634
+ nodes: selectionIrSchema.optional()
2635
+ }))
2636
+ })
2637
+ );
2638
+ var includeIfSchema = zod.z.object({ variable: zod.z.string(), negated: zod.z.boolean() });
2639
+ var selectRootSchema = zod.z.object({
2640
+ kind: zod.z.literal("select"),
2641
+ alias: zod.z.string(),
2642
+ table: zod.z.string(),
2643
+ selection: selectionIrSchema,
2644
+ /** Composed at compile time: AND(policy, documentWhere?, dynamicFilter?). */
2645
+ where: predIrSchema,
2646
+ orderBy: zod.z.array(orderIrSchema).default([]),
2647
+ distinctOn: zod.z.union([zod.z.array(zod.z.string()), zod.z.object({ slot: zod.z.string() })]).optional(),
2648
+ limit: limitIrSchema,
2649
+ offset: zod.z.object({ variable: zod.z.string().optional(), value: zod.z.number().int().optional() }).optional(),
2650
+ includeIf: includeIfSchema.optional()
2651
+ });
2652
+ var byPkRootSchema = zod.z.object({
2653
+ kind: zod.z.literal("byPk"),
2654
+ alias: zod.z.string(),
2655
+ table: zod.z.string(),
2656
+ selection: selectionIrSchema,
2657
+ pk: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })).min(1),
2658
+ /** Policy predicate — ANDed with the PK match. */
2659
+ where: predIrSchema,
2660
+ includeIf: includeIfSchema.optional()
2661
+ });
2662
+ var aggregateRootSchema = zod.z.object({
2663
+ kind: zod.z.literal("aggregate"),
2664
+ alias: zod.z.string(),
2665
+ table: zod.z.string(),
2666
+ where: predIrSchema,
2667
+ count: zod.z.object({ columns: zod.z.array(zod.z.string()).optional(), distinct: zod.z.boolean().optional() }).optional(),
2668
+ sum: zod.z.array(zod.z.string()).optional(),
2669
+ avg: zod.z.array(zod.z.string()).optional(),
2670
+ nodes: selectionIrSchema.optional(),
2671
+ includeIf: includeIfSchema.optional()
2672
+ });
2673
+ var writeValuesSchema = zod.z.union([
2674
+ zod.z.object({ slot: zod.z.string() }),
2675
+ zod.z.object({ entries: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })) })
2676
+ ]);
2677
+ var onConflictIrSchema = zod.z.union([
2678
+ zod.z.object({ slot: zod.z.string() }),
2679
+ zod.z.object({ constraint: zod.z.string(), updateColumns: zod.z.array(zod.z.string()) })
2680
+ ]);
2681
+ var mutationRootSchema = zod.z.object({
2682
+ kind: zod.z.literal("mutation"),
2683
+ op: zod.z.enum(["insert", "insertOne", "update", "updateByPk", "delete", "deleteByPk"]),
2684
+ alias: zod.z.string(),
2685
+ table: zod.z.string(),
2686
+ /** insert/insertOne: rows come from a slot ($object/$objects) or literals. */
2687
+ objects: zod.z.union([
2688
+ zod.z.object({ slot: zod.z.string() }),
2689
+ zod.z.object({ rows: zod.z.array(zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema }))) })
2690
+ ]).optional(),
2691
+ /** Server-pinned columns (e.g. author_sub ← claim('sub')) merged into every inserted row. */
2692
+ pinnedColumns: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })).default([]),
2693
+ onConflict: onConflictIrSchema.optional(),
2694
+ set: writeValuesSchema.optional(),
2695
+ append: writeValuesSchema.optional(),
2696
+ inc: writeValuesSchema.optional(),
2697
+ /** update/delete row filter: AND(writePolicy, documentWhere/pk, dynamicFilter?). */
2698
+ where: predIrSchema.optional(),
2699
+ pk: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })).optional(),
2700
+ /** WITH CHECK analogue evaluated against NEW row values (insert/update). */
2701
+ insertCheck: predIrSchema.optional(),
2702
+ returning: selectionIrSchema.nullable(),
2703
+ affectedRows: zod.z.boolean().default(false),
2704
+ includeIf: includeIfSchema.optional()
2705
+ });
2706
+ var actionRootSchema = zod.z.object({
2707
+ kind: zod.z.literal("action"),
2708
+ alias: zod.z.string(),
2709
+ name: zod.z.string(),
2710
+ params: zod.z.array(zod.z.object({ name: zod.z.string(), value: valueIrSchema })),
2711
+ returns: zod.z.enum(["rows", "rowsAffected", "scalar"])
2712
+ });
2713
+ var rootIrSchema = zod.z.discriminatedUnion("kind", [
2714
+ selectRootSchema,
2715
+ byPkRootSchema,
2716
+ aggregateRootSchema,
2717
+ mutationRootSchema,
2718
+ actionRootSchema
2719
+ ]);
2720
+ var INPUT_REF_KINDS = [
2721
+ "boolExp",
2722
+ "orderBy",
2723
+ "selectColumn",
2724
+ "insertInput",
2725
+ "setInput",
2726
+ "appendInput",
2727
+ "onConflict"
2728
+ ];
2729
+ var variableDefaultIrSchema = zod.z.object({
2730
+ value: zod.z.union([scalarLiteral, zod.z.array(scalarLiteral)])
2731
+ });
2732
+ var variableIrSchema = zod.z.object({
2733
+ name: zod.z.string(),
2734
+ type: zod.z.union([
2735
+ zod.z.object({ kind: zod.z.literal("scalar"), scalar: zod.z.enum(COLUMN_TYPES) }),
2736
+ /** `values` is the declared membership whitelist — the executor validates against it. */
2737
+ zod.z.object({ kind: zod.z.literal("enum"), name: zod.z.string(), values: zod.z.array(zod.z.string()).min(1) }),
2738
+ /** §4f dynamic slot: validated against `tables[table]` whitelists at runtime. */
2739
+ zod.z.object({ kind: zod.z.literal("inputRef"), input: zod.z.enum(INPUT_REF_KINDS), table: zod.z.string() })
2740
+ ]),
2741
+ nullable: zod.z.boolean(),
2742
+ list: zod.z.boolean(),
2743
+ /** Absent = no default declared; see {@link variableDefaultIrSchema}. */
2744
+ defaultValue: variableDefaultIrSchema.optional()
2745
+ });
2746
+ var compiledOperationSchema = zod.z.object({
2747
+ irVersion: zod.z.literal(IR_VERSION),
2748
+ name: zod.z.string(),
2749
+ opHash: zod.z.string().regex(/^sha256:[0-9a-f]{64}$/),
2750
+ kind: zod.z.enum(["query", "mutation", "action"]),
2751
+ requires: zod.z.object({
2752
+ capability: zod.z.string().optional(),
2753
+ role: zod.z.string().optional()
2754
+ }).nullable(),
2755
+ variables: zod.z.array(variableIrSchema),
2756
+ /** Every table the op touches — data-token scoping + audit. */
2757
+ tableSet: zod.z.array(zod.z.string()).min(1),
2758
+ roots: zod.z.array(rootIrSchema).min(1)
2759
+ });
2760
+ var tableMetaIrSchema = zod.z.object({
2761
+ table: zod.z.string(),
2762
+ schema: zod.z.string(),
2763
+ typename: zod.z.string(),
2764
+ columns: zod.z.array(zod.z.object({
2765
+ name: zod.z.string(),
2766
+ columnName: zod.z.string(),
2767
+ type: zod.z.union([zod.z.enum(COLUMN_TYPES), zod.z.object({ enum: zod.z.string(), values: zod.z.array(zod.z.string()) })]),
2768
+ nullable: zod.z.boolean()
2769
+ })),
2770
+ primaryKey: zod.z.array(zod.z.string()).min(1),
2771
+ links: zod.z.array(zod.z.object({
2772
+ name: zod.z.string(),
2773
+ kind: zod.z.enum(["toOne", "toMany", "toPlatformUser"]),
2774
+ target: zod.z.string(),
2775
+ on: zod.z.string(),
2776
+ references: zod.z.string()
2777
+ })),
2778
+ /** §4f whitelists: what dynamic inputs may reference. */
2779
+ filterable: zod.z.array(zod.z.string()),
2780
+ orderable: zod.z.array(zod.z.string()),
2781
+ insertable: zod.z.array(zod.z.string()),
2782
+ settable: zod.z.array(zod.z.string()),
2783
+ appendable: zod.z.array(zod.z.string()),
2784
+ constraints: zod.z.array(zod.z.object({ name: zod.z.string(), columns: zod.z.array(zod.z.string()) })),
2785
+ /** Depth/node caps for dynamic filter trees on this table. */
2786
+ dynamicFilterMaxDepth: zod.z.number().int().positive().default(6),
2787
+ dynamicFilterMaxNodes: zod.z.number().int().positive().default(64)
2788
+ });
2789
+ var compiledArtifactSchema = zod.z.object({
2790
+ irVersion: zod.z.literal(IR_VERSION),
2791
+ namespace: zod.z.string(),
2792
+ schemaHash: zod.z.string(),
2793
+ opsHash: zod.z.string(),
2794
+ tables: zod.z.record(zod.z.string(), tableMetaIrSchema),
2795
+ operations: zod.z.record(zod.z.string(), compiledOperationSchema)
2796
+ });
2797
+ var IrVersionError = class extends Error {
2798
+ constructor(found) {
2799
+ super(`Unsupported IR version ${String(found)} \u2014 this executor supports up to ${IR_VERSION}. Upgrade @sequenceholdings/orm or re-push the namespace.`);
2800
+ this.name = "IrVersionError";
1664
2801
  }
1665
- return errors;
2802
+ };
2803
+ function normalizeIr(raw) {
2804
+ if (!raw || typeof raw !== "object") throw new IrVersionError(void 0);
2805
+ const version = raw.irVersion;
2806
+ if (version !== IR_VERSION) throw new IrVersionError(version);
2807
+ return compiledArtifactSchema.parse(raw);
2808
+ }
2809
+ function indexByHash(artifact) {
2810
+ const map = /* @__PURE__ */ new Map();
2811
+ for (const op of Object.values(artifact.operations)) map.set(op.opHash, op);
2812
+ return map;
1666
2813
  }
1667
2814
 
1668
2815
  // src/schema/namespace.ts
@@ -1696,7 +2843,7 @@ function buildNamespaceDefinition(files, config) {
1696
2843
  }
1697
2844
  }
1698
2845
  const capabilities = config?.capabilities ? { roles: config.capabilities.roles ?? EMPTY_CAPABILITIES.roles, uses: config.capabilities.uses ?? [] } : EMPTY_CAPABILITIES;
1699
- const pinIssues = validateCapabilityPins({ uses: capabilities.uses, roles: capabilities.roles });
2846
+ const pinIssues = customRolesManifest.validateCapabilityPins({ uses: capabilities.uses, roles: capabilities.roles });
1700
2847
  if (pinIssues.length > 0) throw new OrmDefinitionError(pinIssues.join("; "), "namespace.yaml");
1701
2848
  const tables = files.map(({ table }) => table).sort((a, b) => a.table.localeCompare(b.table));
1702
2849
  const byName = new Map(tables.map((table) => [table.table, table]));
@@ -1806,8 +2953,8 @@ var namespaceConfigSchema = zod.z.strictObject({
1806
2953
  namespace: namespaceSchema,
1807
2954
  description: zod.z.string().optional(),
1808
2955
  capabilities: zod.z.strictObject({
1809
- roles: customRolesBlockSchema.optional(),
1810
- uses: capabilityPinsSchema.optional()
2956
+ roles: customRolesManifest.customRolesBlockSchema.optional(),
2957
+ uses: customRolesManifest.capabilityPinsSchema.optional()
1811
2958
  }).optional()
1812
2959
  });
1813
2960
 
@@ -1920,8 +3067,8 @@ async function readMigrationWorkspace(dir, namespace) {
1920
3067
  journalPath
1921
3068
  );
1922
3069
  }
1923
- parsed.data.entries.forEach((entry, index2) => {
1924
- if (entry.ordinal !== index2 + 1) {
3070
+ parsed.data.entries.forEach((entry, index3) => {
3071
+ if (entry.ordinal !== index3 + 1) {
1925
3072
  throw new OrmDefinitionError(`migration journal entries must be contiguous from 1 (found ${entry.name})`, journalPath);
1926
3073
  }
1927
3074
  });
@@ -1944,7 +3091,7 @@ async function readMigrationSql(dir, entry) {
1944
3091
  throw new OrmDefinitionError("missing migration file", path$1);
1945
3092
  });
1946
3093
  }
1947
- var checksumOf = (text2) => crypto.createHash("sha256").update(text2).digest("hex");
3094
+ var checksumOf = (text3) => crypto.createHash("sha256").update(text3).digest("hex");
1948
3095
  var migrationName = (ordinal, contentHash) => `${pad(ordinal)}_${contentHash.slice(0, 12)}`;
1949
3096
  function renderMigrationSql({
1950
3097
  name,
@@ -1970,12 +3117,12 @@ async function writeMigration({
1970
3117
  const tip = workspace.journal.entries.at(-1);
1971
3118
  const ordinal = (tip?.ordinal ?? 0) + 1;
1972
3119
  const name = migrationName(ordinal, contentHash);
1973
- const sql2 = renderMigrationSql({ name, namespace: workspace.journal.namespace, contentHash, plan });
3120
+ const sql3 = renderMigrationSql({ name, namespace: workspace.journal.namespace, contentHash, plan });
1974
3121
  const metaDir = path.join(dir, MIGRATIONS_DIRNAME, META_DIRNAME);
1975
3122
  await promises.mkdir(metaDir, { recursive: true });
1976
3123
  const snapshotText = `${JSON.stringify(plan.snapshot, null, 2)}
1977
3124
  `;
1978
- await promises.writeFile(path.join(dir, MIGRATIONS_DIRNAME, `${name}.sql`), sql2);
3125
+ await promises.writeFile(path.join(dir, MIGRATIONS_DIRNAME, `${name}.sql`), sql3);
1979
3126
  await promises.writeFile(path.join(metaDir, `${pad(ordinal)}.snapshot.json`), snapshotText);
1980
3127
  const journal = {
1981
3128
  ...workspace.journal,
@@ -1986,7 +3133,7 @@ async function writeMigration({
1986
3133
  name,
1987
3134
  content_hash: contentHash,
1988
3135
  previous_content_hash: tip?.content_hash ?? null,
1989
- checksum: checksumOf(sql2),
3136
+ checksum: checksumOf(sql3),
1990
3137
  snapshot_checksum: checksumOf(snapshotText),
1991
3138
  destructive
1992
3139
  }
@@ -2098,11 +3245,11 @@ async function checkWorkspace({
2098
3245
  log(`no committed migrations for '${loaded.definition.namespace}' \u2014 run \`seq-studio orm diff\` and commit the result`);
2099
3246
  return 1;
2100
3247
  }
2101
- let previousId2;
3248
+ let previousId3;
2102
3249
  let previousHash = null;
2103
3250
  for (const entry of workspace.journal.entries) {
2104
- const sql2 = await readMigrationSql(dir, entry);
2105
- if (checksumOf(sql2) !== entry.checksum) {
3251
+ const sql3 = await readMigrationSql(dir, entry);
3252
+ if (checksumOf(sql3) !== entry.checksum) {
2106
3253
  log(`${MIGRATIONS_DIRNAME}/${entry.name}.sql does not match its journal checksum \u2014 committed migrations must not be edited`);
2107
3254
  return 1;
2108
3255
  }
@@ -2112,7 +3259,7 @@ async function checkWorkspace({
2112
3259
  return 1;
2113
3260
  }
2114
3261
  const snapshot = JSON.parse(snapshotText);
2115
- if (entry.ordinal > 1 && snapshot.prevId !== previousId2) {
3262
+ if (entry.ordinal > 1 && snapshot.prevId !== previousId3) {
2116
3263
  log(`snapshot chain broken at ${entry.name} \u2014 regenerate the workspace with \`seq-studio orm diff\``);
2117
3264
  return 1;
2118
3265
  }
@@ -2120,7 +3267,7 @@ async function checkWorkspace({
2120
3267
  log(`content-hash chain broken at ${entry.name} \u2014 migrations must be appended in order by \`seq-studio orm diff\``);
2121
3268
  return 1;
2122
3269
  }
2123
- previousId2 = snapshot.id;
3270
+ previousId3 = snapshot.id;
2124
3271
  previousHash = entry.content_hash;
2125
3272
  }
2126
3273
  if (tip.content_hash !== loaded.contentHash) {
@@ -2142,12 +3289,161 @@ async function checkWorkspace({
2142
3289
  log(`migrations in sync \u2014 ${workspace.journal.entries.length} committed, tip ${tip.name}`);
2143
3290
  return 0;
2144
3291
  }
2145
- var firstLine = (sql2) => sql2.split("\n")[0] ?? sql2;
3292
+ var firstLine = (sql3) => sql3.split("\n")[0] ?? sql3;
3293
+
3294
+ // src/migrations/from-yaml.ts
3295
+ function convertV1DefinitionToCanonical(definition) {
3296
+ const raw = {
3297
+ definition_format: CANONICAL_FORMAT,
3298
+ namespace: definition.namespace,
3299
+ description: definition.description ?? void 0,
3300
+ enums: [],
3301
+ tables: definition.tables.map(convertTable),
3302
+ capabilities: {
3303
+ roles: definition.capabilities.roles,
3304
+ uses: [...definition.capabilities.uses]
3305
+ }
3306
+ };
3307
+ const parsed = canonicalDefinitionSchema.safeParse(raw);
3308
+ if (!parsed.success) {
3309
+ const issue = parsed.error.issues[0];
3310
+ throw new OrmDefinitionError(
3311
+ `converted definition is not valid canonical v2: ${issue ? `${issue.path.join(".")}: ${issue.message}` : "unknown issue"}`
3312
+ );
3313
+ }
3314
+ return normalizeCanonical(parsed.data);
3315
+ }
3316
+ function convertTable(table) {
3317
+ const columns = Object.entries(table.columns ?? {});
3318
+ const primaryKey2 = columns.filter(([, column]) => column.primary_key).map(([name]) => name);
3319
+ return {
3320
+ table: table.table,
3321
+ description: table.description,
3322
+ source: table.source,
3323
+ columns: columns.map(([name, column]) => convertColumn(name, column)),
3324
+ // Synced tables reflect their source — no columns, no primary key.
3325
+ primaryKey: primaryKey2.length > 0 ? primaryKey2 : void 0,
3326
+ links: Object.entries(table.links ?? {}).map(([name, link]) => convertLink(table.table, name, link)),
3327
+ indexes: (table.indexes ?? []).map((index3) => ({
3328
+ columns: [...index3.columns],
3329
+ unique: index3.unique ?? false,
3330
+ name: index3.name
3331
+ })),
3332
+ policies: {
3333
+ // Verbatim DSL source strings — the parsed v1 AST is derived state.
3334
+ read: table.policies?.read?.source,
3335
+ write: table.policies?.write?.source
3336
+ },
3337
+ actions: Object.entries(table.actions ?? {}).map(([name, action]) => convertAction(table.table, name, action))
3338
+ };
3339
+ }
3340
+ function convertColumn(name, column) {
3341
+ const isDefaultFn = column.default !== void 0 && isFunctionDefault(column.default, column.type);
3342
+ return {
3343
+ name,
3344
+ columnName: name,
3345
+ type: column.type,
3346
+ nullable: column.primary_key ? false : column.nullable !== false,
3347
+ unique: column.unique === true,
3348
+ default: isDefaultFn ? void 0 : column.default,
3349
+ // isFunctionDefault guarantees one of the two allowlisted functions; the
3350
+ // canonicalDefinitionSchema parse below re-checks the enum.
3351
+ defaultFn: isDefaultFn ? column.default : void 0,
3352
+ description: column.description,
3353
+ renamedFrom: column.renamed_from,
3354
+ cast: column.cast,
3355
+ deprecated: column.deprecated === true
3356
+ };
3357
+ }
3358
+ function convertLink(table, name, link) {
3359
+ if (link.to.includes(".")) {
3360
+ throw new OrmDefinitionError(
3361
+ `link '${name}' on '${table}' targets '${link.to}' \u2014 cross-namespace links have no canonical v2 representation (links are namespace-local in v2)`
3362
+ );
3363
+ }
3364
+ return {
3365
+ name,
3366
+ kind: "toOne",
3367
+ target: link.to,
3368
+ on: link.on,
3369
+ enforce: link.enforce === true,
3370
+ description: link.description
3371
+ };
3372
+ }
3373
+ function convertAction(table, name, action) {
3374
+ return {
3375
+ name,
3376
+ requires: action.requires?.source,
3377
+ params: Object.fromEntries(
3378
+ Object.entries(action.params ?? {}).map(([param, definition]) => [
3379
+ param,
3380
+ { type: definition.type, nullable: definition.optional === true }
3381
+ ])
3382
+ ),
3383
+ // The v2 contract carries one SQL string; statement boundaries survive as
3384
+ // `;\n` (v1 validation guarantees no bare `;` inside a single statement).
3385
+ executes: actionStatementSources(action.executes).join(";\n"),
3386
+ // v1 declared the RETURNING columns inline; v2 types them at compile time,
3387
+ // so the shape collapses to rows-vs-rowsAffected.
3388
+ returns: action.returns ? "rows" : "rowsAffected",
3389
+ audit: action.audit ? { action: action.audit.action, resource: action.audit.resource ?? table } : void 0
3390
+ };
3391
+ }
3392
+
3393
+ // src/migrations/v2.ts
3394
+ var SHA256_HEX = /^[0-9a-f]{64}$/;
3395
+ function rebaseViolations(statements, options) {
3396
+ const allowSecurity = options?.allowSecurityReemission ?? false;
3397
+ return statements.filter((statement) => !(statement.kind === "security" && allowSecurity));
3398
+ }
3399
+ var verifyRebaseIsNoop = (plan, options) => rebaseViolations(plan.statements, options).length === 0;
3400
+ function buildRebaseJournalEntry({ namespace, previousHash, newHash, ordinal, snapshot }) {
3401
+ if (!SHA256_HEX.test(previousHash)) {
3402
+ throw new OrmDefinitionError(`rebase previousHash is not a sha256 hex digest: '${previousHash}'`);
3403
+ }
3404
+ if (!SHA256_HEX.test(newHash)) {
3405
+ throw new OrmDefinitionError(`rebase newHash is not a sha256 hex digest: '${newHash}'`);
3406
+ }
3407
+ if (previousHash === newHash) {
3408
+ throw new OrmDefinitionError("rebase previousHash and newHash are identical \u2014 nothing to rebase");
3409
+ }
3410
+ if (!Number.isInteger(ordinal) || ordinal < 2) {
3411
+ throw new OrmDefinitionError(`rebase ordinal must be an integer \u2265 2 (a rebase sits on an existing journal tip); got ${ordinal}`);
3412
+ }
3413
+ const name = migrationName(ordinal, newHash);
3414
+ const sql3 = renderRebaseMigrationSql({ name, namespace, previousHash, newHash });
3415
+ const snapshotText = `${JSON.stringify(snapshot, null, 2)}
3416
+ `;
3417
+ const entry = {
3418
+ ordinal,
3419
+ name,
3420
+ content_hash: newHash,
3421
+ previous_content_hash: previousHash,
3422
+ checksum: checksumOf(sql3),
3423
+ snapshot_checksum: checksumOf(snapshotText),
3424
+ destructive: false
3425
+ };
3426
+ return { name, entry, sql: sql3, snapshotText };
3427
+ }
3428
+ function renderRebaseMigrationSql({
3429
+ name,
3430
+ namespace,
3431
+ previousHash,
3432
+ newHash
3433
+ }) {
3434
+ return [
3435
+ `-- ${name}`,
3436
+ `-- namespace: ${namespace}`,
3437
+ `-- content hash: ${newHash}`,
3438
+ `-- rebase: v1 definitions (${previousHash}) converted to canonical v2 \u2014 verified no-op, zero statements`,
3439
+ "-- generated by `seq-studio orm diff --rebase` \u2014 review and commit, do not edit"
3440
+ ].join("\n") + "\n";
3441
+ }
2146
3442
 
2147
3443
  // src/schema/canonical.ts
2148
3444
  function parseCanonicalDefinition(value) {
2149
3445
  const canonical = asCanonicalShape(value);
2150
- const files = canonical.tables.map((table, index2) => {
3446
+ const files = canonical.tables.map((table, index3) => {
2151
3447
  const input = {
2152
3448
  namespace: canonical.namespace,
2153
3449
  table: table["table"],
@@ -2164,10 +3460,10 @@ function parseCanonicalDefinition(value) {
2164
3460
  const issue = parsed.error.issues[0];
2165
3461
  throw new OrmDefinitionError(
2166
3462
  `stored definition for table ${String(table["table"])} is invalid: ${issue?.message ?? "unknown issue"}`,
2167
- `canonical[${index2}]`
3463
+ `canonical[${index3}]`
2168
3464
  );
2169
3465
  }
2170
- return { file: `canonical[${index2}]`, table: parsed.data };
3466
+ return { file: `canonical[${index3}]`, table: parsed.data };
2171
3467
  });
2172
3468
  const config = namespaceConfigSchema.safeParse({
2173
3469
  namespace: canonical.namespace,
@@ -2224,22 +3520,56 @@ function canonicalActions(value) {
2224
3520
  );
2225
3521
  }
2226
3522
 
3523
+ Object.defineProperty(exports, "capabilityPinsSchema", {
3524
+ enumerable: true,
3525
+ get: function () { return customRolesManifest.capabilityPinsSchema; }
3526
+ });
3527
+ Object.defineProperty(exports, "customRolesBlockSchema", {
3528
+ enumerable: true,
3529
+ get: function () { return customRolesManifest.customRolesBlockSchema; }
3530
+ });
3531
+ Object.defineProperty(exports, "customRolesDeclared", {
3532
+ enumerable: true,
3533
+ get: function () { return customRolesManifest.customRolesDeclared; }
3534
+ });
3535
+ Object.defineProperty(exports, "parseCapabilityPin", {
3536
+ enumerable: true,
3537
+ get: function () { return customRolesManifest.parseCapabilityPin; }
3538
+ });
3539
+ Object.defineProperty(exports, "validateCapabilityPins", {
3540
+ enumerable: true,
3541
+ get: function () { return customRolesManifest.validateCapabilityPins; }
3542
+ });
2227
3543
  exports.ACTION_REQUIRES_DENIED_SQLSTATE = ACTION_REQUIRES_DENIED_SQLSTATE;
2228
3544
  exports.ACTION_VALIDATES_FAILED_SQLSTATE = ACTION_VALIDATES_FAILED_SQLSTATE;
2229
3545
  exports.AUDIT_ACTIONS = AUDIT_ACTIONS;
3546
+ exports.CANONICAL_FORMAT = CANONICAL_FORMAT;
2230
3547
  exports.CAPABILITIES_CLAIM_KEY = CAPABILITIES_CLAIM_KEY;
2231
3548
  exports.CAPABILITY_KEY_PATTERN = CAPABILITY_KEY_PATTERN;
3549
+ exports.CLAIMS_CONTRACT = CLAIMS_CONTRACT;
2232
3550
  exports.CLAIMS_SETTING = CLAIMS_SETTING;
2233
3551
  exports.CLAIM_KEY_PATTERN = CLAIM_KEY_PATTERN;
2234
- exports.COLUMN_TYPES = COLUMN_TYPES;
3552
+ exports.CMP_OPS = CMP_OPS;
3553
+ exports.COLUMN_BRAND = COLUMN_BRAND;
3554
+ exports.COLUMN_DEFAULT_FNS = COLUMN_DEFAULT_FNS;
3555
+ exports.COLUMN_TYPES = COLUMN_TYPES2;
2235
3556
  exports.COMPARE_OPS = COMPARE_OPS;
2236
3557
  exports.CONSUMER_ROLE_SUFFIX = CONSUMER_ROLE_SUFFIX;
3558
+ exports.ColumnBuilder = ColumnBuilder;
2237
3559
  exports.DEFINITION_FILE_EXTENSIONS = DEFINITION_FILE_EXTENSIONS;
3560
+ exports.ENUM_BRAND = ENUM_BRAND;
2238
3561
  exports.HASH_DOMAIN = HASH_DOMAIN;
2239
3562
  exports.IDENTIFIER_PATTERN = IDENTIFIER_PATTERN;
3563
+ exports.IDENTIFIER_RE = IDENTIFIER_RE;
3564
+ exports.INPUT_REF_KINDS = INPUT_REF_KINDS;
3565
+ exports.IR_VERSION = IR_VERSION;
3566
+ exports.IrVersionError = IrVersionError;
3567
+ exports.LINK_BRAND = LINK_BRAND;
2240
3568
  exports.MAX_DEFINITION_FILE_BYTES = MAX_DEFINITION_FILE_BYTES;
2241
3569
  exports.MAX_IDENTIFIER_LENGTH = MAX_IDENTIFIER_LENGTH;
2242
3570
  exports.MIGRATIONS_DIRNAME = MIGRATIONS_DIRNAME;
3571
+ exports.NAMESPACE_CONFIG_BRAND = NAMESPACE_CONFIG_BRAND;
3572
+ exports.NAMESPACE_CONFIG_FILE = NAMESPACE_CONFIG_FILE;
2243
3573
  exports.NAMESPACE_CONFIG_FILENAMES = NAMESPACE_CONFIG_FILENAMES;
2244
3574
  exports.NAMESPACE_PATTERN = NAMESPACE_PATTERN;
2245
3575
  exports.ORM_DATA_TOKEN_HEADER = ORM_DATA_TOKEN_HEADER;
@@ -2250,8 +3580,10 @@ exports.PredicateParseError = PredicateParseError;
2250
3580
  exports.QUALIFIED_TABLE_PATTERN = QUALIFIED_TABLE_PATTERN;
2251
3581
  exports.RESERVED_COLUMN_NAMES = RESERVED_COLUMN_NAMES;
2252
3582
  exports.RESERVED_TABLE_NAMES = RESERVED_TABLE_NAMES;
3583
+ exports.SCHEMA_DIR = SCHEMA_DIR;
2253
3584
  exports.STATEMENT_KINDS = STATEMENT_KINDS;
2254
3585
  exports.SYNCED_SOURCE_PATTERN = SYNCED_SOURCE_PATTERN;
3586
+ exports.TABLE_BRAND = TABLE_BRAND;
2255
3587
  exports.actionFunctionName = actionFunctionName;
2256
3588
  exports.actionFunctionStatements = actionFunctionStatements;
2257
3589
  exports.actionParamArg = actionParamArg;
@@ -2261,71 +3593,118 @@ exports.actionPrepareChecks = actionPrepareChecks;
2261
3593
  exports.actionSchema = actionSchema;
2262
3594
  exports.actionWriteTargets = actionWriteTargets;
2263
3595
  exports.actionsInterfaceName = actionsInterfaceName;
3596
+ exports.activeAuthoringContext = activeAuthoringContext;
2264
3597
  exports.applyMigrationHints = applyMigrationHints;
3598
+ exports.applyMigrationHintsV2 = applyMigrationHintsV2;
3599
+ exports.beginAuthoringContext = beginAuthoringContext;
2265
3600
  exports.buildActionParamsSchema = buildActionParamsSchema;
2266
3601
  exports.buildDrizzleEntities = buildDrizzleEntities;
3602
+ exports.buildDrizzleEntitiesV2 = buildDrizzleEntitiesV2;
2267
3603
  exports.buildNamespaceDefinition = buildNamespaceDefinition;
3604
+ exports.buildRebaseJournalEntry = buildRebaseJournalEntry;
3605
+ exports.canonicalActionSchema = canonicalActionSchema;
3606
+ exports.canonicalColumnSchema = canonicalColumnSchema;
3607
+ exports.canonicalDefinitionSchema = canonicalDefinitionSchema;
3608
+ exports.canonicalEnumSchema = canonicalEnumSchema;
3609
+ exports.canonicalIndexSchema = canonicalIndexSchema;
3610
+ exports.canonicalLinkSchema = canonicalLinkSchema;
3611
+ exports.canonicalPoliciesSchema = canonicalPoliciesSchema;
3612
+ exports.canonicalTableSchema = canonicalTableSchema;
2268
3613
  exports.canonicalizeDefinition = canonicalizeDefinition;
2269
3614
  exports.capabilityExpression = capabilityExpression;
2270
- exports.capabilityPinsSchema = capabilityPinsSchema;
2271
3615
  exports.castParts = castParts;
2272
3616
  exports.checksumOf = checksumOf;
2273
3617
  exports.claimExpression = claimExpression;
2274
3618
  exports.classifyDestructive = classifyDestructive;
2275
3619
  exports.columnSchema = columnSchema;
2276
- exports.columnTypeSchema = columnTypeSchema;
3620
+ exports.columnTypeSchema = columnTypeSchema2;
2277
3621
  exports.compileActionRequires = compileActionRequires;
2278
3622
  exports.compileActionStatements = compileActionStatements;
2279
3623
  exports.compileNamespace = compileNamespace;
2280
3624
  exports.compilePredicate = compilePredicate;
3625
+ exports.compiledArtifactSchema = compiledArtifactSchema;
3626
+ exports.compiledOperationSchema = compiledOperationSchema;
3627
+ exports.computeCanonicalHash = computeCanonicalHash;
2281
3628
  exports.computeDefinitionHash = computeDefinitionHash;
2282
3629
  exports.consumerRoleName = consumerRoleName;
2283
- exports.customRolesBlockSchema = customRolesBlockSchema;
2284
- exports.customRolesDeclared = customRolesDeclared;
3630
+ exports.convertV1DefinitionToCanonical = convertV1DefinitionToCanonical;
2285
3631
  exports.declaredCapabilityKeys = declaredCapabilityKeys;
3632
+ exports.defineEnum = defineEnum;
3633
+ exports.defineNamespace = defineNamespace;
3634
+ exports.defineSyncedTable = defineSyncedTable;
3635
+ exports.defineTable = defineTable;
3636
+ exports.deriveColumnName = deriveColumnName;
2286
3637
  exports.diffCommand = diffCommand;
2287
3638
  exports.diffStatements = diffStatements;
2288
3639
  exports.emptyJournal = emptyJournal;
2289
3640
  exports.emptySnapshot = emptySnapshot;
3641
+ exports.endAuthoringContext = endAuthoringContext;
2290
3642
  exports.extractNamedParams = extractNamedParams;
2291
3643
  exports.generateNamespaceTypes = generateNamespaceTypes;
2292
3644
  exports.generateSnapshot = generateSnapshot;
3645
+ exports.generateSnapshotV2 = generateSnapshotV2;
2293
3646
  exports.identifierSchema = identifierSchema;
3647
+ exports.indexByHash = indexByHash;
3648
+ exports.isColumnBuilder = isColumnBuilder;
3649
+ exports.isEnumRef = isEnumRef;
2294
3650
  exports.isFunctionDefault = isFunctionDefault;
2295
3651
  exports.isOwnedStatement = isOwnedStatement;
2296
3652
  exports.isQualifiedReference = isQualifiedReference;
3653
+ exports.isSeqLink = isSeqLink;
3654
+ exports.isSeqNamespaceConfig = isSeqNamespaceConfig;
3655
+ exports.isSeqTable = isSeqTable;
3656
+ exports.limitIrSchema = limitIrSchema;
2297
3657
  exports.loadCommittedMigrations = loadCommittedMigrations;
2298
3658
  exports.loadCommittedTipMigration = loadCommittedTipMigration;
2299
3659
  exports.loadNamespaceDefinition = loadNamespaceDefinition;
3660
+ exports.loadNamespaceFromDir = loadNamespaceFromDir;
2300
3661
  exports.migrationName = migrationName;
2301
3662
  exports.namespaceConfigSchema = namespaceConfigSchema;
2302
3663
  exports.namespaceSchema = namespaceSchema;
3664
+ exports.normalizeCanonical = normalizeCanonical;
3665
+ exports.normalizeIr = normalizeIr;
2303
3666
  exports.normalizeSnapshot = normalizeSnapshot;
3667
+ exports.orderIrSchema = orderIrSchema;
2304
3668
  exports.ormSchemaName = ormSchemaName;
2305
3669
  exports.parseCanonicalDefinition = parseCanonicalDefinition;
2306
- exports.parseCapabilityPin = parseCapabilityPin;
2307
3670
  exports.parseDefinitionSources = parseDefinitionSources;
2308
3671
  exports.parsePredicate = parsePredicate;
2309
3672
  exports.parseTableFile = parseTableFile;
2310
3673
  exports.parsedPredicateSchema = parsedPredicateSchema;
2311
3674
  exports.pendingKitStatements = pendingKitStatements;
2312
3675
  exports.planMigration = planMigration;
3676
+ exports.planMigrationV2 = planMigrationV2;
3677
+ exports.policyExpressionSchema = policyExpressionSchema;
3678
+ exports.policyVariantSchema = policyVariantSchema;
3679
+ exports.predIrSchema = predIrSchema;
2313
3680
  exports.predicateOperands = predicateOperands;
2314
3681
  exports.quoteIdentifier = quoteIdentifier;
2315
3682
  exports.quoteLiteral = quoteLiteral;
2316
3683
  exports.readMigrationSql = readMigrationSql;
2317
3684
  exports.readMigrationWorkspace = readMigrationWorkspace;
2318
3685
  exports.readSnapshot = readSnapshot;
3686
+ exports.rebaseViolations = rebaseViolations;
2319
3687
  exports.referencedCapabilities = referencedCapabilities;
2320
3688
  exports.referencedColumns = referencedColumns;
2321
3689
  exports.renderMigrationSql = renderMigrationSql;
3690
+ exports.rootIrSchema = rootIrSchema;
2322
3691
  exports.securityStatements = securityStatements;
3692
+ exports.selectionIrSchema = selectionIrSchema;
3693
+ exports.serializeNamespace = serializeNamespace;
2323
3694
  exports.sqlTypeName = sqlTypeName;
2324
3695
  exports.stableJson = stableJson;
3696
+ exports.t = t;
2325
3697
  exports.tableFileSchema = tableFileSchema;
3698
+ exports.tableMetaIrSchema = tableMetaIrSchema;
2326
3699
  exports.tableReferenceSchema = tableReferenceSchema;
3700
+ exports.toMany = toMany;
3701
+ exports.toOne = toOne;
3702
+ exports.toPlatformUser = toPlatformUser;
2327
3703
  exports.typesInterfaceName = typesInterfaceName;
2328
- exports.validateCapabilityPins = validateCapabilityPins;
3704
+ exports.valueIrSchema = valueIrSchema;
3705
+ exports.variableDefaultIrSchema = variableDefaultIrSchema;
3706
+ exports.variableIrSchema = variableIrSchema;
3707
+ exports.verifyRebaseIsNoop = verifyRebaseIsNoop;
2329
3708
  exports.walkPredicate = walkPredicate;
2330
3709
  exports.writeMigration = writeMigration;
2331
3710
  //# sourceMappingURL=index.cjs.map