grafeo-ogm 1.12.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +10 -1
  3. package/dist/cjs/cli/commands/db-push.d.ts.map +1 -1
  4. package/dist/cjs/cli/commands/db-push.js +6 -3
  5. package/dist/cjs/cli/commands/db-push.js.map +1 -1
  6. package/dist/cjs/cli/display.d.ts +15 -0
  7. package/dist/cjs/cli/display.d.ts.map +1 -0
  8. package/dist/cjs/cli/display.js +21 -0
  9. package/dist/cjs/cli/display.js.map +1 -0
  10. package/dist/cjs/compilers/mutation.compiler.d.ts +54 -1
  11. package/dist/cjs/compilers/mutation.compiler.d.ts.map +1 -1
  12. package/dist/cjs/compilers/mutation.compiler.js +134 -32
  13. package/dist/cjs/compilers/mutation.compiler.js.map +1 -1
  14. package/dist/cjs/compilers/where.compiler.d.ts.map +1 -1
  15. package/dist/cjs/compilers/where.compiler.js +7 -0
  16. package/dist/cjs/compilers/where.compiler.js.map +1 -1
  17. package/dist/cjs/interface-model.d.ts.map +1 -1
  18. package/dist/cjs/interface-model.js +9 -1
  19. package/dist/cjs/interface-model.js.map +1 -1
  20. package/dist/cjs/model.d.ts.map +1 -1
  21. package/dist/cjs/model.js +12 -3
  22. package/dist/cjs/model.js.map +1 -1
  23. package/dist/cjs/ogm.d.ts.map +1 -1
  24. package/dist/cjs/ogm.js +6 -1
  25. package/dist/cjs/ogm.js.map +1 -1
  26. package/dist/cjs/subgraph/subgraph-operations.d.ts +2 -1
  27. package/dist/cjs/subgraph/subgraph-operations.d.ts.map +1 -1
  28. package/dist/cjs/subgraph/subgraph-operations.js +20 -4
  29. package/dist/cjs/subgraph/subgraph-operations.js.map +1 -1
  30. package/dist/cjs/subgraph/types.d.ts +8 -0
  31. package/dist/cjs/subgraph/types.d.ts.map +1 -1
  32. package/dist/cjs/utils/validation.d.ts +7 -0
  33. package/dist/cjs/utils/validation.d.ts.map +1 -1
  34. package/dist/cjs/utils/validation.js +421 -0
  35. package/dist/cjs/utils/validation.js.map +1 -1
  36. package/dist/esm/cli/commands/db-push.d.ts.map +1 -1
  37. package/dist/esm/cli/commands/db-push.js +6 -3
  38. package/dist/esm/cli/commands/db-push.js.map +1 -1
  39. package/dist/esm/cli/display.d.ts +15 -0
  40. package/dist/esm/cli/display.d.ts.map +1 -0
  41. package/dist/esm/cli/display.js +18 -0
  42. package/dist/esm/cli/display.js.map +1 -0
  43. package/dist/esm/compilers/mutation.compiler.d.ts +54 -1
  44. package/dist/esm/compilers/mutation.compiler.d.ts.map +1 -1
  45. package/dist/esm/compilers/mutation.compiler.js +134 -32
  46. package/dist/esm/compilers/mutation.compiler.js.map +1 -1
  47. package/dist/esm/compilers/where.compiler.d.ts.map +1 -1
  48. package/dist/esm/compilers/where.compiler.js +8 -1
  49. package/dist/esm/compilers/where.compiler.js.map +1 -1
  50. package/dist/esm/interface-model.d.ts.map +1 -1
  51. package/dist/esm/interface-model.js +9 -1
  52. package/dist/esm/interface-model.js.map +1 -1
  53. package/dist/esm/model.d.ts.map +1 -1
  54. package/dist/esm/model.js +12 -3
  55. package/dist/esm/model.js.map +1 -1
  56. package/dist/esm/ogm.d.ts.map +1 -1
  57. package/dist/esm/ogm.js +6 -1
  58. package/dist/esm/ogm.js.map +1 -1
  59. package/dist/esm/subgraph/subgraph-operations.d.ts +2 -1
  60. package/dist/esm/subgraph/subgraph-operations.d.ts.map +1 -1
  61. package/dist/esm/subgraph/subgraph-operations.js +20 -4
  62. package/dist/esm/subgraph/subgraph-operations.js.map +1 -1
  63. package/dist/esm/subgraph/types.d.ts +8 -0
  64. package/dist/esm/subgraph/types.d.ts.map +1 -1
  65. package/dist/esm/utils/validation.d.ts +7 -0
  66. package/dist/esm/utils/validation.d.ts.map +1 -1
  67. package/dist/esm/utils/validation.js +420 -0
  68. package/dist/esm/utils/validation.js.map +1 -1
  69. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.14.0 (2026-07-24) — 🛡️ Security release: NLS enforcement on interface reads & relationship writes, and a `_MATCHES` ReDoS guard
