@sequenceholdings/orm 0.1.2 → 0.1.3

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 (65) hide show
  1. package/README.md +11 -1
  2. package/dist/authoring.cjs +1066 -59
  3. package/dist/authoring.cjs.map +1 -1
  4. package/dist/authoring.d.cts +289 -24
  5. package/dist/authoring.d.ts +289 -24
  6. package/dist/authoring.js +1056 -60
  7. package/dist/authoring.js.map +1 -1
  8. package/dist/canonical.cjs +415 -9
  9. package/dist/canonical.cjs.map +1 -1
  10. package/dist/canonical.d.cts +235 -1
  11. package/dist/canonical.d.ts +235 -1
  12. package/dist/canonical.js +411 -10
  13. package/dist/canonical.js.map +1 -1
  14. package/dist/cli.cjs +1764 -225
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.js +1765 -226
  17. package/dist/cli.js.map +1 -1
  18. package/dist/client.cjs.map +1 -1
  19. package/dist/client.d.cts +1 -1
  20. package/dist/client.d.ts +1 -1
  21. package/dist/client.js.map +1 -1
  22. package/dist/compiler.cjs +506 -54
  23. package/dist/compiler.cjs.map +1 -1
  24. package/dist/compiler.d.cts +39 -231
  25. package/dist/compiler.d.ts +39 -231
  26. package/dist/compiler.js +504 -55
  27. package/dist/compiler.js.map +1 -1
  28. package/dist/drizzle.cjs +14 -0
  29. package/dist/drizzle.cjs.map +1 -0
  30. package/dist/drizzle.d.cts +1 -0
  31. package/dist/drizzle.d.ts +1 -0
  32. package/dist/drizzle.js +3 -0
  33. package/dist/drizzle.js.map +1 -0
  34. package/dist/dynamic-input.cjs +391 -0
  35. package/dist/dynamic-input.cjs.map +1 -0
  36. package/dist/dynamic-input.d.cts +111 -0
  37. package/dist/dynamic-input.d.ts +111 -0
  38. package/dist/dynamic-input.js +380 -0
  39. package/dist/dynamic-input.js.map +1 -0
  40. package/dist/index.cjs +2223 -219
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +125 -9
  43. package/dist/index.d.ts +125 -9
  44. package/dist/index.js +2199 -220
  45. package/dist/index.js.map +1 -1
  46. package/dist/ir.cjs +249 -14
  47. package/dist/ir.cjs.map +1 -1
  48. package/dist/ir.d.cts +20 -80
  49. package/dist/ir.d.ts +20 -80
  50. package/dist/ir.js +249 -14
  51. package/dist/ir.js.map +1 -1
  52. package/dist/predicate-v2.cjs +1093 -0
  53. package/dist/predicate-v2.cjs.map +1 -0
  54. package/dist/predicate-v2.d.cts +139 -0
  55. package/dist/predicate-v2.d.ts +139 -0
  56. package/dist/predicate-v2.js +1083 -0
  57. package/dist/predicate-v2.js.map +1 -0
  58. package/dist/sdl.cjs +344 -55
  59. package/dist/sdl.cjs.map +1 -1
  60. package/dist/sdl.d.cts +1 -3
  61. package/dist/sdl.d.ts +1 -3
  62. package/dist/sdl.js +344 -55
  63. package/dist/sdl.js.map +1 -1
  64. package/package.json +16 -1
  65. package/templates/orm-namespace/CLAUDE.md +6 -5
@@ -1,6 +1,8 @@
1
- import { CanonicalEnum, CanonicalDefinition, PolicyExpression } from './canonical.cjs';
2
- import { ClaimKey, PredIr, RootIr, InputRefKind, TableMetaIr, CompiledOperation, CompiledArtifact, CmpOp, VariableIr, OrderIr, SelectionIr } from './ir.cjs';
1
+ import { CanonicalEnum, CanonicalDefinition } from './canonical.cjs';
2
+ import { ClaimKey, PredIr, RootIr, InputRefKind, TableMetaIr, CompiledOperation, CompiledArtifact, VariableIr, OrderIr, SelectionIr } from './ir.cjs';
3
3
  import { DocumentNode, OperationDefinitionNode, FragmentDefinitionNode, GraphQLSchema, ValueNode, SelectionSetNode } from 'graphql';
4
+ export { DynamicInputIssue, DynamicInputResult, NormalizedBoolExp, NormalizedOnConflict, NormalizedOrderBy, NormalizedRow, ORDER_BY_DIRECTIONS, ScalarKind, allowedBoolExpOperators, allowedOps, validateAppendInput, validateBoolExpInput, validateInsertInput, validateOnConflictInput, validateOrderByInput, validateSelectColumns, validateSetInput } from './dynamic-input.cjs';
5
+ export { CompilePolicyInput, CompilePredicateInput, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, ParsedPolicy, PolicyColumnInfo, PolicyCompareOp, PolicyCompileError, PolicyCompileErrorCode, PolicyLinkInfo, PolicyNode, PolicyOperand, PolicyParseError, PolicyResolver, PolicyTableInfo, assertClaimsOnlyWhen, compilePolicy, compilePredicateV2, parsePolicy, walkPolicy } from './predicate-v2.cjs';
4
6
  export { P as PLATFORM_USER_TYPENAME, c as camelCase, e as enumTypeName, p as pascalCase } from './naming-DRyinU4u.cjs';
