@nicia-ai/typegraph 0.55.0 → 0.56.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 (148) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/backend/index.cjs +86 -86
  3. package/dist/backend/index.js +7 -7
  4. package/dist/backend/postgres/index.cjs +22 -22
  5. package/dist/backend/postgres/index.js +8 -8
  6. package/dist/backend/postgres/pglite-store.cjs +1 -1
  7. package/dist/backend/postgres/pglite-store.d.cts +2 -2
  8. package/dist/backend/postgres/pglite-store.d.ts +2 -2
  9. package/dist/backend/postgres/pglite-store.js +1 -1
  10. package/dist/backend/postgres/pglite.cjs +10 -10
  11. package/dist/backend/postgres/pglite.js +9 -9
  12. package/dist/backend/sqlite/index.cjs +21 -21
  13. package/dist/backend/sqlite/index.js +8 -8
  14. package/dist/backend/sqlite/libsql.cjs +12 -12
  15. package/dist/backend/sqlite/libsql.js +8 -8
  16. package/dist/backend/sqlite/local-store.cjs +1 -1
  17. package/dist/backend/sqlite/local-store.d.cts +2 -2
  18. package/dist/backend/sqlite/local-store.d.ts +2 -2
  19. package/dist/backend/sqlite/local-store.js +1 -1
  20. package/dist/backend/sqlite/local.cjs +10 -10
  21. package/dist/backend/sqlite/local.js +9 -9
  22. package/dist/{chunk-S5WG5AFG.cjs → chunk-2XUAUSMI.cjs} +12 -12
  23. package/dist/{chunk-S5WG5AFG.cjs.map → chunk-2XUAUSMI.cjs.map} +1 -1
  24. package/dist/{chunk-MTE255N3.cjs → chunk-36XLQHZA.cjs} +4 -4
  25. package/dist/{chunk-MTE255N3.cjs.map → chunk-36XLQHZA.cjs.map} +1 -1
  26. package/dist/{chunk-FWSGKOBN.js → chunk-6LTRZOUU.js} +6 -6
  27. package/dist/{chunk-FWSGKOBN.js.map → chunk-6LTRZOUU.js.map} +1 -1
  28. package/dist/{chunk-YVKPUSHS.js → chunk-75KH6Y2W.js} +16 -7
  29. package/dist/chunk-75KH6Y2W.js.map +1 -0
  30. package/dist/{chunk-MJXEO7YA.js → chunk-762VPGHN.js} +5 -5
  31. package/dist/{chunk-MJXEO7YA.js.map → chunk-762VPGHN.js.map} +1 -1
  32. package/dist/{chunk-GGDTMBNA.cjs → chunk-7CCVR2QF.cjs} +54 -54
  33. package/dist/{chunk-GGDTMBNA.cjs.map → chunk-7CCVR2QF.cjs.map} +1 -1
  34. package/dist/{chunk-7EOJO6QB.js → chunk-7MHENVRG.js} +3 -3
  35. package/dist/{chunk-7EOJO6QB.js.map → chunk-7MHENVRG.js.map} +1 -1
  36. package/dist/{chunk-7B3DSFX3.cjs → chunk-AUTRK6WM.cjs} +4 -4
  37. package/dist/{chunk-7B3DSFX3.cjs.map → chunk-AUTRK6WM.cjs.map} +1 -1
  38. package/dist/{chunk-SIQ4BFL5.js → chunk-AZP5CCHL.js} +4 -4
  39. package/dist/{chunk-SIQ4BFL5.js.map → chunk-AZP5CCHL.js.map} +1 -1
  40. package/dist/{chunk-WTW7RWAG.cjs → chunk-BYUIOM4L.cjs} +6 -6
  41. package/dist/{chunk-WTW7RWAG.cjs.map → chunk-BYUIOM4L.cjs.map} +1 -1
  42. package/dist/{chunk-74FNI3PT.js → chunk-C3TJU4KQ.js} +6 -6
  43. package/dist/chunk-C3TJU4KQ.js.map +1 -0
  44. package/dist/{chunk-7V2R4MH6.js → chunk-CEQOTZGB.js} +5 -5
  45. package/dist/{chunk-7V2R4MH6.js.map → chunk-CEQOTZGB.js.map} +1 -1
  46. package/dist/{chunk-TKFQLKH2.cjs → chunk-CYKHSH5O.cjs} +36 -36
  47. package/dist/{chunk-TKFQLKH2.cjs.map → chunk-CYKHSH5O.cjs.map} +1 -1
  48. package/dist/{chunk-D5TCKAQT.cjs → chunk-DGIA64DM.cjs} +4 -4
  49. package/dist/{chunk-D5TCKAQT.cjs.map → chunk-DGIA64DM.cjs.map} +1 -1
  50. package/dist/{chunk-FFR3YUY2.js → chunk-E4QYEWVH.js} +5 -5
  51. package/dist/{chunk-FFR3YUY2.js.map → chunk-E4QYEWVH.js.map} +1 -1
  52. package/dist/{chunk-467YITD4.cjs → chunk-ETU5IILQ.cjs} +13 -13
  53. package/dist/{chunk-467YITD4.cjs.map → chunk-ETU5IILQ.cjs.map} +1 -1
  54. package/dist/{chunk-HW3IX2RF.js → chunk-EWRLWI7W.js} +4 -4
  55. package/dist/{chunk-HW3IX2RF.js.map → chunk-EWRLWI7W.js.map} +1 -1
  56. package/dist/{chunk-KZ6OHFDV.js → chunk-F2S5JWCT.js} +3 -3
  57. package/dist/{chunk-KZ6OHFDV.js.map → chunk-F2S5JWCT.js.map} +1 -1
  58. package/dist/{chunk-45WPPI64.js → chunk-FMCPKMQI.js} +3 -3
  59. package/dist/{chunk-45WPPI64.js.map → chunk-FMCPKMQI.js.map} +1 -1
  60. package/dist/{chunk-QM6IQW7B.js → chunk-ILHVYKXJ.js} +7 -7
  61. package/dist/{chunk-QM6IQW7B.js.map → chunk-ILHVYKXJ.js.map} +1 -1
  62. package/dist/{chunk-ECYEWFEH.cjs → chunk-J34FSPSC.cjs} +16 -6
  63. package/dist/chunk-J34FSPSC.cjs.map +1 -0
  64. package/dist/{chunk-GFYCLCGU.cjs → chunk-KM3CLHDB.cjs} +9 -9
  65. package/dist/{chunk-GFYCLCGU.cjs.map → chunk-KM3CLHDB.cjs.map} +1 -1
  66. package/dist/{chunk-SLNH62T3.js → chunk-KQYUKOGX.js} +3 -3
  67. package/dist/{chunk-SLNH62T3.js.map → chunk-KQYUKOGX.js.map} +1 -1
  68. package/dist/{chunk-7I2PYI4U.cjs → chunk-KR3N6Y7O.cjs} +67 -67
  69. package/dist/{chunk-7I2PYI4U.cjs.map → chunk-KR3N6Y7O.cjs.map} +1 -1
  70. package/dist/{chunk-HZCOCNIX.cjs → chunk-L2REUAJB.cjs} +24 -24
  71. package/dist/{chunk-HZCOCNIX.cjs.map → chunk-L2REUAJB.cjs.map} +1 -1
  72. package/dist/{chunk-VU65FXEG.js → chunk-LFXBFPI2.js} +66 -29
  73. package/dist/chunk-LFXBFPI2.js.map +1 -0
  74. package/dist/{chunk-NXRSR6QG.js → chunk-MHM6OGZR.js} +9 -9
  75. package/dist/{chunk-NXRSR6QG.js.map → chunk-MHM6OGZR.js.map} +1 -1
  76. package/dist/{chunk-FCUSVSYX.js → chunk-MRGWM5LE.js} +10 -10
  77. package/dist/{chunk-FCUSVSYX.js.map → chunk-MRGWM5LE.js.map} +1 -1
  78. package/dist/{chunk-WXGMDROJ.js → chunk-QDNEXTON.js} +7 -7
  79. package/dist/{chunk-WXGMDROJ.js.map → chunk-QDNEXTON.js.map} +1 -1
  80. package/dist/{chunk-VYU5H4FO.js → chunk-RXA2D3UR.js} +3 -3
  81. package/dist/{chunk-VYU5H4FO.js.map → chunk-RXA2D3UR.js.map} +1 -1
  82. package/dist/{chunk-XODNY4QI.js → chunk-TIBSLFHR.js} +6 -6
  83. package/dist/{chunk-XODNY4QI.js.map → chunk-TIBSLFHR.js.map} +1 -1
  84. package/dist/{chunk-KZG7HQSN.cjs → chunk-UVMSWO6X.cjs} +173 -173
  85. package/dist/{chunk-KZG7HQSN.cjs.map → chunk-UVMSWO6X.cjs.map} +1 -1
  86. package/dist/{chunk-ORPT5EQW.cjs → chunk-UZ6CJUC5.cjs} +27 -27
  87. package/dist/chunk-UZ6CJUC5.cjs.map +1 -0
  88. package/dist/{chunk-GNF3PHEQ.cjs → chunk-VF2IMMZT.cjs} +17 -17
  89. package/dist/{chunk-GNF3PHEQ.cjs.map → chunk-VF2IMMZT.cjs.map} +1 -1
  90. package/dist/{chunk-PGZV3E3I.cjs → chunk-VXEHEPC4.cjs} +4 -4
  91. package/dist/{chunk-PGZV3E3I.cjs.map → chunk-VXEHEPC4.cjs.map} +1 -1
  92. package/dist/{chunk-OJ47LMOB.cjs → chunk-WIUHN6SZ.cjs} +669 -628
  93. package/dist/chunk-WIUHN6SZ.cjs.map +1 -0
  94. package/dist/{chunk-HNW5IDB3.js → chunk-WIZB5U6N.js} +7 -7
  95. package/dist/{chunk-HNW5IDB3.js.map → chunk-WIZB5U6N.js.map} +1 -1
  96. package/dist/{chunk-IDQZI6GL.js → chunk-XH75W3O5.js} +3 -3
  97. package/dist/{chunk-IDQZI6GL.js.map → chunk-XH75W3O5.js.map} +1 -1
  98. package/dist/{chunk-T7LSSV7J.cjs → chunk-XXEFDJHY.cjs} +45 -45
  99. package/dist/{chunk-T7LSSV7J.cjs.map → chunk-XXEFDJHY.cjs.map} +1 -1
  100. package/dist/{chunk-GORCU2GR.cjs → chunk-Z4NU4MYB.cjs} +123 -123
  101. package/dist/{chunk-GORCU2GR.cjs.map → chunk-Z4NU4MYB.cjs.map} +1 -1
  102. package/dist/{chunk-KFC3OUV4.cjs → chunk-ZHK3HEZ2.cjs} +130 -130
  103. package/dist/{chunk-KFC3OUV4.cjs.map → chunk-ZHK3HEZ2.cjs.map} +1 -1
  104. package/dist/{chunk-FYMYLZGX.cjs → chunk-ZXXGMQC3.cjs} +10 -10
  105. package/dist/{chunk-FYMYLZGX.cjs.map → chunk-ZXXGMQC3.cjs.map} +1 -1
  106. package/dist/graph-merge/index.cjs +577 -99
  107. package/dist/graph-merge/index.cjs.map +1 -1
  108. package/dist/graph-merge/index.d.cts +108 -4
  109. package/dist/graph-merge/index.d.ts +108 -4
  110. package/dist/graph-merge/index.js +495 -21
  111. package/dist/graph-merge/index.js.map +1 -1
  112. package/dist/{graph-templates-qraW63Ry.d.ts → graph-templates-BSA9VU_O.d.ts} +1 -1
  113. package/dist/{graph-templates--hp2U4kn.d.cts → graph-templates-Cg7DpEOF.d.cts} +1 -1
  114. package/dist/index.cjs +95 -95
  115. package/dist/index.d.cts +3 -3
  116. package/dist/index.d.ts +3 -3
  117. package/dist/index.js +16 -16
  118. package/dist/interchange/index.cjs +33 -33
  119. package/dist/interchange/index.d.cts +1 -1
  120. package/dist/interchange/index.d.ts +1 -1
  121. package/dist/interchange/index.js +10 -10
  122. package/dist/{local-store-impl-HXBO3VF4.js → local-store-impl-77DCLAAY.js} +18 -18
  123. package/dist/{local-store-impl-HXBO3VF4.js.map → local-store-impl-77DCLAAY.js.map} +1 -1
  124. package/dist/{local-store-impl-CUQKHHOZ.cjs → local-store-impl-NJCWM3KR.cjs} +22 -22
  125. package/dist/{local-store-impl-CUQKHHOZ.cjs.map → local-store-impl-NJCWM3KR.cjs.map} +1 -1
  126. package/dist/{pglite-store-impl-BD3AVOUH.js → pglite-store-impl-3VFSYLAJ.js} +18 -18
  127. package/dist/{pglite-store-impl-BD3AVOUH.js.map → pglite-store-impl-3VFSYLAJ.js.map} +1 -1
  128. package/dist/{pglite-store-impl-C3MQ72LT.cjs → pglite-store-impl-LHLJ3GBQ.cjs} +22 -22
  129. package/dist/{pglite-store-impl-C3MQ72LT.cjs.map → pglite-store-impl-LHLJ3GBQ.cjs.map} +1 -1
  130. package/dist/profiler/index.d.cts +1 -1
  131. package/dist/profiler/index.d.ts +1 -1
  132. package/dist/provenance/index.cjs +21 -21
  133. package/dist/provenance/index.d.cts +1 -1
  134. package/dist/provenance/index.d.ts +1 -1
  135. package/dist/provenance/index.js +5 -5
  136. package/dist/schema/index.cjs +36 -36
  137. package/dist/schema/index.d.cts +3 -3
  138. package/dist/schema/index.d.ts +3 -3
  139. package/dist/schema/index.js +6 -6
  140. package/dist/{store-stw2AEB4.d.ts → store-CQ3uzXla.d.ts} +58 -27
  141. package/dist/{store-DTEkUQ0k.d.cts → store-DbHAgVMH.d.cts} +58 -27
  142. package/package.json +1 -1
  143. package/dist/chunk-74FNI3PT.js.map +0 -1
  144. package/dist/chunk-ECYEWFEH.cjs.map +0 -1
  145. package/dist/chunk-OJ47LMOB.cjs.map +0 -1
  146. package/dist/chunk-ORPT5EQW.cjs.map +0 -1
  147. package/dist/chunk-VU65FXEG.js.map +0 -1
  148. package/dist/chunk-YVKPUSHS.js.map +0 -1