4
+
5
+ > **Three security fixes.** Two are object-level authorization gaps: grafeo's node-level-security (NLS) policies were threaded correctly through the concrete-model read and write paths, but two paths silently skipped the **target type's** policy — nested relationship projections on **interface** reads, and **connect/disconnect** relationship writes — so a caller whose own access was correctly scoped could still read, or link/unlink, related nodes their policy forbids. The third hardens the `_MATCHES` filter operator against server-side ReDoS. If you use `policies` with interface models or nested `connect`/`disconnect`, or expose `_MATCHES` to untrusted input, upgrade.
6
+
7
+ ### 🛡️ Interface reads now apply the target type's `read` policy to nested projections
8
+
9
+ `InterfaceModel.find` (and its `findFirst` / `findUnique` / `*OrThrow` siblings, which all route through it) applied the interface's source-side policy and the WHERE-side traversal policy — but compiled the **RETURN projection** without the read `policyContext` that `Model.find` passes. Every nested relationship pattern comprehension was therefore emitted with **no target-type policy**, so an interface query could project fields of related, policy-protected node types (e.g. another tenant's `author { email }`) that the target type's `read` policy is meant to filter out. The leak was silent and spanned every row the interface query returned.
10
+
11
+ The fix threads the resolved read `policyContext` into the interface selection compile, exactly as the concrete-model path already does, so every nested projection AND-stitches the target type's read policy — including union and connection branches. **When no policy layer is configured the emitted Cypher is byte-identical** to before; the guard engages only when a policy actually resolves for the projected type.
12
+
13
+ ### 🛡️ Nested `connect` / `disconnect` now enforce the target type's `read` policy
14
+
15
+ `MutationCompiler` was policy-unaware: the target `MATCH` emitted for a nested `connect` (MERGE) or `disconnect` selected the target node by the caller's `where` alone, with no policy. A caller operating under a bound `withContext(ctx)` — whose *source* node was correctly policy-filtered — could therefore link or unlink relationships to arbitrary target nodes their policy should forbid (cross-tenant / cross-owner relationship writes):
16
+
17
+ ```typescript
18
+ // `Book` has a read policy scoped to the owner. Previously this linked a
19
+ // foreign Book anyway — the target MATCH carried no Book policy. Now it
20
+ // AND-stitches the Book read policy, so an unreadable target fails to
21
+ // match and the MERGE is a no-op.
22
+ ogm.withContext({ uid }).model('User').update({
23
+ where: { id: myId },
24
+ connect: { ownedBooks: { where: { id: someBookId } } },
25
+ });
26
+ ```
27
+
28
+ The fix threads the resolved policy context into `MutationCompiler` and AND-stitches the target type's `read` policy into every connect/disconnect target `MATCH` — all seven sites (single / array / `UNWIND` connect, specific disconnect, nested-in-update connect and disconnect, union targets), reached from both `update` and `updateMany`. `read` is the correct gate: row-level target visibility is expressed as the `read` policy, while `create`/`update` restrictives are WITH-CHECK predicates over a mutation-input bag that a referenced existing node has none of. **No-policy, bypass (`unsafe.bypassPolicies`), and no-target-policy paths stay byte-identical**; `create` and `upsert` (which never emits a relationship `MATCH`) are untouched. Policy predicates use the mutation's shared, monotonic parameter counter, so they never collide with the caller's `connect`/`disconnect` `where` params.
29
+
30
+ ### 🛡️ `_MATCHES` is now guarded against catastrophic-backtracking regexes (ReDoS)
31
+
32
+ The `_MATCHES` filter operator forwards its value into a Neo4j `=~` predicate, which the server evaluates with Java's **backtracking** regex engine. An attacker able to influence a `where` filter could supply a catastrophic pattern (e.g. `(a+)+$`, `([a-z]+)+$`, `(a?)+$`) and pin shared Neo4j CPU — a server-side ReDoS ([CWE-1333](https://cwe.mitre.org/data/definitions/1333.html)). Parameterization stops injection but not this: the payload *is* the regex.
33
+
34
+ Every `_MATCHES` value is now validated at compile time by a **sound-by-construction** guard. Rather than blocklisting known-bad shapes (always incomplete), it accepts a pattern **only when it can prove the pattern is linear**, and refuses everything it cannot model — alternation, quantified groups, lookaround, backreferences, unsupported escapes. The check is single-pass and bounded, so it cannot itself become a DoS vector, and Java-flavor divergences are modeled soundly (`\v` is the vertical-whitespace class; `\0`/octal escapes are refused; only inline flags that don't change the analysis — `i`/`m`/`s`/`d` — are honored, so `(?x)` COMMENTS mode and `(?u)`/`(?U)` Unicode widening are refused).
35
+
36
+ - **Precision cost (intended, fail-closed).** Some linear-but-unprovable patterns are refused — notably **all alternation** (`(cat|dog)`) and **contains-style** `.*x.*` shapes. Reach for the dedicated, always-safe operators (`_CONTAINS` / `_STARTS_WITH` / `_ENDS_WITH` / `_IN`), simplify the pattern, or disable `_MATCHES` entirely via `features.filters.String.MATCHES` if you must run arbitrary regexes and accept the risk. The refusal error names these options.
37
+ - **Common patterns keep working** — anchors, character classes, single wildcards (`^foo.*bar$`, `[A-Za-z0-9_]+`, `\d{3}-\d{4}`), fenced quantifiers (`[a-z]+@[a-z]+\.[a-z]+`), and inline-flag prefixes (`(?i)…`).
38
+
39
+ ### Tests
40
+
41
+ Interface-read policy: two specs asserting the nested projection now carries the target `read` predicate for interface reads, and that the no-policy path stays byte-identical. Connect/disconnect policy: six specs covering connect and disconnect target MATCHes carrying the target `read` policy, the update-op-not-stitched case, byte-identical no-policy/bypass Cypher, and non-colliding parameter numbering. ReDoS guard: a 100+-case battery covering every known catastrophic family (nested quantifiers, nullable/overlapping alternation under repeat, custom-class and nested-group bases, unrolled adjacent optionals), fail-closed refusal of unmodeled constructs, acceptance of provably-linear patterns, and the three Java-flavor soundness regressions found and closed during adversarial review (`(?x)`, `\v`, `\0`). Full suite green (1629); lint and format clean.
42
+
43
+ ---
44
+
45
+ ## 1.13.0 (2026-07-14) — ✨ `$cloneSubgraph` returns `nodesByLabel`
46
+
47
+ > **First community-requested feature** ([#1](https://github.com/neomodular/grafeo-ogm/issues/1)). After deep-cloning a content subgraph, a caller often needs to post-process only the nodes of a **specific label** (re-normalize, re-stamp, re-index). Until now `nodeMapping` held every cloned id across all labels, forcing a broad-`IN`-plus-label-filter dance on the caller. The clone already visits every node with its labels in hand — so now it just tells you.
48
+
49
+ ### ✨ `nodesByLabel: Map<label, newId[]>` on the clone result
50
+
51
+ - **Additive and backwards-compatible** — `clonedRootId` and `nodeMapping` are unchanged; existing callers are unaffected.
52
+ - **Zero extra round-trips** — `labels(output)` is folded into the existing Step-1 `RETURN` of the APOC clone query.
53
+ - **Multi-label nodes appear under each of their labels**, so `nodesByLabel.get('DoseValue')` is exactly the set you post-process.
54
+ - **Consistent by construction** — `nodesByLabel` is built in the same pass as the final `nodeMapping`, so a node dropped during UUID re-assignment is absent from *both* maps: every id in `nodesByLabel` is also a `nodeMapping` value.
55
+
56
+ ```typescript
57
+ const result = await ogm.$cloneSubgraph(rootId, config, tx);
58
+ const doseValueIds = result.nodesByLabel.get('DoseValue') ?? [];
59
+ // target exactly one label — no over-broad IN list
60
+ ```
61
+
62
+ ### 🛡️ CLI display hardening — `db push` sanitizes live-DB names
63
+
64
+ Names introspected from the live database that fail identifier validation are correctly routed to `unmanaged` and never executed as Cypher — but they were printed **raw**. Neo4j allows arbitrary characters in backtick-quoted identifiers, so a hostile constraint/index name could smuggle ANSI/C0 escape sequences into the developer's terminal (title changes, output spoofing). All live-DB names rendered by `db push` (unmanaged, orphan listings, drop confirmations) now pass through a `safeDisplay()` helper that replaces C0/C1 control characters with a visible `�` placeholder. Cypher execution was never affected — this closes the display path.
65
+
66
+ ### 📝 Docs
67
+
68
+ - Fixed the `cloneSubgraph` README snippet: the result field is `nodeMapping`, not the stale `idMapping`, and the config examples now include the required `maxLevel`.
69
+
70
+ ### Tests
71
+
72
+ Four new subgraph specs (label grouping, root-label → `clonedRootId` linkage, multi-label fan-out, UUID-failure consistency across both maps) plus a CLI spec proving a hostile constraint name lands in `unmanaged`, prints sanitized, and never reaches a `DROP`. Full suite green (1514); lint, format, and type-check clean.
73
+
74
+ ---
75
+
3
76
  ## 1.12.0 (2026-07-01) — 🛡️ `OR: []` now matches nothing (Prisma semantics)
4
77
 
5
78
  > **Safety fix, and the one deliberate compat break with `@neo4j/graphql-ogm`.** An empty logical `OR` array used to vanish from the compiled WHERE clause, so `deleteMany({ where: { OR: [] } })` compiled **byte-identical to no `where` at all**: `MATCH (n:Label) DETACH DELETE n` — a full-label wipe. The realistic trigger is a dynamically built filter (`OR: ids.map((id) => ({ id }))`) receiving an empty list. The deprecated `@neo4j/graphql-ogm` (verified against its final release, 5.11.4) has the same behavior, so grafeo was bug-for-bug compatible. We now diverge on purpose.
package/README.md CHANGED
@@ -943,13 +943,21 @@ const cloneResult = await cloneSubgraph(
943
943
  {
944
944
  ownedLabels: ['Book', 'Chapter', 'Section'],
945
945
  ownedRelationships: ['HAS_CHAPTER', 'HAS_SECTION'],
946
+ maxLevel: 5,
946
947
  referenceRelationships: [
947
948
  { fromLabel: 'Book', relationshipType: 'WRITTEN_BY', direction: 'OUT' },
948
949
  ],
949
950
  },
950
951
  transaction,
951
952
  );
952
- // cloneResult: { clonedRootId, idMapping: Map<original, cloned> }
953
+ // cloneResult: {
954
+ // clonedRootId,
955
+ // nodeMapping: Map<originalId, newId>,
956
+ // nodesByLabel: Map<label, newId[]>, // v1.13.0+ — multi-label nodes appear under each label
957
+ // }
958
+
959
+ // v1.13.0+ — post-process only the nodes of one label, no broad-IN filtering:
960
+ const chapterIds = cloneResult.nodesByLabel.get('Chapter') ?? [];
953
961
 
954
962
  // Delete a subgraph
955
963
  const deleteResult = await deleteSubgraph(
@@ -957,6 +965,7 @@ const deleteResult = await deleteSubgraph(
957
965
  {
958
966
  ownedLabels: ['Book', 'Chapter'],
959
967
  ownedRelationships: ['HAS_CHAPTER'],
968
+ maxLevel: 5,
960
969
  referenceRelationships: [],
961
970
  },
962
971
  transaction,
@@ -1 +1 @@
1
- {"version":3,"file":"db-push.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AA+ItC,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAgE1E"}
1
+ {"version":3,"file":"db-push.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAkJtC,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAgE1E"}
@@ -38,6 +38,7 @@ const fs = __importStar(require("node:fs"));
38
38
  const node_util_1 = require("node:util");
39
39
  const parser_1 = require("../../schema/parser");
40
40
  const config_1 = require("../config");
41
+ const display_1 = require("../display");
41
42
  const driver_1 = require("../driver");
42
43
  const errors_1 = require("../errors");
43
44
  const introspect_1 = require("../introspect");
@@ -98,10 +99,12 @@ function renderPlan(plan, io, willDrop) {
98
99
  else {
99
100
  io.out(`Orphans — ${plan.orphans.length} kept (use --force-drop to remove):`);
100
101
  for (const orphan of plan.orphans)
101
- io.out(` - ${orphan.name}`);
102
+ io.out(` - ${(0, display_1.safeDisplay)(orphan.name)}`);
102
103
  }
104
+ // v1.13.0 — unmanaged names come from live introspection and are exactly
105
+ // the ones that FAILED identifier validation: sanitize before printing.
103
106
  if (plan.unmanaged.length > 0)
104
- io.out(`Unmanaged — ${plan.unmanaged.length} ignored: ${plan.unmanaged.join(', ')}`);
107
+ io.out(`Unmanaged — ${plan.unmanaged.length} ignored: ${plan.unmanaged.map(display_1.safeDisplay).join(', ')}`);
105
108
  }
106
109
  async function resolveDropConsent(plan, io, yes) {
107
110
  if (yes)
@@ -135,7 +138,7 @@ async function applyDrops(driver, database, plan, io) {
135
138
  try {
136
139
  for (const orphan of plan.orphans) {
137
140
  await session.run(orphan.dropCypher);
138
- io.out(`✓ dropped ${orphan.name}`);
141
+ io.out(`✓ dropped ${(0, display_1.safeDisplay)(orphan.name)}`);
139
142
  }
140
143
  }
141
144
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"db-push.js","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"db-push.js","sourceRoot":"","sources":["../../../../src/cli/commands/db-push.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Display hygiene for strings sourced from LIVE database introspection.
3
+ *
4
+ * v1.13.0 — names failing `isSafeIdentifier` are correctly routed to
5
+ * `unmanaged` and never executed as Cypher, but they were printed raw. A
6
+ * hostile constraint/index name (Neo4j allows arbitrary characters in
7
+ * backtick-quoted identifiers) could smuggle ANSI/C0 escapes into the
8
+ * developer's terminal — title changes, output spoofing/hiding. The
9
+ * identifier validation that blocks Cypher injection does not cover the
10
+ * display path, so any live-DB string reaching `io.out`/`io.err` must pass
11
+ * through here first.
12
+ */
13
+ /** Replaces C0/C1 control characters with a visible placeholder (U+FFFD). */
14
+ export declare function safeDisplay(value: string): string;
15
+ //# sourceMappingURL=display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../../src/cli/display.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Display hygiene for strings sourced from LIVE database introspection.
4
+ *
5
+ * v1.13.0 — names failing `isSafeIdentifier` are correctly routed to
6
+ * `unmanaged` and never executed as Cypher, but they were printed raw. A
7
+ * hostile constraint/index name (Neo4j allows arbitrary characters in
8
+ * backtick-quoted identifiers) could smuggle ANSI/C0 escapes into the
9
+ * developer's terminal — title changes, output spoofing/hiding. The
10
+ * identifier validation that blocks Cypher injection does not cover the
11
+ * display path, so any live-DB string reaching `io.out`/`io.err` must pass
12
+ * through here first.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.safeDisplay = safeDisplay;
16
+ const CONTROL_CHARS = new RegExp('[\\u0000-\\u001F\\u007F-\\u009F]', 'g');
17
+ /** Replaces C0/C1 control characters with a visible placeholder (U+FFFD). */
18
+ function safeDisplay(value) {
19
+ return value.replace(CONTROL_CHARS, '�');
20
+ }
21
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../../../src/cli/display.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;AAKH,kCAEC;AALD,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;AAE1E,6EAA6E;AAC7E,SAAgB,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;AAC3C,CAAC"}
@@ -1,5 +1,7 @@
1
1
  import type { OGMLogger } from '../execution/executor';
2
+ import type { PolicyContextBundle } from '../policy/types';
2
3
  import { NodeDefinition, SchemaMetadata } from '../schema/types';
4
+ import { WhereCompiler } from './where.compiler';
3
5
  export interface MutationResult {
4
6
  cypher: string;
5
7
  params: Record<string, unknown>;
@@ -15,9 +17,44 @@ export declare class MutationCompiler {
15
17
  */
16
18
  private labelCache;
17
19
  private logger?;
20
+ /**
21
+ * WhereCompiler used ONLY to compile a relationship TARGET type's
22
+ * `read` policy predicate for connect/disconnect target MATCHes,
23
+ * mirroring the read paths (`WhereCompiler`/`SelectionCompiler`).
24
+ * Injected by the OGM so it shares the user's compiler options;
25
+ * lazily constructed with default options otherwise.
26
+ */
27
+ private policyWhereCompiler?;
18
28
  constructor(schema: SchemaMetadata, options?: {
19
29
  logger?: OGMLogger;
30
+ whereCompiler?: WhereCompiler;
20
31
  });
32
+ /**
33
+ * Resolve and compile the TARGET type's `read` policy predicate for a
34
+ * connect/disconnect target MATCH, mirroring the read path
35
+ * (`WhereCompiler.buildTargetBundle` + `WhereCompiler.compile`). You
36
+ * must be allowed to SEE a node to link/unlink it, so linking to an
37
+ * unreadable node is the IDOR this closes; the codebase models the
38
+ * row-level write gate for `update`/`delete` targets as `read`
39
+ * ReadRestrictive policies (see policy/types.ts), so `read` is both
40
+ * necessary and the semantically correct operation here.
41
+ *
42
+ * Returns `null` — leaving the emitted Cypher BYTE-IDENTICAL — when:
43
+ * - no policy context is threaded (no policy bound / bypass active), OR
44
+ * - no `paramCounter` is available to allocate policy params, OR
45
+ * - the target type has no policy applicable to `read`, OR
46
+ * - the resolved policy is `overridden` (compiles to nothing).
47
+ *
48
+ * When a target policy resolves, the compiled predicate is returned and
49
+ * its bound params are merged into `params`. Policy params use the
50
+ * shared `paramCounter` (`param<N>`), continuing the sequence started by
51
+ * the top-level WHERE, so they can never collide with the
52
+ * connect/disconnect `where` params (prefix-named, e.g.
53
+ * `connect_<field>_<prop>`) or the selection's params (allocated later
54
+ * from the same counter).
55
+ */
56
+ private buildTargetPolicyPredicate;
57
+ private getPolicyWhereCompiler;
21
58
  /**
22
59
  * Surface a logical operator that contributed zero effective conditions.
23
60
  * Mirrors WhereCompiler.warnEmptyLogical — fires only on the anomalous
@@ -39,7 +76,23 @@ export declare class MutationCompiler {
39
76
  cypher: string;
40
77
  params: Record<string, unknown>;
41
78
  preludes?: string[];
42
- }, labels?: string[], returnMode?: 'node' | 'count'): MutationResult;
79
+ }, labels?: string[], returnMode?: 'node' | 'count',
80
+ /**
81
+ * The caller's resolved policy bundle for this mutation (the SOURCE
82
+ * type's `update` bundle). Its `resolveForType` is used to resolve
83
+ * each connect/disconnect TARGET type's `read` policy. `undefined`
84
+ * when no policy is bound or a bypass is active — in which case the
85
+ * emitted Cypher is byte-identical to before this enforcement.
86
+ */
87
+ policyContext?: PolicyContextBundle,
88
+ /**
89
+ * Shared `param<N>` counter, continued from the top-level WHERE
90
+ * compile so target-policy params never collide with connect/
91
+ * disconnect `where` params or the selection's params.
92
+ */
93
+ paramCounter?: {
94
+ count: number;
95
+ }): MutationResult;
43
96
  /**
44
97
  * Generate DELETE Cypher with optional cascade.
45
98
  */
@@ -1 +1 @@
1
- {"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mutation.compiler.d.ts","sourceRoot":"","sources":["../../../src/compilers/mutation.compiler.ts"],"names":[],"mappings":"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"}