5
7
  import 'zod';
6
8
 
@@ -133,10 +135,28 @@ interface QueryRootInfo {
133
135
  kind: 'select' | 'byPk' | 'aggregate';
134
136
  table: string;
135
137
  }
136
- interface MutationRootInfo {
138
+ interface CrudMutationRootInfo {
137
139
  op: MutationOp;
138
140
  table: string;
139
141
  }
142
+ /**
143
+ * A declared copy-on-write mutation root (canonical `cowMutations`). Carries
144
+ * everything lowering needs so the executor can generate the SQL — no
145
+ * authored statements anywhere in the pipeline.
146
+ */
147
+ interface CowMutationRootInfo {
148
+ op: 'cowOverride' | 'cowRevert';
149
+ table: string;
150
+ /** Logical synced twin table (same namespace). */
151
+ synced: string;
152
+ /** Shared single-column primary-key property. */
153
+ pk: string;
154
+ /** Override: overlay properties written by the UPDATE. */
155
+ set: readonly string[];
156
+ /** Override: properties copied INSERT…SELECT from synced (pk included). */
157
+ copyColumns: readonly string[];
158
+ }
159
+ type MutationRootInfo = CrudMutationRootInfo | CowMutationRootInfo;
140
160
  interface CompileContext {
141
161
  namespace: string;
142
162
  tables: Record<string, TableMetaIr>;
@@ -147,9 +167,14 @@ interface CompileContext {
147
167
  /** GraphQL enum type name → canonical enum (SelectColumn enums are NOT here). */
148
168
  enumsByTypeName: Map<string, CanonicalEnum>;
149
169
  readPolicies: Map<string, PredIr>;
170
+ /** Legacy combined write policy (mutation row filters when insert/update are absent). */
150
171
  writePolicies: Map<string, PredIr>;
151
- /** Per-table `col = claim(k)` write-policy pins (insert-merged, non-insertable). */
172
+ insertPolicies: Map<string, PredIr>;
173
+ updatePolicies: Map<string, PredIr>;
174
+ /** Per-table `col = claim(k)` insert-policy pins (insert-merged, non-insertable). */
152
175
  pins: Map<string, PinnedColumn[]>;
176
+ /** Tables with both `insert` and `update` declared (no legacy `write`-only path). */
177
+ splitWritePolicyTables: ReadonlySet<string>;
153
178
  }
154
179
  /**
155
180
  * §4b curated platform-users view — synthesized, never consumer-defined.
@@ -202,7 +227,7 @@ declare function parseDocuments({ schema, documents, }: {
202
227
  declare function computeSchemaHash(canonical: CanonicalDefinition): string;
203
228
  interface ClientManifestOperation {
204
229
  opHash: string;
205
- kind: 'query' | 'mutation' | 'action';
230
+ kind: 'query' | 'mutation';
206
231
  requires: CompiledOperation['requires'];
207
232
  }
208
233
  /** What codegen/the client transport needs: name → hash mapping + set identity. */
@@ -237,97 +262,6 @@ declare function compileNamespaceOrThrow(input: CompileNamespaceInput): {
237
262
  /** Per-table `col = claim(k)` write-policy pins — exposed for SDL generation options. */
238
263
  declare function computePinnedColumnsByTable(canonical: CanonicalDefinition): Record<string, PinnedColumn[]>;
239
264
 
240
- /**
241
- * §4f dynamic-input validators — PURE, data-only functions the data plane
242
- * imports to check client-supplied values for dynamic slots (BoolExp /
243
- * OrderBy / SelectColumn / InsertInput / SetInput / AppendInput / OnConflict)
244
- * against the artifact's per-table whitelist metadata (TableMetaIr).
245
- *
246
- * No drizzle imports, no IO. Each validator returns a normalized tree or
247
- * typed issues; the executor's runtime lowering step consumes the normalized
248
- * form and ANDs the result with the baked policy predicate — the policy is
249
- * non-negotiable regardless of what the client sends.
250
- */
251
-
252
- interface DynamicInputIssue {
253
- code: 'invalid-shape' | 'unknown-column' | 'unknown-link' | 'unknown-operator' | 'invalid-value' | 'column-not-allowed' | 'nested-insert' | 'unknown-constraint' | 'too-deep' | 'too-many-nodes' | 'too-many-rows';
254
- path: string;
255
- message: string;
256
- }
257
- type DynamicInputResult<T> = {
258
- ok: true;
259
- value: T;
260
- } | {
261
- ok: false;
262
- issues: DynamicInputIssue[];
263
- };
264
- type NormalizedBoolExp = {
265
- kind: 'and' | 'or';
266
- operands: NormalizedBoolExp[];
267
- } | {
268
- kind: 'not';
269
- operand: NormalizedBoolExp;
270
- } | {
271
- kind: 'cmp';
272
- op: CmpOp;
273
- column: string;
274
- value: unknown;
275
- } | {
276
- kind: 'exists';
277
- link: string;
278
- target: string;
279
- where: NormalizedBoolExp;
280
- };
281
- interface NormalizedOrderBy {
282
- column: string;
283
- link?: string;
284
- direction: 'asc' | 'desc';
285
- nulls?: 'first' | 'last';
286
- }
287
- type NormalizedRow = Record<string, unknown>;
288
- interface NormalizedOnConflict {
289
- constraint: string;
290
- updateColumns: string[];
291
- }
292
- interface BoolExpInput {
293
- table: TableMetaIr;
294
- /** Artifact tables record — relationship predicates resolve targets here. */
295
- tables: Record<string, TableMetaIr>;
296
- value: unknown;
297
- maxDepth?: number;
298
- maxNodes?: number;
299
- }
300
- declare function validateBoolExpInput({ table, tables, value, maxDepth, maxNodes }: BoolExpInput): DynamicInputResult<NormalizedBoolExp>;
301
- declare function validateOrderByInput({ table, tables, value, }: {
302
- table: TableMetaIr;
303
- tables: Record<string, TableMetaIr>;
304
- value: unknown;
305
- }): DynamicInputResult<NormalizedOrderBy[]>;
306
- declare function validateSelectColumns({ table, value }: {
307
- table: TableMetaIr;
308
- value: unknown;
309
- }): DynamicInputResult<string[]>;
310
- declare function validateInsertInput({ table, value, list, maxRows, }: {
311
- table: TableMetaIr;
312
- value: unknown;
313
- /** true for `$objects: [FooInsertInput!]`, false for `$object: FooInsertInput`. */
314
- list: boolean;
315
- maxRows?: number;
316
- }): DynamicInputResult<NormalizedRow[]>;
317
- declare function validateSetInput({ table, value }: {
318
- table: TableMetaIr;
319
- value: unknown;
320
- }): DynamicInputResult<NormalizedRow>;
321
- /** _append targets jsonb columns; values are arbitrary JSON (no scalar check). */
322
- declare function validateAppendInput({ table, value }: {
323
- table: TableMetaIr;
324
- value: unknown;
325
- }): DynamicInputResult<NormalizedRow>;
326
- declare function validateOnConflictInput({ table, value, }: {
327
- table: TableMetaIr;
328
- value: unknown;
329
- }): DynamicInputResult<NormalizedOnConflict>;
330
-
331
265
  /**
332
266
  * Flatten pass — inline every fragment spread (and inline fragment) so the
333
267
  * lowering pass sees one plain selection tree. The bios corpus uses flat,
@@ -420,6 +354,14 @@ declare class OperationLowerer {
420
354
  /** byPk-style pk arguments: one argument per primary-key column, exactly. */
421
355
  private lowerPkArgs;
422
356
  private lowerMutationRoot;
357
+ /**
358
+ * Copy-on-write roots: flat args — the pk plus (override only) every
359
+ * declared set column. Overrides are full snapshots of the set columns, so
360
+ * every set argument must be supplied explicitly (pass null to clear a
361
+ * nullable column); the executor generates the copy/update/delete SQL from
362
+ * the structured fields, never from authored statements.
363
+ */
364
+ private lowerCowRoot;
423
365
  private lowerMutationResponse;
424
366
  private lowerInsertObjects;
425
367
  private lowerInsertRow;
@@ -444,138 +386,4 @@ declare function predContainsExists(pred: PredIr): boolean;
444
386
  /** Structural containment: does `haystack` carry `needle` as a subtree? */
445
387
  declare function predContains(haystack: PredIr, needle: PredIr): boolean;
446
388
 
447
- declare const POLICY_COMPARE_OPS: readonly ["=", "!=", "<", "<=", ">", ">="];
448
- type PolicyCompareOp = (typeof POLICY_COMPARE_OPS)[number];
449
- type PolicyOperand =
450
- /** A column reference, or a dotted to-one path ending in a column (`a.b.c`). */
451
- {
452
- kind: 'path';
453
- segments: readonly string[];
454
- }
455
- /** `claim('sub')` / `claim('org')` — the only claim() keys in CLAIMS_CONTRACT. */
456
- | {
457
- kind: 'claim';
458
- key: ClaimKey;
459
- } | {
460
- kind: 'literal';
461
- value: string | number | boolean | null;
462
- };
463
- type PolicyNode = {
464
- kind: 'and';
465
- operands: readonly PolicyNode[];
466
- } | {
467
- kind: 'or';
468
- operands: readonly PolicyNode[];
469
- } | {
470
- kind: 'not';
471
- operand: PolicyNode;
472
- } | {
473
- kind: 'compare';
474
- op: PolicyCompareOp;
475
- left: PolicyOperand;
476
- right: PolicyOperand;
477
- }
478
- /** Boolean claims leaves — pre-resolved against the caller's claims at runtime. */
479
- | {
480
- kind: 'capability';
481
- key: string;
482
- } | {
483
- kind: 'role';
484
- key: string;
485
- }
486
- /** `exists(<link-path>, <pred>)` — the inner predicate runs against the final target. */
487
- | {
488
- kind: 'exists';
489
- path: readonly string[];
490
- where: PolicyNode;
491
- };
492
- interface ParsedPolicy {
493
- readonly source: string;
494
- readonly ast: PolicyNode;
495
- }
496
- declare function walkPolicy(node: PolicyNode, visit: (node: PolicyNode) => void): void;
497
-
498
- /** Parse-time failure — bad token stream, malformed call, invalid claim key. */
499
- declare class PolicyParseError extends Error {
500
- readonly position: number;
501
- readonly name = "PolicyParseError";
502
- constructor(message: string, position: number);
503
- }
504
- type PolicyCompileErrorCode = 'unknown-table' | 'unknown-column' | 'unknown-link' | 'not-to-one' | 'link-depth-exceeded' | 'unsupported-comparison' | 'invalid-null-comparison' | 'when-not-claims-only';
505
- /**
506
- * Compile-time failure — the parsed policy references something the table
507
- * doesn't declare, or uses a shape the v2.0 IR cannot represent. Carries
508
- * `candidates` so the error can name what IS available.
509
- */
510
- declare class PolicyCompileError extends Error {
511
- readonly code: PolicyCompileErrorCode;
512
- readonly candidates: readonly string[];
513
- readonly name = "PolicyCompileError";
514
- constructor(message: string, code: PolicyCompileErrorCode, candidates?: readonly string[]);
515
- }
516
-
517
- declare function parsePolicy(source: string): ParsedPolicy;
518
-
519
- /**
520
- * Policy DSL v2 → PredIr compiler. Resolves column/link references against a
521
- * table resolver (TableMetaIr satisfies the shapes structurally), normalizes
522
- * everything to LOGICAL column names, and enforces the v2.0 representability
523
- * rules the frozen IR imposes:
524
- *
525
- * - dotted to-one paths (`deal.org = claim('org')`) lower to nested
526
- * `exists(link, …)` with the comparison innermost;
527
- * - total link-traversal depth (dotted hops + exists nesting) ≤ 3;
528
- * - a comparison must reference exactly ONE column side (column↔column and
529
- * claims↔literal comparisons have no PredIr shape in v2.0);
530
- * - `col = null` / `col != null` normalize to the isNull operator;
531
- * - variant `when` guards are claims-only: capability()/role() under
532
- * and/or/not. (claim() comparisons in `when` are not representable in the
533
- * v2.0 IR — a targeted error says so.)
534
- */
535
-
536
- declare const POLICY_MAX_LINK_DEPTH = 3;
537
- interface PolicyColumnInfo {
538
- readonly name: string;
539
- readonly columnName: string;
540
- }
541
- interface PolicyLinkInfo {
542
- readonly name: string;
543
- readonly kind: 'toOne' | 'toMany' | 'toPlatformUser';
544
- readonly target: string;
545
- }
546
- interface PolicyTableInfo {
547
- readonly columns: readonly PolicyColumnInfo[];
548
- readonly links: readonly PolicyLinkInfo[];
549
- }
550
- /** `{ tables }` keyed by table name — TableMetaIr's record is assignable. */
551
- interface PolicyResolver {
552
- readonly tables: Record<string, PolicyTableInfo>;
553
- }
554
- interface CompilePredicateInput {
555
- /** DSL source text, or an already-parsed policy. */
556
- expression: string | ParsedPolicy;
557
- table: string;
558
- resolver: PolicyResolver;
559
- maxLinkDepth?: number;
560
- }
561
- declare function compilePredicateV2({ expression, table, resolver, maxLinkDepth }: CompilePredicateInput): PredIr;
562
- /** Variant `when` guards may only test claims: capability()/role() under and/or/not. */
563
- declare function assertClaimsOnlyWhen(parsed: ParsedPolicy): void;
564
- interface CompilePolicyInput {
565
- expression: PolicyExpression;
566
- table: string;
567
- resolver: PolicyResolver;
568
- maxLinkDepth?: number;
569
- }
570
- /**
571
- * Policy expression (string or `{default, variants}`) → one PredIr under §4c
572
- * permissive-union semantics:
573
- *
574
- * OR(default, …variants.map(v => AND(when, v.allow ? const(true) : policy)))
575
- *
576
- * Granting a role/capability only ever widens access; `allow: true`
577
- * short-circuits its branch to the guard alone.
578
- */
579
- declare function compilePolicy({ expression, table, resolver, maxLinkDepth }: CompilePolicyInput): PredIr;
580
-
581
- export { type BuildContextResult, COMPILER_MAJOR, CONST_TRUE, type ClientManifest, type ClientManifestOperation, type CompileContext, type CompileNamespaceInput, type CompileNamespaceResult, type CompilePolicyInput, type CompilePredicateInput, type CompilerDiagnostic, DEFAULT_LIMIT, type DiagnosticSeverity, DocumentCompileError, type DynamicInputIssue, type DynamicInputResult, MAX_LIMIT, type MutationOp, type MutationRootInfo, NamespaceCompileError, type NormalizedBoolExp, type NormalizedOnConflict, type NormalizedOrderBy, type NormalizedRow, OperationLowerer, PLATFORM_USER_TABLE, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, type ParseDocumentsResult, type ParsedDocument, type ParsedPolicy, type PinnedColumn, type PolicyColumnInfo, type PolicyCompareOp, PolicyCompileError, type PolicyCompileErrorCode, type PolicyLinkInfo, type PolicyNode, type PolicyOperand, PolicyParseError, type PolicyResolver, type PolicyTableInfo, type QueryRootInfo, type RestrictedOperation, type SourceDocument, andPred, assertClaimsOnlyWhen, buildCompileContext, canonicalOperationText, classifyInputType, collectPinnedColumns, compileNamespace, compileNamespaceOrThrow, compilePolicy, compilePredicateV2, computeOpHash, computeOpsHash, computePinnedColumnsByTable, computeSchemaHash, flattenOperation, injectPolicies, inputTypeName, lowerOperation, mutationRootNames, parseDocuments, parsePolicy, parseSdl, platformUserMeta, predContains, predContainsExists, queryRootNames, restrictOperation, typeNameForTable, validateAppendInput, validateBoolExpInput, validateInsertInput, validateOnConflictInput, validateOrderByInput, validateSelectColumns, validateSetInput, walkPolicy, walkPred };
389
+ export { type BuildContextResult, COMPILER_MAJOR, CONST_TRUE, type ClientManifest, type ClientManifestOperation, type CompileContext, type CompileNamespaceInput, type CompileNamespaceResult, type CompilerDiagnostic, DEFAULT_LIMIT, type DiagnosticSeverity, DocumentCompileError, MAX_LIMIT, type MutationOp, type MutationRootInfo, NamespaceCompileError, OperationLowerer, PLATFORM_USER_TABLE, type ParseDocumentsResult, type ParsedDocument, type PinnedColumn, type QueryRootInfo, type RestrictedOperation, type SourceDocument, andPred, buildCompileContext, canonicalOperationText, classifyInputType, collectPinnedColumns, compileNamespace, compileNamespaceOrThrow, computeOpHash, computeOpsHash, computePinnedColumnsByTable, computeSchemaHash, flattenOperation, injectPolicies, inputTypeName, lowerOperation, mutationRootNames, parseDocuments, parseSdl, platformUserMeta, predContains, predContainsExists, queryRootNames, restrictOperation, typeNameForTable, walkPred };
@@ -1,6 +1,8 @@
1
- import { CanonicalEnum, CanonicalDefinition, PolicyExpression } from './canonical.js';
2
- import { ClaimKey, PredIr, RootIr, InputRefKind, TableMetaIr, CompiledOperation, CompiledArtifact, CmpOp, VariableIr, OrderIr, SelectionIr } from './ir.js';
1
+ import { CanonicalEnum, CanonicalDefinition } from './canonical.js';
2
+ import { ClaimKey, PredIr, RootIr, InputRefKind, TableMetaIr, CompiledOperation, CompiledArtifact, VariableIr, OrderIr, SelectionIr } from './ir.js';
3
3
  import { DocumentNode, OperationDefinitionNode, FragmentDefinitionNode, GraphQLSchema, ValueNode, SelectionSetNode } from 'graphql';
4
+ export { DynamicInputIssue, DynamicInputResult, NormalizedBoolExp, NormalizedOnConflict, NormalizedOrderBy, NormalizedRow, ORDER_BY_DIRECTIONS, ScalarKind, allowedBoolExpOperators, allowedOps, validateAppendInput, validateBoolExpInput, validateInsertInput, validateOnConflictInput, validateOrderByInput, validateSelectColumns, validateSetInput } from './dynamic-input.js';
5
+ export { CompilePolicyInput, CompilePredicateInput, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, ParsedPolicy, PolicyColumnInfo, PolicyCompareOp, PolicyCompileError, PolicyCompileErrorCode, PolicyLinkInfo, PolicyNode, PolicyOperand, PolicyParseError, PolicyResolver, PolicyTableInfo, assertClaimsOnlyWhen, compilePolicy, compilePredicateV2, parsePolicy, walkPolicy } from './predicate-v2.js';
4
6
  export { P as PLATFORM_USER_TYPENAME, c as camelCase, e as enumTypeName, p as pascalCase } from './naming-CTvWSRTf.js';
5
7
  import 'zod';
6
8
 
@@ -133,10 +135,28 @@ interface QueryRootInfo {
133
135
  kind: 'select' | 'byPk' | 'aggregate';
134
136
  table: string;
135
137
  }
136
- interface MutationRootInfo {
138
+ interface CrudMutationRootInfo {
137
139
  op: MutationOp;
138
140
  table: string;
139
141
  }
142
+ /**
143
+ * A declared copy-on-write mutation root (canonical `cowMutations`). Carries
144
+ * everything lowering needs so the executor can generate the SQL — no
145
+ * authored statements anywhere in the pipeline.
146
+ */
147
+ interface CowMutationRootInfo {
148
+ op: 'cowOverride' | 'cowRevert';
149
+ table: string;
150
+ /** Logical synced twin table (same namespace). */
151
+ synced: string;
152
+ /** Shared single-column primary-key property. */
153
+ pk: string;
154
+ /** Override: overlay properties written by the UPDATE. */
155
+ set: readonly string[];
156
+ /** Override: properties copied INSERT…SELECT from synced (pk included). */
157
+ copyColumns: readonly string[];
158
+ }
159
+ type MutationRootInfo = CrudMutationRootInfo | CowMutationRootInfo;
140
160
  interface CompileContext {
141
161
  namespace: string;
142
162
  tables: Record<string, TableMetaIr>;
@@ -147,9 +167,14 @@ interface CompileContext {
147
167
  /** GraphQL enum type name → canonical enum (SelectColumn enums are NOT here). */
148
168
  enumsByTypeName: Map<string, CanonicalEnum>;
149
169
  readPolicies: Map<string, PredIr>;
170
+ /** Legacy combined write policy (mutation row filters when insert/update are absent). */
150
171
  writePolicies: Map<string, PredIr>;
151
- /** Per-table `col = claim(k)` write-policy pins (insert-merged, non-insertable). */
172
+ insertPolicies: Map<string, PredIr>;
173
+ updatePolicies: Map<string, PredIr>;
174
+ /** Per-table `col = claim(k)` insert-policy pins (insert-merged, non-insertable). */
152
175
  pins: Map<string, PinnedColumn[]>;
176
+ /** Tables with both `insert` and `update` declared (no legacy `write`-only path). */
177
+ splitWritePolicyTables: ReadonlySet<string>;
153
178
  }
154
179
  /**
155
180
  * §4b curated platform-users view — synthesized, never consumer-defined.
@@ -202,7 +227,7 @@ declare function parseDocuments({ schema, documents, }: {
202
227
  declare function computeSchemaHash(canonical: CanonicalDefinition): string;
203
228
  interface ClientManifestOperation {
204
229
  opHash: string;
205
- kind: 'query' | 'mutation' | 'action';
230
+ kind: 'query' | 'mutation';
206
231
  requires: CompiledOperation['requires'];
207
232
  }
208
233
  /** What codegen/the client transport needs: name → hash mapping + set identity. */
@@ -237,97 +262,6 @@ declare function compileNamespaceOrThrow(input: CompileNamespaceInput): {
237
262
  /** Per-table `col = claim(k)` write-policy pins — exposed for SDL generation options. */
238
263
  declare function computePinnedColumnsByTable(canonical: CanonicalDefinition): Record<string, PinnedColumn[]>;
239
264
 
240
- /**
241
- * §4f dynamic-input validators — PURE, data-only functions the data plane
242
- * imports to check client-supplied values for dynamic slots (BoolExp /
243
- * OrderBy / SelectColumn / InsertInput / SetInput / AppendInput / OnConflict)
244
- * against the artifact's per-table whitelist metadata (TableMetaIr).
245
- *
246
- * No drizzle imports, no IO. Each validator returns a normalized tree or
247
- * typed issues; the executor's runtime lowering step consumes the normalized
248
- * form and ANDs the result with the baked policy predicate — the policy is
249
- * non-negotiable regardless of what the client sends.
250
- */
251
-
252
- interface DynamicInputIssue {
253
- code: 'invalid-shape' | 'unknown-column' | 'unknown-link' | 'unknown-operator' | 'invalid-value' | 'column-not-allowed' | 'nested-insert' | 'unknown-constraint' | 'too-deep' | 'too-many-nodes' | 'too-many-rows';
254
- path: string;
255
- message: string;
256
- }
257
- type DynamicInputResult<T> = {
258
- ok: true;
259
- value: T;
260
- } | {
261
- ok: false;
262
- issues: DynamicInputIssue[];
263
- };
264
- type NormalizedBoolExp = {
265
- kind: 'and' | 'or';
266
- operands: NormalizedBoolExp[];
267
- } | {
268
- kind: 'not';
269
- operand: NormalizedBoolExp;
270
- } | {
271
- kind: 'cmp';
272
- op: CmpOp;
273
- column: string;
274
- value: unknown;
275
- } | {
276
- kind: 'exists';
277
- link: string;
278
- target: string;
279
- where: NormalizedBoolExp;
280
- };
281
- interface NormalizedOrderBy {
282
- column: string;
283
- link?: string;
284
- direction: 'asc' | 'desc';
285
- nulls?: 'first' | 'last';
286
- }
287
- type NormalizedRow = Record<string, unknown>;
288
- interface NormalizedOnConflict {
289
- constraint: string;
290
- updateColumns: string[];
291
- }
292
- interface BoolExpInput {
293
- table: TableMetaIr;
294
- /** Artifact tables record — relationship predicates resolve targets here. */
295
- tables: Record<string, TableMetaIr>;
296
- value: unknown;
297
- maxDepth?: number;
298
- maxNodes?: number;
299
- }
300
- declare function validateBoolExpInput({ table, tables, value, maxDepth, maxNodes }: BoolExpInput): DynamicInputResult<NormalizedBoolExp>;
301
- declare function validateOrderByInput({ table, tables, value, }: {
302
- table: TableMetaIr;
303
- tables: Record<string, TableMetaIr>;
304
- value: unknown;
305
- }): DynamicInputResult<NormalizedOrderBy[]>;
306
- declare function validateSelectColumns({ table, value }: {
307
- table: TableMetaIr;
308
- value: unknown;
309
- }): DynamicInputResult<string[]>;
310
- declare function validateInsertInput({ table, value, list, maxRows, }: {
311
- table: TableMetaIr;
312
- value: unknown;
313
- /** true for `$objects: [FooInsertInput!]`, false for `$object: FooInsertInput`. */
314
- list: boolean;
315
- maxRows?: number;
316
- }): DynamicInputResult<NormalizedRow[]>;
317
- declare function validateSetInput({ table, value }: {
318
- table: TableMetaIr;
319
- value: unknown;
320
- }): DynamicInputResult<NormalizedRow>;
321
- /** _append targets jsonb columns; values are arbitrary JSON (no scalar check). */
322
- declare function validateAppendInput({ table, value }: {
323
- table: TableMetaIr;
324
- value: unknown;
325
- }): DynamicInputResult<NormalizedRow>;
326
- declare function validateOnConflictInput({ table, value, }: {
327
- table: TableMetaIr;
328
- value: unknown;
329
- }): DynamicInputResult<NormalizedOnConflict>;
330
-
331
265
  /**
332
266
  * Flatten pass — inline every fragment spread (and inline fragment) so the
333
267
  * lowering pass sees one plain selection tree. The bios corpus uses flat,
@@ -420,6 +354,14 @@ declare class OperationLowerer {
420
354
  /** byPk-style pk arguments: one argument per primary-key column, exactly. */
421
355
  private lowerPkArgs;
422
356
  private lowerMutationRoot;
357
+ /**
358
+ * Copy-on-write roots: flat args — the pk plus (override only) every
359
+ * declared set column. Overrides are full snapshots of the set columns, so
360
+ * every set argument must be supplied explicitly (pass null to clear a
361
+ * nullable column); the executor generates the copy/update/delete SQL from
362
+ * the structured fields, never from authored statements.
363
+ */
364
+ private lowerCowRoot;
423
365
  private lowerMutationResponse;
424
366
  private lowerInsertObjects;
425
367
  private lowerInsertRow;
@@ -444,138 +386,4 @@ declare function predContainsExists(pred: PredIr): boolean;
444
386
  /** Structural containment: does `haystack` carry `needle` as a subtree? */
445
387
  declare function predContains(haystack: PredIr, needle: PredIr): boolean;
446
388
 
447
- declare const POLICY_COMPARE_OPS: readonly ["=", "!=", "<", "<=", ">", ">="];
448
- type PolicyCompareOp = (typeof POLICY_COMPARE_OPS)[number];
449
- type PolicyOperand =
450
- /** A column reference, or a dotted to-one path ending in a column (`a.b.c`). */
451
- {
452
- kind: 'path';
453
- segments: readonly string[];
454
- }
455
- /** `claim('sub')` / `claim('org')` — the only claim() keys in CLAIMS_CONTRACT. */
456
- | {
457
- kind: 'claim';
458
- key: ClaimKey;
459
- } | {
460
- kind: 'literal';
461
- value: string | number | boolean | null;
462
- };
463
- type PolicyNode = {
464
- kind: 'and';
465
- operands: readonly PolicyNode[];
466
- } | {
467
- kind: 'or';
468
- operands: readonly PolicyNode[];
469
- } | {
470
- kind: 'not';
471
- operand: PolicyNode;
472
- } | {
473
- kind: 'compare';
474
- op: PolicyCompareOp;
475
- left: PolicyOperand;
476
- right: PolicyOperand;
477
- }
478
- /** Boolean claims leaves — pre-resolved against the caller's claims at runtime. */
479
- | {
480
- kind: 'capability';
481
- key: string;
482
- } | {
483
- kind: 'role';
484
- key: string;
485
- }
486
- /** `exists(<link-path>, <pred>)` — the inner predicate runs against the final target. */
487
- | {
488
- kind: 'exists';
489
- path: readonly string[];
490
- where: PolicyNode;
491
- };
492
- interface ParsedPolicy {
493
- readonly source: string;
494
- readonly ast: PolicyNode;
495
- }
496
- declare function walkPolicy(node: PolicyNode, visit: (node: PolicyNode) => void): void;
497
-
498
- /** Parse-time failure — bad token stream, malformed call, invalid claim key. */
499
- declare class PolicyParseError extends Error {
500
- readonly position: number;
501
- readonly name = "PolicyParseError";
502
- constructor(message: string, position: number);
503
- }
504
- type PolicyCompileErrorCode = 'unknown-table' | 'unknown-column' | 'unknown-link' | 'not-to-one' | 'link-depth-exceeded' | 'unsupported-comparison' | 'invalid-null-comparison' | 'when-not-claims-only';
505
- /**
506
- * Compile-time failure — the parsed policy references something the table
507
- * doesn't declare, or uses a shape the v2.0 IR cannot represent. Carries
508
- * `candidates` so the error can name what IS available.
509
- */
510
- declare class PolicyCompileError extends Error {
511
- readonly code: PolicyCompileErrorCode;
512
- readonly candidates: readonly string[];
513
- readonly name = "PolicyCompileError";
514
- constructor(message: string, code: PolicyCompileErrorCode, candidates?: readonly string[]);
515
- }
516
-
517
- declare function parsePolicy(source: string): ParsedPolicy;
518
-
519
- /**
520
- * Policy DSL v2 → PredIr compiler. Resolves column/link references against a
521
- * table resolver (TableMetaIr satisfies the shapes structurally), normalizes
522
- * everything to LOGICAL column names, and enforces the v2.0 representability
523
- * rules the frozen IR imposes:
524
- *
525
- * - dotted to-one paths (`deal.org = claim('org')`) lower to nested
526
- * `exists(link, …)` with the comparison innermost;
527
- * - total link-traversal depth (dotted hops + exists nesting) ≤ 3;
528
- * - a comparison must reference exactly ONE column side (column↔column and
529
- * claims↔literal comparisons have no PredIr shape in v2.0);
530
- * - `col = null` / `col != null` normalize to the isNull operator;
531
- * - variant `when` guards are claims-only: capability()/role() under
532
- * and/or/not. (claim() comparisons in `when` are not representable in the
533
- * v2.0 IR — a targeted error says so.)
534
- */
535
-
536
- declare const POLICY_MAX_LINK_DEPTH = 3;
537
- interface PolicyColumnInfo {
538
- readonly name: string;
539
- readonly columnName: string;
540
- }
541
- interface PolicyLinkInfo {
542
- readonly name: string;
543
- readonly kind: 'toOne' | 'toMany' | 'toPlatformUser';
544
- readonly target: string;
545
- }
546
- interface PolicyTableInfo {
547
- readonly columns: readonly PolicyColumnInfo[];
548
- readonly links: readonly PolicyLinkInfo[];
549
- }
550
- /** `{ tables }` keyed by table name — TableMetaIr's record is assignable. */
551
- interface PolicyResolver {
552
- readonly tables: Record<string, PolicyTableInfo>;
553
- }
554
- interface CompilePredicateInput {
555
- /** DSL source text, or an already-parsed policy. */
556
- expression: string | ParsedPolicy;
557
- table: string;
558
- resolver: PolicyResolver;
559
- maxLinkDepth?: number;
560
- }
561
- declare function compilePredicateV2({ expression, table, resolver, maxLinkDepth }: CompilePredicateInput): PredIr;
562
- /** Variant `when` guards may only test claims: capability()/role() under and/or/not. */
563
- declare function assertClaimsOnlyWhen(parsed: ParsedPolicy): void;
564
- interface CompilePolicyInput {
565
- expression: PolicyExpression;
566
- table: string;
567
- resolver: PolicyResolver;
568
- maxLinkDepth?: number;
569
- }
570
- /**
571
- * Policy expression (string or `{default, variants}`) → one PredIr under §4c
572
- * permissive-union semantics:
573
- *
574
- * OR(default, …variants.map(v => AND(when, v.allow ? const(true) : policy)))
575
- *
576
- * Granting a role/capability only ever widens access; `allow: true`
577
- * short-circuits its branch to the guard alone.
578
- */
579
- declare function compilePolicy({ expression, table, resolver, maxLinkDepth }: CompilePolicyInput): PredIr;
580
-
581
- export { type BuildContextResult, COMPILER_MAJOR, CONST_TRUE, type ClientManifest, type ClientManifestOperation, type CompileContext, type CompileNamespaceInput, type CompileNamespaceResult, type CompilePolicyInput, type CompilePredicateInput, type CompilerDiagnostic, DEFAULT_LIMIT, type DiagnosticSeverity, DocumentCompileError, type DynamicInputIssue, type DynamicInputResult, MAX_LIMIT, type MutationOp, type MutationRootInfo, NamespaceCompileError, type NormalizedBoolExp, type NormalizedOnConflict, type NormalizedOrderBy, type NormalizedRow, OperationLowerer, PLATFORM_USER_TABLE, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, type ParseDocumentsResult, type ParsedDocument, type ParsedPolicy, type PinnedColumn, type PolicyColumnInfo, type PolicyCompareOp, PolicyCompileError, type PolicyCompileErrorCode, type PolicyLinkInfo, type PolicyNode, type PolicyOperand, PolicyParseError, type PolicyResolver, type PolicyTableInfo, type QueryRootInfo, type RestrictedOperation, type SourceDocument, andPred, assertClaimsOnlyWhen, buildCompileContext, canonicalOperationText, classifyInputType, collectPinnedColumns, compileNamespace, compileNamespaceOrThrow, compilePolicy, compilePredicateV2, computeOpHash, computeOpsHash, computePinnedColumnsByTable, computeSchemaHash, flattenOperation, injectPolicies, inputTypeName, lowerOperation, mutationRootNames, parseDocuments, parsePolicy, parseSdl, platformUserMeta, predContains, predContainsExists, queryRootNames, restrictOperation, typeNameForTable, validateAppendInput, validateBoolExpInput, validateInsertInput, validateOnConflictInput, validateOrderByInput, validateSelectColumns, validateSetInput, walkPolicy, walkPred };
389
+ export { type BuildContextResult, COMPILER_MAJOR, CONST_TRUE, type ClientManifest, type ClientManifestOperation, type CompileContext, type CompileNamespaceInput, type CompileNamespaceResult, type CompilerDiagnostic, DEFAULT_LIMIT, type DiagnosticSeverity, DocumentCompileError, MAX_LIMIT, type MutationOp, type MutationRootInfo, NamespaceCompileError, OperationLowerer, PLATFORM_USER_TABLE, type ParseDocumentsResult, type ParsedDocument, type PinnedColumn, type QueryRootInfo, type RestrictedOperation, type SourceDocument, andPred, buildCompileContext, canonicalOperationText, classifyInputType, collectPinnedColumns, compileNamespace, compileNamespaceOrThrow, computeOpHash, computeOpsHash, computePinnedColumnsByTable, computeSchemaHash, flattenOperation, injectPolicies, inputTypeName, lowerOperation, mutationRootNames, parseDocuments, parseSdl, platformUserMeta, predContains, predContainsExists, queryRootNames, restrictOperation, typeNameForTable, walkPred };