@@ -1,20 +1,20 @@
1
- import { createStoreWithSchema } from '../chunk-VU65FXEG.js';
2
- import '../chunk-HW3IX2RF.js';
3
- import { InterchangeIdentitySchema, importGraphStream, exportGraphStream, importGraph, exportGraph, registerIngestionImportTarget } from '../chunk-NXRSR6QG.js';
4
- import '../chunk-FCUSVSYX.js';
5
- import { storeBackend, storeRuntime, transactionBackend } from '../chunk-74FNI3PT.js';
6
- import '../chunk-45WPPI64.js';
7
- import '../chunk-7EOJO6QB.js';
8
- import '../chunk-SLNH62T3.js';
9
- import { computeSchemaHash, serializeSchema } from '../chunk-FFR3YUY2.js';
1
+ import { NODE_TEMPORAL_READ_NAMES, CURRENT_ONLY_READ_NAMES, createStoreWithSchema, IDENTITY_READ_NAMES, EDGE_TEMPORAL_READ_NAMES } from '../chunk-LFXBFPI2.js';
2
+ import '../chunk-EWRLWI7W.js';
3
+ import { InterchangeIdentitySchema, importGraphStream, exportGraphStream, importGraph, exportGraph, registerIngestionImportTarget } from '../chunk-MHM6OGZR.js';
4
+ import '../chunk-MRGWM5LE.js';
5
+ import { storeBackend, storeRuntime, transactionBackend } from '../chunk-C3TJU4KQ.js';
6
+ import '../chunk-FMCPKMQI.js';
7
+ import '../chunk-7MHENVRG.js';
8
+ import '../chunk-KQYUKOGX.js';
9
+ import { computeSchemaHash, serializeSchema } from '../chunk-E4QYEWVH.js';
10
10
  import '../chunk-RFMSZ7CF.js';
11
11
  import { defineNode } from '../chunk-P5J256Q7.js';
12
- import { normalizeIdentityPair, identityReferenceKey, identityValidityWindowsOverlap, identityAssertionSemanticKey } from '../chunk-MJXEO7YA.js';
13
- import { generateId, readRevisionOrigin, readRecordedClock, forceRecordedGraphRevision, forceWriteTransactionRevision, advanceRevisionClock, lockSchemaVersionForStoreWrite, lockRecordedGraphWrite } from '../chunk-SIQ4BFL5.js';
12
+ import { normalizeIdentityPair, identityReferenceKey, identityValidityWindowsOverlap, identityAssertionSemanticKey } from '../chunk-762VPGHN.js';
13
+ import { generateId, readRevisionOrigin, readRecordedClock, forceRecordedGraphRevision, forceWriteTransactionRevision, advanceRevisionClock, lockSchemaVersionForStoreWrite, lockRecordedGraphWrite } from '../chunk-AZP5CCHL.js';
14
14
  import '../chunk-JYY2EB5K.js';
15
15
  import { sortedReplacer } from '../chunk-U4SGJQKQ.js';
16
- import '../chunk-IDQZI6GL.js';
17
- import { snapshotExportContention, resolveWriteFencePlan, requireWriteFence, createSqlSchema } from '../chunk-YVKPUSHS.js';
16
+ import '../chunk-XH75W3O5.js';
17
+ import { snapshotExportContention, resolveWriteFencePlan, requireWriteFence, createSqlSchema, graphCommandCoordinationIsolation } from '../chunk-75KH6Y2W.js';
18
18
  import { getNodeKinds, getEdgeKinds, defineInternalGraph } from '../chunk-4PNRH5BO.js';
19
19
  import { encodeTupleKey, validateEdgeEndpoints, computeUniqueKey } from '../chunk-HFZWYHYC.js';
20
20
  import '../chunk-EMORF4PV.js';
@@ -128,7 +128,8 @@ var MERGE_ERROR_CODES = {
128
128
  planningStale: "GRAPH_MERGE_PLANNING_STALE",
129
129
  candidateSource: "GRAPH_MERGE_CANDIDATE_SOURCE",
130
130
  evidence: "GRAPH_MERGE_EVIDENCE",
131
- candidateWriteSet: "GRAPH_MERGE_CANDIDATE_WRITE_SET"
131
+ candidateWriteSet: "GRAPH_MERGE_CANDIDATE_WRITE_SET",
132
+ review: "GRAPH_MERGE_REVIEW"
132
133
  };
133
134
  function toTypeGraphErrorOptions(category, options) {
134
135
  return {
@@ -158,6 +159,14 @@ var InvalidMergeOptionsError = class extends MergeError {
158
159
  this.name = "InvalidMergeOptionsError";
159
160
  }
160
161
  };
162
+ var MergeReviewError = class extends MergeError {
163
+ static errorCategory = "user";
164
+ code = MERGE_ERROR_CODES.review;
165
+ constructor(message, options = {}) {
166
+ super(message, options);
167
+ this.name = "MergeReviewError";
168
+ }
169
+ };
161
170
  var BranchError = class extends TypeGraphError {
162
171
  constructor(message, options = {}) {
163
172
  super(
@@ -2097,6 +2106,45 @@ function unwrapMergeBranches(inputs) {
2097
2106
  return inputs.map((input) => unwrapMergeBranch(input));
2098
2107
  }
2099
2108
 
2109
+ // src/graph-merge/apply-callbacks.ts
2110
+ var NODE_READ_NAMES = [
2111
+ ...NODE_TEMPORAL_READ_NAMES,
2112
+ ...CURRENT_ONLY_READ_NAMES
2113
+ ];
2114
+ function pickReadMethods(source, names) {
2115
+ return Object.fromEntries(names.map((name) => [name, source[name]]));
2116
+ }
2117
+ function mergePlanReadContext(tx, graph) {
2118
+ return {
2119
+ nodes: Object.fromEntries(
2120
+ Object.keys(graph.nodes).map((kind) => [
2121
+ kind,
2122
+ pickReadMethods(requireDefined(tx.nodes[kind]), NODE_READ_NAMES)
2123
+ ])
2124
+ ),
2125
+ edges: Object.fromEntries(
2126
+ Object.keys(graph.edges).map((kind) => [
2127
+ kind,
2128
+ pickReadMethods(
2129
+ requireDefined(tx.edges[kind]),
2130
+ EDGE_TEMPORAL_READ_NAMES
2131
+ )
2132
+ ])
2133
+ ),
2134
+ ..."identity" in tx ? {
2135
+ identity: pickReadMethods(tx.identity, IDENTITY_READ_NAMES)
2136
+ } : {}
2137
+ };
2138
+ }
2139
+ function assertMergeCallbackResult(result, callback) {
2140
+ if (result !== void 0) {
2141
+ throw new InvalidMergeOptionsError(
2142
+ `${callback} must resolve without a return value; throw or reject to abort merge application.`,
2143
+ { cause: result, details: { callback } }
2144
+ );
2145
+ }
2146
+ }
2147
+
2100
2148
  // src/graph-merge/blocking.ts
2101
2149
  var UNBLOCKED_BUCKET_KEY = "unblocked";
2102
2150
  var KEY_PART_SEPARATOR = "\0";
@@ -5895,7 +5943,20 @@ async function lockMergeTargetWrite(txBackend, input) {
5895
5943
  throw input.staleSchemaError(error);
5896
5944
  }
5897
5945
  if (input.graphLock === "required") {
5898
- await lockRecordedGraphWrite(txBackend, input.graphId);
5946
+ const lock = await lockRecordedGraphWrite(txBackend, input.graphId);
5947
+ if (input.requireFreshSnapshot && lock.coordination !== void 0) {
5948
+ const isolation = graphCommandCoordinationIsolation(
5949
+ txBackend.commands,
5950
+ input.graphId,
5951
+ lock.coordination
5952
+ );
5953
+ if (isolation !== "read_committed") {
5954
+ throw new MergePlanCapabilityError(
5955
+ "Merge callbacks require read-committed isolation so their reads observe the target after acquiring its graph lock.",
5956
+ { details: { capability: "mergeCallbackIsolation", isolation } }
5957
+ );
5958
+ }
5959
+ }
5899
5960
  }
5900
5961
  }
5901
5962
 
@@ -8023,11 +8084,12 @@ async function preflightWireMergeWrites(target, nodesApi, edgesApi, artifact) {
8023
8084
  }
8024
8085
  }
8025
8086
  }
8026
- async function assertMergePlanFenceInsideTransaction(target, txBackend, artifact) {
8087
+ async function assertMergePlanFenceInsideTransaction(target, txBackend, artifact, requireFreshSnapshot) {
8027
8088
  await lockMergeTargetWrite(txBackend, {
8028
8089
  graphId: target.graphId,
8029
8090
  schemaVersion: artifact.target.schema.managed ? artifact.target.schema.version : void 0,
8030
8091
  graphLock: "required",
8092
+ requireFreshSnapshot,
8031
8093
  staleSchemaError: (cause) => new MergePlanSchemaMismatchError(
8032
8094
  "The target's active schema no longer matches the merge plan.",
8033
8095
  { cause, details: { expected: artifact.target.schema } }
@@ -8181,7 +8243,7 @@ function reportFromArtifact(artifact, merged, warnings, provenancePersisted) {
8181
8243
  ...provenancePersisted === void 0 ? {} : { provenancePersisted }
8182
8244
  };
8183
8245
  }
8184
- async function applyMergePlan(target, input) {
8246
+ async function applyMergePlan(target, input, options = {}) {
8185
8247
  let validation;
8186
8248
  try {
8187
8249
  validation = await validateMergePlanArtifact(input);
@@ -8210,6 +8272,9 @@ async function applyMergePlan(target, input) {
8210
8272
  );
8211
8273
  }
8212
8274
  try {
8275
+ const { beforeApply, afterApply } = options;
8276
+ const composed = beforeApply !== void 0 || afterApply !== void 0;
8277
+ const transactionOptions = composed ? { isolationLevel: "read_committed" } : mergeCommitTransactionOptions(target);
8213
8278
  assertPublicPlanCapability(target);
8214
8279
  const provenanceStore = artifact.provenance.persist ? await tryOpenProvenanceStore(target) : void 0;
8215
8280
  if (provenanceStore !== void 0 && isErr(provenanceStore)) {
@@ -8221,8 +8286,15 @@ async function applyMergePlan(target, input) {
8221
8286
  await assertMergePlanFenceInsideTransaction(
8222
8287
  target,
8223
8288
  txBackend,
8224
- artifact
8289
+ artifact,
8290
+ composed
8225
8291
  );
8292
+ if (beforeApply !== void 0) {
8293
+ assertMergeCallbackResult(
8294
+ await beforeApply(mergePlanReadContext(tx, target.graph)),
8295
+ "beforeApply"
8296
+ );
8297
+ }
8226
8298
  await preflightWireMergeWrites(
8227
8299
  target,
8228
8300
  tx.nodes,
@@ -8233,14 +8305,21 @@ async function applyMergePlan(target, input) {
8233
8305
  identityAssertions: artifact.writes.identityAssertions,
8234
8306
  identityRetractions: artifact.writes.identityRetractions
8235
8307
  });
8236
- return applyWireMergeWrites(
8308
+ const applied = await applyWireMergeWrites(
8237
8309
  target,
8238
8310
  tx.nodes,
8239
8311
  tx.edges,
8240
8312
  txBackend,
8241
8313
  artifact
8242
8314
  );
8243
- }, mergeCommitTransactionOptions(target))
8315
+ if (afterApply !== void 0) {
8316
+ assertMergeCallbackResult(
8317
+ await afterApply(tx, { merged: structuredClone(applied) }),
8318
+ "afterApply"
8319
+ );
8320
+ }
8321
+ return applied;
8322
+ }, transactionOptions)
8244
8323
  );
8245
8324
  const warnings = [...artifact.review.warnings];
8246
8325
  let provenancePersisted;
@@ -8965,6 +9044,401 @@ async function planCandidateWriteSet(args) {
8965
9044
  }
8966
9045
  }
8967
9046
 
8968
- export { BaseVersionMismatchError, BranchError, CANDIDATE_WRITE_SET_FORMAT_VERSION, CandidateSourceError, CandidateWriteSetError, CandidateWriteSetSchema, CandidateWriteSetTargetSchema, IdentityMergeConflictError, InvalidMergeOptionsError, InvalidMergePlanError, MERGE_ERROR_CODES, MERGE_OPTION_DEFAULTS, MERGE_PLAN_DIGEST_ALGORITHM, MERGE_PLAN_FORMAT_VERSION, MatchEvidenceError, MergeConflictError, MergeConstraintConflictError, MergeError, MergePlanCapabilityError, MergePlanDigestMismatchError, MergePlanOriginMismatchError, MergePlanSchemaMismatchError, MergePlanTargetMismatchError, MergePlanningStaleError, SimilarityUnavailableError, StaleMergePlanError, UnsupportedMergePlanVersionError, VALIDITY_END_TARGET_PRECEDENCE, applyMergePlan, asBaseVersion, asBranchId, branch, captureCandidateWriteSetTarget, cloneWorkingCopyStrategy, computeBaseVersion, ingestionBranch, merge, mergeIncremental, normalizeMergeOptions, openProvenanceStore, persistProvenanceRecords, planCandidateWriteSet, planMerge, planMergeIncremental, provenanceGraphId, readProvenance };
9047
+ // src/graph-merge/review-evidence.ts
9048
+ function reviewJson(value) {
9049
+ if (value === void 0) return "undefined";
9050
+ return JSON.stringify(value, sortedReplacer);
9051
+ }
9052
+ async function reviewDigest(value) {
9053
+ return sha256Hex(reviewJson(value), 32);
9054
+ }
9055
+ function reviewOptionEvidence(options) {
9056
+ return encodeOption(normalizeMergeOptions(options), /* @__PURE__ */ new Set());
9057
+ }
9058
+ function encodeOption(value, ancestors) {
9059
+ if (value === void 0) return ["undefined"];
9060
+ if (typeof value === "function") return ["callback"];
9061
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
9062
+ return ["literal", value];
9063
+ }
9064
+ if (typeof value === "number" && Number.isFinite(value))
9065
+ return ["number", value];
9066
+ if (typeof value !== "object" || ancestors.has(value)) {
9067
+ throw new MergeReviewError(
9068
+ "Merge options contain unsupported or cyclic review evidence."
9069
+ );
9070
+ }
9071
+ const nextAncestors = /* @__PURE__ */ new Set([...ancestors, value]);
9072
+ if (Array.isArray(value)) {
9073
+ return [
9074
+ "array",
9075
+ value.map((item) => encodeOption(item, nextAncestors))
9076
+ ];
9077
+ }
9078
+ if (value instanceof Map) {
9079
+ const entries = [...value].map(
9080
+ ([key, entry]) => [
9081
+ encodeOption(key, nextAncestors),
9082
+ encodeOption(entry, nextAncestors)
9083
+ ]
9084
+ );
9085
+ entries.sort(
9086
+ (left, right) => compareStrings(reviewJson(left), reviewJson(right))
9087
+ );
9088
+ return ["map", entries];
9089
+ }
9090
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
9091
+ throw new MergeReviewError(
9092
+ "Merge options contain a non-JSON object without a review representation."
9093
+ );
9094
+ }
9095
+ return [
9096
+ "object",
9097
+ Object.entries(value).sort(([left], [right]) => compareStrings(left, right)).map(([key, entry]) => [key, encodeOption(entry, nextAncestors)])
9098
+ ];
9099
+ }
9100
+
9101
+ // src/graph-merge/review-baseline.ts
9102
+ function reviewRowKey(row) {
9103
+ return JSON.stringify([row.role, row.kind, row.id]);
9104
+ }
9105
+ async function captureReviewBaseline(target) {
9106
+ const backend = storeBackend(target);
9107
+ const rows = [];
9108
+ for (const kind of getNodeKinds(target.graph)) {
9109
+ for (const row of await enumerateAllNodes(backend, target.graphId, kind)) {
9110
+ rows.push({
9111
+ role: "node",
9112
+ kind,
9113
+ id: row.id,
9114
+ digest: await reviewDigest({ ...row, props: parseRowProps(row.props) })
9115
+ });
9116
+ }
9117
+ }
9118
+ for (const kind of getEdgeKinds(target.graph)) {
9119
+ for (const row of await enumerateAllEdges(backend, target.graphId, kind)) {
9120
+ rows.push({
9121
+ role: "edge",
9122
+ kind,
9123
+ id: row.id,
9124
+ digest: await reviewDigest({ ...row, props: parseRowProps(row.props) })
9125
+ });
9126
+ }
9127
+ }
9128
+ const identity = await storeRuntime(target).readCurrentIdentityAssertions(
9129
+ "archival",
9130
+ {
9131
+ includeDeleted: true
9132
+ }
9133
+ );
9134
+ return {
9135
+ rows: rows.sort(
9136
+ (left, right) => compareStrings(reviewRowKey(left), reviewRowKey(right))
9137
+ ),
9138
+ identityDigest: await reviewDigest(
9139
+ [...identity].sort((left, right) => compareStrings(left.id, right.id))
9140
+ )
9141
+ };
9142
+ }
9143
+ function withReviewAbsences(baseline, writeSet, plan, graph) {
9144
+ const rows = new Map(baseline.rows.map((row) => [reviewRowKey(row), row]));
9145
+ function addNode(entity) {
9146
+ for (const kind of getNodeKinds(graph)) {
9147
+ const row = { role: "node", kind, id: entity.id };
9148
+ if (!rows.has(reviewRowKey(row))) rows.set(reviewRowKey(row), row);
9149
+ }
9150
+ }
9151
+ for (const row of baseline.rows) if (row.role === "node") addNode(row);
9152
+ function addEdge(entity) {
9153
+ for (const kind of getEdgeKinds(graph)) {
9154
+ const row = { role: "edge", kind, id: entity.id };
9155
+ if (!rows.has(reviewRowKey(row))) rows.set(reviewRowKey(row), row);
9156
+ }
9157
+ }
9158
+ for (const node of [
9159
+ ...writeSet.nodes,
9160
+ ...plan.writes.nodeUpserts,
9161
+ ...plan.writes.nodeDeletes,
9162
+ ...plan.guards.deletedNodes
9163
+ ])
9164
+ addNode(node);
9165
+ for (const edge of [...writeSet.edges, ...plan.writes.edgeUpserts]) {
9166
+ addEdge(edge);
9167
+ addNode(edge.from);
9168
+ addNode(edge.to);
9169
+ }
9170
+ for (const edge of plan.writes.edgeDeletes) addEdge(edge);
9171
+ for (const assertion of [
9172
+ ...writeSet.identity?.assertions ?? [],
9173
+ ...plan.writes.identityAssertions,
9174
+ ...plan.writes.identityRetractions
9175
+ ]) {
9176
+ addNode(assertion.a);
9177
+ addNode(assertion.b);
9178
+ if (assertion.endedBy !== void 0) addNode(assertion.endedBy);
9179
+ }
9180
+ for (const mapping of plan.guards.canonicalMappings) {
9181
+ addNode(mapping.member);
9182
+ addNode(mapping.canonical);
9183
+ }
9184
+ for (const retype of plan.guards.retypes) {
9185
+ addNode(retype.entity);
9186
+ addNode({ kind: retype.toKind, id: retype.entity.id });
9187
+ }
9188
+ return {
9189
+ ...baseline,
9190
+ rows: [...rows.values()].sort(
9191
+ (left, right) => compareStrings(reviewRowKey(left), reviewRowKey(right))
9192
+ )
9193
+ };
9194
+ }
9195
+ function compareReviewBaseline(reviewed, current) {
9196
+ const currentRows = new Map(
9197
+ current.rows.map((row) => [reviewRowKey(row), row])
9198
+ );
9199
+ const differences = [];
9200
+ for (const row of reviewed.rows) {
9201
+ if (row.digest !== currentRows.get(reviewRowKey(row))?.digest) {
9202
+ differences.push({
9203
+ category: "baseline",
9204
+ path: "baseline.rows",
9205
+ entity: { role: row.role, kind: row.kind, id: row.id }
9206
+ });
9207
+ }
9208
+ }
9209
+ if (reviewed.identityDigest !== current.identityDigest) {
9210
+ differences.push({ category: "baseline", path: "baseline.identityDigest" });
9211
+ }
9212
+ return differences;
9213
+ }
9214
+ var MERGE_REVIEW_FORMAT_VERSION = 1;
9215
+ var digestSchema = z.string().regex(/^[\da-f]{64}$/u);
9216
+ var mergeReviewPolicySchema = z.object({
9217
+ id: z.string().min(1),
9218
+ context: z.json()
9219
+ }).strict();
9220
+ var mergeReviewArtifactSchema = z.object({
9221
+ formatVersion: z.literal(MERGE_REVIEW_FORMAT_VERSION),
9222
+ kind: z.literal("candidate-write-set"),
9223
+ digest: z.object({ algorithm: z.literal("sha256"), value: digestSchema }).strict(),
9224
+ writeSet: CandidateWriteSetSchema,
9225
+ policy: mergeReviewPolicySchema,
9226
+ options: z.json(),
9227
+ plan: mergePlanArtifactV1Schema,
9228
+ baseline: z.object({
9229
+ rows: z.array(
9230
+ z.object({
9231
+ role: z.enum(["node", "edge"]),
9232
+ kind: z.string().min(1),
9233
+ id: z.string().min(1),
9234
+ digest: digestSchema.optional()
9235
+ }).strict()
9236
+ ),
9237
+ identityDigest: digestSchema
9238
+ }).strict()
9239
+ }).strict();
9240
+
9241
+ // src/graph-merge/candidate-review.ts
9242
+ async function planCandidateWriteSetReview(args) {
9243
+ try {
9244
+ const writeSet = CandidateWriteSetSchema.parse(args.writeSet);
9245
+ const policy = mergeReviewPolicySchema.parse(args.policy);
9246
+ const options = reviewOptionEvidence(args.options);
9247
+ const startingFence = await captureMergePlanTargetFence(args.target);
9248
+ const baseline = await captureReviewBaseline(args.target);
9249
+ const planned = await planCandidateWriteSet({ ...args, writeSet });
9250
+ if (isErr(planned)) return planned;
9251
+ assertReviewPlanFence(startingFence, planned.data);
9252
+ await assertPlanningFenceUnchanged(args.target, startingFence);
9253
+ assertOptionsUnchanged(options, reviewOptionEvidence(args.options));
9254
+ const input = {
9255
+ formatVersion: MERGE_REVIEW_FORMAT_VERSION,
9256
+ kind: "candidate-write-set",
9257
+ writeSet,
9258
+ policy,
9259
+ options,
9260
+ plan: planned.data,
9261
+ baseline: withReviewAbsences(
9262
+ baseline,
9263
+ writeSet,
9264
+ planned.data,
9265
+ args.target.graph
9266
+ )
9267
+ };
9268
+ const review = {
9269
+ ...input,
9270
+ digest: { algorithm: "sha256", value: await reviewDigest(input) }
9271
+ };
9272
+ mergeReviewArtifactSchema.parse(review);
9273
+ return ok(review);
9274
+ } catch (error) {
9275
+ return err(asReviewError(error));
9276
+ }
9277
+ }
9278
+ async function revalidateCandidateWriteSetReview(args) {
9279
+ try {
9280
+ const review = await validateReview(args.review);
9281
+ const policy = mergeReviewPolicySchema.parse(args.policy);
9282
+ const options = reviewOptionEvidence(args.options);
9283
+ const startingFence = await captureMergePlanTargetFence(args.target);
9284
+ const targetDifferences = compareReviewTarget(
9285
+ review.plan.target,
9286
+ startingFence
9287
+ );
9288
+ if (targetDifferences.length > 0)
9289
+ return ok({
9290
+ status: "incompatible",
9291
+ reviewDigest: review.digest,
9292
+ differences: targetDifferences
9293
+ });
9294
+ if (withReviewAbsences(
9295
+ review.baseline,
9296
+ review.writeSet,
9297
+ review.plan,
9298
+ args.target.graph
9299
+ ).rows.length !== review.baseline.rows.length) {
9300
+ throw new MergeReviewError(
9301
+ "The merge review is missing required baseline evidence.",
9302
+ { details: { reason: "incomplete-baseline" } }
9303
+ );
9304
+ }
9305
+ const policyDifferences = compareFields(
9306
+ "policy",
9307
+ { policy: review.policy, options: review.options },
9308
+ { policy, options }
9309
+ );
9310
+ if (policyDifferences.length > 0)
9311
+ return ok({
9312
+ status: "changed",
9313
+ reviewDigest: review.digest,
9314
+ differences: policyDifferences
9315
+ });
9316
+ const baseline = await captureReviewBaseline(args.target);
9317
+ const baselineDifferences = compareReviewBaseline(
9318
+ review.baseline,
9319
+ baseline
9320
+ );
9321
+ if (baselineDifferences.length > 0) {
9322
+ await assertPlanningFenceUnchanged(args.target, startingFence);
9323
+ return ok({
9324
+ status: "changed",
9325
+ reviewDigest: review.digest,
9326
+ differences: baselineDifferences
9327
+ });
9328
+ }
9329
+ const planned = await planCandidateWriteSet({
9330
+ ...args,
9331
+ writeSet: review.writeSet
9332
+ });
9333
+ if (isErr(planned)) return planned;
9334
+ assertReviewPlanFence(startingFence, planned.data);
9335
+ await assertPlanningFenceUnchanged(args.target, startingFence);
9336
+ assertOptionsUnchanged(options, reviewOptionEvidence(args.options));
9337
+ const differences = compareFields(
9338
+ "plan",
9339
+ reviewPlanContent(review.plan),
9340
+ reviewPlanContent(planned.data)
9341
+ );
9342
+ return ok(
9343
+ differences.length === 0 ? {
9344
+ status: "compatible",
9345
+ reviewDigest: review.digest,
9346
+ plan: planned.data
9347
+ } : {
9348
+ status: "changed",
9349
+ reviewDigest: review.digest,
9350
+ differences,
9351
+ plan: planned.data
9352
+ }
9353
+ );
9354
+ } catch (error) {
9355
+ return err(asReviewError(error));
9356
+ }
9357
+ }
9358
+ async function validateReview(input) {
9359
+ const review = mergeReviewArtifactSchema.parse(input);
9360
+ if (reviewJson(input) !== reviewJson(review)) {
9361
+ throw new MergeReviewError(
9362
+ "Stored merge review evidence must not require normalization.",
9363
+ {
9364
+ details: { reason: "noncanonical-shape" }
9365
+ }
9366
+ );
9367
+ }
9368
+ const { digest, ...content } = review;
9369
+ if (digest.value !== await reviewDigest(content)) {
9370
+ throw new MergeReviewError(
9371
+ "The merge review digest does not match its content.",
9372
+ { details: { reason: "digest-mismatch" } }
9373
+ );
9374
+ }
9375
+ const plan = await validateMergePlanArtifact(review.plan);
9376
+ if (!plan.success)
9377
+ throw new MergeReviewError("The reviewed execution plan is invalid.", {
9378
+ details: { reason: "invalid-plan", error: plan.error }
9379
+ });
9380
+ const anchors = plan.artifact.anchors;
9381
+ if (plan.artifact.mode !== "incremental" || anchors.kind !== "incremental" || anchors.forkPoint.graphId !== review.writeSet.target.graphId || plan.artifact.target.graphId !== review.writeSet.target.graphId || plan.artifact.target.schema.version !== review.writeSet.target.schemaVersion || plan.artifact.target.schema.hash !== review.writeSet.target.schemaHash || reviewJson(anchors.forkPoint.schema) !== reviewJson(plan.artifact.target.schema) || anchors.branches.length !== 1 || anchors.branches[0]?.branchId !== review.writeSet.sourceId || anchors.branches[0].baseVersion !== anchors.forkPoint.baseVersion) {
9382
+ throw new MergeReviewError(
9383
+ "The reviewed plan does not describe the retained candidate source and target.",
9384
+ { details: { reason: "incompatible-plan" } }
9385
+ );
9386
+ }
9387
+ if (new Set(review.baseline.rows.map((row) => reviewRowKey(row))).size !== review.baseline.rows.length) {
9388
+ throw new MergeReviewError(
9389
+ "The merge review contains duplicate baseline references.",
9390
+ { details: { reason: "duplicate-baseline" } }
9391
+ );
9392
+ }
9393
+ return { ...review, plan: plan.artifact };
9394
+ }
9395
+ function assertReviewPlanFence(fence, plan) {
9396
+ if (!sameMergePlanTargetFence(fence, plan.target)) {
9397
+ throw new MergePlanningStaleError(
9398
+ "The target changed between review evidence capture and planning."
9399
+ );
9400
+ }
9401
+ }
9402
+ function assertOptionsUnchanged(before, after) {
9403
+ if (reviewJson(before) !== reviewJson(after))
9404
+ throw new MergeReviewError(
9405
+ "Merge options changed while review evidence was being captured."
9406
+ );
9407
+ }
9408
+ function compareReviewTarget(reviewed, current) {
9409
+ return compareFields(
9410
+ "target",
9411
+ {
9412
+ graphId: reviewed.graphId,
9413
+ schema: reviewed.schema,
9414
+ origin: reviewed.revision.origin
9415
+ },
9416
+ {
9417
+ graphId: current.graphId,
9418
+ schema: current.schema,
9419
+ origin: current.revision.origin
9420
+ }
9421
+ );
9422
+ }
9423
+ function reviewPlanContent(plan) {
9424
+ const {
9425
+ digest: _digest,
9426
+ target: _target,
9427
+ anchors: _anchors,
9428
+ ...content
9429
+ } = plan;
9430
+ return content;
9431
+ }
9432
+ function compareFields(category, reviewed, current) {
9433
+ return [.../* @__PURE__ */ new Set([...Object.keys(reviewed), ...Object.keys(current)])].sort().filter((key) => reviewJson(reviewed[key]) !== reviewJson(current[key])).map((key) => ({ category, path: `${category}.${key}` }));
9434
+ }
9435
+ function asReviewError(error) {
9436
+ return error instanceof MergeError ? error : new MergeReviewError(
9437
+ "Unable to validate or capture merge review evidence.",
9438
+ { cause: error }
9439
+ );
9440
+ }
9441
+
9442
+ export { BaseVersionMismatchError, BranchError, CANDIDATE_WRITE_SET_FORMAT_VERSION, CandidateSourceError, CandidateWriteSetError, CandidateWriteSetSchema, CandidateWriteSetTargetSchema, IdentityMergeConflictError, InvalidMergeOptionsError, InvalidMergePlanError, MERGE_ERROR_CODES, MERGE_OPTION_DEFAULTS, MERGE_PLAN_DIGEST_ALGORITHM, MERGE_PLAN_FORMAT_VERSION, MERGE_REVIEW_FORMAT_VERSION, MatchEvidenceError, MergeConflictError, MergeConstraintConflictError, MergeError, MergePlanCapabilityError, MergePlanDigestMismatchError, MergePlanOriginMismatchError, MergePlanSchemaMismatchError, MergePlanTargetMismatchError, MergePlanningStaleError, MergeReviewError, SimilarityUnavailableError, StaleMergePlanError, UnsupportedMergePlanVersionError, VALIDITY_END_TARGET_PRECEDENCE, applyMergePlan, asBaseVersion, asBranchId, branch, captureCandidateWriteSetTarget, cloneWorkingCopyStrategy, computeBaseVersion, ingestionBranch, merge, mergeIncremental, normalizeMergeOptions, openProvenanceStore, persistProvenanceRecords, planCandidateWriteSet, planCandidateWriteSetReview, planMerge, planMergeIncremental, provenanceGraphId, readProvenance, revalidateCandidateWriteSetReview };
8969
9443
  //# sourceMappingURL=index.js.map
8970
9444
  //# sourceMappingURL=index.js.map