@nicia-ai/typegraph 0.67.1 → 0.68.1

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 (40) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/backend/postgres/pglite-store.cjs +1 -1
  3. package/dist/backend/postgres/pglite-store.js +1 -1
  4. package/dist/backend/sqlite/local-store.cjs +1 -1
  5. package/dist/backend/sqlite/local-store.js +1 -1
  6. package/dist/{chunk-T3VU3YRQ.cjs → chunk-6GUBF5TF.cjs} +24 -18
  7. package/dist/chunk-6GUBF5TF.cjs.map +1 -0
  8. package/dist/{chunk-55DGFZYC.js → chunk-EJYBHBIB.js} +3 -3
  9. package/dist/{chunk-55DGFZYC.js.map → chunk-EJYBHBIB.js.map} +1 -1
  10. package/dist/{chunk-WY3IFEKV.cjs → chunk-IFTYHOEE.cjs} +13 -5
  11. package/dist/chunk-IFTYHOEE.cjs.map +1 -0
  12. package/dist/{chunk-RTPMG6LQ.js → chunk-JVKHJQ6Q.js} +13 -5
  13. package/dist/chunk-JVKHJQ6Q.js.map +1 -0
  14. package/dist/{chunk-FS2GVO2T.cjs → chunk-OBEYH22Q.cjs} +159 -159
  15. package/dist/{chunk-FS2GVO2T.cjs.map → chunk-OBEYH22Q.cjs.map} +1 -1
  16. package/dist/{chunk-7YJHUY4T.js → chunk-VUYODTHL.js} +10 -5
  17. package/dist/chunk-VUYODTHL.js.map +1 -0
  18. package/dist/graph-merge/index.cjs +540 -22
  19. package/dist/graph-merge/index.cjs.map +1 -1
  20. package/dist/graph-merge/index.d.cts +317 -9
  21. package/dist/graph-merge/index.d.ts +317 -9
  22. package/dist/graph-merge/index.js +512 -8
  23. package/dist/graph-merge/index.js.map +1 -1
  24. package/dist/index.cjs +43 -43
  25. package/dist/index.js +2 -2
  26. package/dist/interchange/index.cjs +25 -25
  27. package/dist/interchange/index.js +2 -2
  28. package/dist/{local-store-impl-GI6S4J6B.cjs → local-store-impl-INNRHDK3.cjs} +5 -5
  29. package/dist/{local-store-impl-GI6S4J6B.cjs.map → local-store-impl-INNRHDK3.cjs.map} +1 -1
  30. package/dist/{local-store-impl-CCMWTLGY.js → local-store-impl-VGC3OKCA.js} +4 -4
  31. package/dist/{local-store-impl-CCMWTLGY.js.map → local-store-impl-VGC3OKCA.js.map} +1 -1
  32. package/dist/{pglite-store-impl-HAPAJUIO.cjs → pglite-store-impl-KDS4NRMC.cjs} +5 -5
  33. package/dist/{pglite-store-impl-HAPAJUIO.cjs.map → pglite-store-impl-KDS4NRMC.cjs.map} +1 -1
  34. package/dist/{pglite-store-impl-HDLFOZWS.js → pglite-store-impl-LJDF2EUF.js} +4 -4
  35. package/dist/{pglite-store-impl-HDLFOZWS.js.map → pglite-store-impl-LJDF2EUF.js.map} +1 -1
  36. package/package.json +1 -1
  37. package/dist/chunk-7YJHUY4T.js.map +0 -1
  38. package/dist/chunk-RTPMG6LQ.js.map +0 -1
  39. package/dist/chunk-T3VU3YRQ.cjs.map +0 -1
  40. package/dist/chunk-WY3IFEKV.cjs.map +0 -1
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var chunkFS2GVO2T_cjs = require('../chunk-FS2GVO2T.cjs');
3
+ var chunkOBEYH22Q_cjs = require('../chunk-OBEYH22Q.cjs');
4
4
  require('../chunk-76OB5RSH.cjs');
5
5
  var chunk3HMEGR7U_cjs = require('../chunk-3HMEGR7U.cjs');
6
6
  require('../chunk-2XQYRCPM.cjs');
7
- var chunkT3VU3YRQ_cjs = require('../chunk-T3VU3YRQ.cjs');
8
- require('../chunk-WY3IFEKV.cjs');
7
+ var chunk6GUBF5TF_cjs = require('../chunk-6GUBF5TF.cjs');
8
+ require('../chunk-IFTYHOEE.cjs');
9
9
  require('../chunk-VNJMM2QQ.cjs');
10
10
  require('../chunk-I7SBZJI2.cjs');
11
11
  require('../chunk-G7OKJDMG.cjs');
@@ -40,7 +40,7 @@ var chunkXPSPDFKO_cjs = require('../chunk-XPSPDFKO.cjs');
40
40
  require('../chunk-HAHNRASW.cjs');
41
41
  var chunkHQU2SE74_cjs = require('../chunk-HQU2SE74.cjs');
42
42
  var chunkXUO3KQFO_cjs = require('../chunk-XUO3KQFO.cjs');
43
- require('../chunk-JLSXOBLQ.cjs');
43
+ var chunkJLSXOBLQ_cjs = require('../chunk-JLSXOBLQ.cjs');
44
44
  var chunkNYWU6CBZ_cjs = require('../chunk-NYWU6CBZ.cjs');
45
45
  require('../chunk-OZ3ZU7Q2.cjs');
46
46
  var chunkBXHAPCQG_cjs = require('../chunk-BXHAPCQG.cjs');
@@ -135,7 +135,13 @@ var MERGE_ERROR_CODES = {
135
135
  candidateSource: "GRAPH_MERGE_CANDIDATE_SOURCE",
136
136
  evidence: "GRAPH_MERGE_EVIDENCE",
137
137
  candidateWriteSet: "GRAPH_MERGE_CANDIDATE_WRITE_SET",
138
- review: "GRAPH_MERGE_REVIEW"
138
+ review: "GRAPH_MERGE_REVIEW",
139
+ operation: "GRAPH_MERGE_OPERATION",
140
+ operationRequest: "GRAPH_MERGE_OPERATION_REQUEST",
141
+ operationConflict: "GRAPH_MERGE_OPERATION_CONFLICT",
142
+ operationUnsupported: "GRAPH_MERGE_OPERATION_UNSUPPORTED",
143
+ operationEvidence: "GRAPH_MERGE_OPERATION_EVIDENCE",
144
+ operationUndelivered: "GRAPH_MERGE_OPERATION_UNDELIVERED"
139
145
  };
140
146
  function toTypeGraphErrorOptions(category, options) {
141
147
  return {
@@ -342,6 +348,51 @@ var MatchEvidenceError = class extends MergeError {
342
348
  this.name = "MatchEvidenceError";
343
349
  }
344
350
  };
351
+ var DurableOperationError = class extends MergeError {
352
+ code = MERGE_ERROR_CODES.operation;
353
+ constructor(message, options = {}) {
354
+ super(message, options);
355
+ this.name = "DurableOperationError";
356
+ }
357
+ };
358
+ var DurableOperationRequestError = class extends DurableOperationError {
359
+ static errorCategory = "user";
360
+ code = MERGE_ERROR_CODES.operationRequest;
361
+ constructor(message, options = {}) {
362
+ super(message, options);
363
+ this.name = "DurableOperationRequestError";
364
+ }
365
+ };
366
+ var DurableOperationConflictError = class extends DurableOperationError {
367
+ static errorCategory = "constraint";
368
+ code = MERGE_ERROR_CODES.operationConflict;
369
+ constructor(message, options = {}) {
370
+ super(message, options);
371
+ this.name = "DurableOperationConflictError";
372
+ }
373
+ };
374
+ var DurableOperationUnsupportedError = class extends DurableOperationError {
375
+ static errorCategory = "user";
376
+ code = MERGE_ERROR_CODES.operationUnsupported;
377
+ constructor(message, options = {}) {
378
+ super(message, options);
379
+ this.name = "DurableOperationUnsupportedError";
380
+ }
381
+ };
382
+ var DurableOperationEvidenceError = class extends DurableOperationError {
383
+ code = MERGE_ERROR_CODES.operationEvidence;
384
+ constructor(message, options = {}) {
385
+ super(message, options);
386
+ this.name = "DurableOperationEvidenceError";
387
+ }
388
+ };
389
+ var DurableEvidenceUndeliveredError = class extends BranchError {
390
+ code = MERGE_ERROR_CODES.operationUndelivered;
391
+ constructor(message, options = {}) {
392
+ super(message, options);
393
+ this.name = "DurableEvidenceUndeliveredError";
394
+ }
395
+ };
345
396
  function describeCause(cause) {
346
397
  return cause instanceof Error ? cause.message : String(cause);
347
398
  }
@@ -2109,7 +2160,7 @@ function cloneWorkingCopyWithGraphStrategy(makeBackend, graphForClone) {
2109
2160
  create: async (baseStore) => {
2110
2161
  const backend = await makeBackend();
2111
2162
  try {
2112
- const [freshStore] = await chunkFS2GVO2T_cjs.createStoreWithSchema(
2163
+ const [freshStore] = await chunkOBEYH22Q_cjs.createStoreWithSchema(
2113
2164
  graphForClone(baseStore),
2114
2165
  backend,
2115
2166
  {
@@ -2140,25 +2191,25 @@ function cloneWorkingCopyWithGraphStrategy(makeBackend, graphForClone) {
2140
2191
  };
2141
2192
  const importOptions = {
2142
2193
  onConflict: "error",
2143
- onUnknownProperty: "error",
2194
+ onUnknownProperty: "allow",
2144
2195
  validateReferences: true,
2145
2196
  batchSize: CLONE_IMPORT_BATCH_SIZE
2146
2197
  };
2147
2198
  const result = chunk6JRVV2SS_cjs.snapshotExportContention(
2148
2199
  chunk6B3LQUYG_cjs.storeBackend(baseStore),
2149
2200
  chunk6B3LQUYG_cjs.storeBackend(freshStore)
2150
- ) === void 0 ? await chunkT3VU3YRQ_cjs.importGraphStream(
2201
+ ) === void 0 ? await chunk6GUBF5TF_cjs.importGraphStream(
2151
2202
  freshStore,
2152
- chunkT3VU3YRQ_cjs.exportGraphStream(baseStore, exportOptions),
2203
+ chunk6GUBF5TF_cjs.exportGraphStream(baseStore, exportOptions),
2153
2204
  importOptions
2154
- ) : await chunkT3VU3YRQ_cjs.importGraph(
2205
+ ) : await chunk6GUBF5TF_cjs.importGraph(
2155
2206
  freshStore,
2156
- await chunkT3VU3YRQ_cjs.exportGraph(baseStore, exportOptions),
2207
+ await chunk6GUBF5TF_cjs.exportGraph(baseStore, exportOptions),
2157
2208
  importOptions
2158
2209
  );
2159
2210
  if (!result.success) {
2160
2211
  throw new BranchError(
2161
- "Clone import failed: the working copy could not be seeded from the base store. The backend returned by makeBackend() must be empty.",
2212
+ `Clone import failed: the working copy could not be seeded from the base store. ${chunk6GUBF5TF_cjs.summarizeImportErrors(result.errors)}`,
2162
2213
  { details: { errors: result.errors } }
2163
2214
  );
2164
2215
  }
@@ -2243,7 +2294,7 @@ function forkedWorkingCopyStrategy(options) {
2243
2294
  { details: { inheritedTables, connectedTables } }
2244
2295
  );
2245
2296
  }
2246
- const forkStore = chunkFS2GVO2T_cjs.createStore(baseStore.graph, backend, forkOptions);
2297
+ const forkStore = chunkOBEYH22Q_cjs.createStore(baseStore.graph, backend, forkOptions);
2247
2298
  await assertWorkingCopyMatchesBase(forkStore, base);
2248
2299
  return forkStore;
2249
2300
  } catch (error) {
@@ -2385,7 +2436,7 @@ async function ingestionBranch(baseStore, makeBackend, options) {
2385
2436
  close: coalescedWorkingCopyClose(store)
2386
2437
  });
2387
2438
  PRIVATE_BRANCHES.set(handle, privateBranch);
2388
- chunkT3VU3YRQ_cjs.registerIngestionImportTarget(handle, store);
2439
+ chunk6GUBF5TF_cjs.registerIngestionImportTarget(handle, store);
2389
2440
  return chunkHQU2SE74_cjs.ok(handle);
2390
2441
  } catch (error) {
2391
2442
  return chunkHQU2SE74_cjs.err(
@@ -2431,8 +2482,8 @@ async function assertMergeTransactionPristine(target, txBackend) {
2431
2482
 
2432
2483
  // src/graph-merge/apply-callbacks.ts
2433
2484
  var NODE_READ_NAMES = [
2434
- ...chunkFS2GVO2T_cjs.NODE_TEMPORAL_READ_NAMES,
2435
- ...chunkFS2GVO2T_cjs.CURRENT_ONLY_READ_NAMES
2485
+ ...chunkOBEYH22Q_cjs.NODE_TEMPORAL_READ_NAMES,
2486
+ ...chunkOBEYH22Q_cjs.CURRENT_ONLY_READ_NAMES
2436
2487
  ];
2437
2488
  function pickReadMethods(source, names) {
2438
2489
  return Object.fromEntries(names.map((name) => [name, source[name]]));
@@ -2450,12 +2501,12 @@ function mergePlanReadContext(tx, graph) {
2450
2501
  kind,
2451
2502
  pickReadMethods(
2452
2503
  chunkBXHAPCQG_cjs.requireDefined(tx.edges[kind]),
2453
- chunkFS2GVO2T_cjs.EDGE_TEMPORAL_READ_NAMES
2504
+ chunkOBEYH22Q_cjs.EDGE_TEMPORAL_READ_NAMES
2454
2505
  )
2455
2506
  ])
2456
2507
  ),
2457
2508
  ..."identity" in tx ? {
2458
- identity: pickReadMethods(tx.identity, chunkFS2GVO2T_cjs.IDENTITY_READ_NAMES)
2509
+ identity: pickReadMethods(tx.identity, chunkOBEYH22Q_cjs.IDENTITY_READ_NAMES)
2459
2510
  } : {}
2460
2511
  };
2461
2512
  }
@@ -5285,7 +5336,7 @@ async function openProvenanceStore(...args) {
5285
5336
  throw provenanceGraphIdCollision(graph.id, targetGraphId, claim.reason);
5286
5337
  }
5287
5338
  }
5288
- const [store] = await chunkFS2GVO2T_cjs.createStoreWithSchema(graph, backend);
5339
+ const [store] = await chunkOBEYH22Q_cjs.createStoreWithSchema(graph, backend);
5289
5340
  return store;
5290
5341
  }
5291
5342
  async function claimSidecarOwnership(backend, graph, targetGraphId) {
@@ -9640,7 +9691,7 @@ var CandidateWriteSetSchema = zod.z.object({
9640
9691
  target: CandidateWriteSetTargetSchema,
9641
9692
  nodes: zod.z.array(candidateNodeSchema),
9642
9693
  edges: zod.z.array(candidateEdgeSchema),
9643
- identity: chunkT3VU3YRQ_cjs.InterchangeIdentitySchema.optional()
9694
+ identity: chunk6GUBF5TF_cjs.InterchangeIdentitySchema.optional()
9644
9695
  });
9645
9696
  async function captureCandidateWriteSetTarget(target) {
9646
9697
  const activeSchema = await chunk6B3LQUYG_cjs.storeBackend(target).getActiveSchema(
@@ -9733,7 +9784,7 @@ async function planCandidateWriteSet(args) {
9733
9784
  }
9734
9785
  const candidate = created.data;
9735
9786
  try {
9736
- const imported = await chunkT3VU3YRQ_cjs.importGraph(
9787
+ const imported = await chunk6GUBF5TF_cjs.importGraph(
9737
9788
  candidate,
9738
9789
  interchangeDocument(writeSet),
9739
9790
  {
@@ -9833,7 +9884,7 @@ async function planCandidateWriteSetForEvolution(args) {
9833
9884
  }
9834
9885
  const candidate = created.data;
9835
9886
  try {
9836
- const imported = await chunkT3VU3YRQ_cjs.importGraph(
9887
+ const imported = await chunk6GUBF5TF_cjs.importGraph(
9837
9888
  candidate,
9838
9889
  interchangeDocument(writeSet),
9839
9890
  {
@@ -10479,6 +10530,7 @@ async function destroyDurableBranch(descriptor, strategy) {
10479
10530
  );
10480
10531
  return chunkHQU2SE74_cjs.ok(void 0);
10481
10532
  } catch (error) {
10533
+ if (error instanceof DurableEvidenceUndeliveredError) return chunkHQU2SE74_cjs.err(error);
10482
10534
  return chunkHQU2SE74_cjs.err(
10483
10535
  new BranchError(
10484
10536
  `Failed to destroy durable working copy for branch "${descriptor.branchId}": ${describeCause(error)}`,
@@ -10733,6 +10785,458 @@ async function applyDurableMergePlan(args) {
10733
10785
  );
10734
10786
  }
10735
10787
 
10788
+ // src/graph-merge/durable-operation.ts
10789
+ var DURABLE_OPERATION_SCAN_DEFAULT_LIMIT = 100;
10790
+ var DURABLE_OPERATION_SCAN_MAX_LIMIT = 1e3;
10791
+ var OPERATION_DIGEST_BYTE_LENGTH = 16;
10792
+ async function computeDurableOperationDigest(request) {
10793
+ const canonical = canonicalValueKey({
10794
+ metadata: request.metadata,
10795
+ mutation: request.mutation
10796
+ });
10797
+ return chunkZY4GXIVN_cjs.sha256Hex(canonical, OPERATION_DIGEST_BYTE_LENGTH);
10798
+ }
10799
+ function requireDescriptorOwner(descriptor, strategy) {
10800
+ const refusal = durableDescriptorRefusal(descriptor, strategy);
10801
+ if (refusal !== void 0) {
10802
+ return {
10803
+ ok: false,
10804
+ error: new DurableOperationRequestError(
10805
+ "Durable operation descriptor validation failed.",
10806
+ { cause: refusal }
10807
+ )
10808
+ };
10809
+ }
10810
+ return { ok: true, origin: durableOriginOfDescriptor(descriptor) };
10811
+ }
10812
+ async function normalizeOperationRequest(request) {
10813
+ const rawRequest = request;
10814
+ if (typeof rawRequest !== "object" || rawRequest === null || Array.isArray(rawRequest)) {
10815
+ return chunkHQU2SE74_cjs.err(
10816
+ new DurableOperationRequestError(
10817
+ "Durable operation request must be a JSON object."
10818
+ )
10819
+ );
10820
+ }
10821
+ if (typeof request.idempotencyKey !== "string" || request.idempotencyKey.length === 0) {
10822
+ return chunkHQU2SE74_cjs.err(
10823
+ new DurableOperationRequestError(
10824
+ "Durable operation request is malformed: idempotencyKey must be a non-empty string.",
10825
+ { details: { idempotencyKey: request.idempotencyKey } }
10826
+ )
10827
+ );
10828
+ }
10829
+ try {
10830
+ chunkJLSXOBLQ_cjs.assertJsonValue(request.metadata, "metadata", "Durable operation");
10831
+ chunkJLSXOBLQ_cjs.assertJsonValue(request.mutation, "mutation", "Durable operation");
10832
+ } catch (error) {
10833
+ return chunkHQU2SE74_cjs.err(
10834
+ new DurableOperationRequestError(
10835
+ `Durable operation request is not JSON-safe: ${describeCause(error)}`,
10836
+ { cause: error, details: { idempotencyKey: request.idempotencyKey } }
10837
+ )
10838
+ );
10839
+ }
10840
+ return chunkHQU2SE74_cjs.ok({
10841
+ idempotencyKey: request.idempotencyKey,
10842
+ metadata: request.metadata,
10843
+ mutation: request.mutation,
10844
+ operationDigest: await computeDurableOperationDigest(request)
10845
+ });
10846
+ }
10847
+ async function normalizeStoredEvidence(evidence, expectedIdempotencyKey) {
10848
+ if (typeof evidence !== "object" || evidence === null || Array.isArray(evidence)) {
10849
+ return chunkHQU2SE74_cjs.err(
10850
+ new DurableOperationEvidenceError(
10851
+ "Durable operation evidence must be a JSON object.",
10852
+ { details: { idempotencyKey: expectedIdempotencyKey } }
10853
+ )
10854
+ );
10855
+ }
10856
+ const record = evidence;
10857
+ if (typeof record["idempotencyKey"] !== "string" || record["idempotencyKey"].length === 0) {
10858
+ return chunkHQU2SE74_cjs.err(
10859
+ new DurableOperationEvidenceError(
10860
+ "Durable operation evidence needs a non-empty idempotency key.",
10861
+ { details: { expectedKey: expectedIdempotencyKey } }
10862
+ )
10863
+ );
10864
+ }
10865
+ if (expectedIdempotencyKey !== void 0 && record["idempotencyKey"] !== expectedIdempotencyKey) {
10866
+ return chunkHQU2SE74_cjs.err(
10867
+ new DurableOperationEvidenceError(
10868
+ "Durable operation evidence does not carry the requested idempotency key.",
10869
+ {
10870
+ details: {
10871
+ expectedKey: expectedIdempotencyKey,
10872
+ receivedKey: record["idempotencyKey"]
10873
+ }
10874
+ }
10875
+ )
10876
+ );
10877
+ }
10878
+ if (typeof record["operationDigest"] !== "string" || record["operationDigest"].length === 0) {
10879
+ return chunkHQU2SE74_cjs.err(
10880
+ new DurableOperationEvidenceError(
10881
+ "Durable operation evidence needs a non-empty operation digest.",
10882
+ { details: { idempotencyKey: record["idempotencyKey"] } }
10883
+ )
10884
+ );
10885
+ }
10886
+ try {
10887
+ chunkJLSXOBLQ_cjs.assertJsonValue(
10888
+ record["metadata"],
10889
+ "metadata",
10890
+ "Durable operation evidence"
10891
+ );
10892
+ chunkJLSXOBLQ_cjs.assertJsonValue(
10893
+ record["mutation"],
10894
+ "mutation",
10895
+ "Durable operation evidence"
10896
+ );
10897
+ } catch (error) {
10898
+ return chunkHQU2SE74_cjs.err(
10899
+ new DurableOperationEvidenceError(
10900
+ `Durable operation evidence content is not JSON-safe: ${describeCause(error)}`,
10901
+ { cause: error, details: { idempotencyKey: record["idempotencyKey"] } }
10902
+ )
10903
+ );
10904
+ }
10905
+ const refusal = validateCoordinates(record["before"], record, "before") ?? validateCoordinates(record["after"], record, "after") ?? (typeof record["delivered"] === "boolean" ? void 0 : new DurableOperationEvidenceError(
10906
+ "Durable operation evidence is missing its delivered flag.",
10907
+ { details: { idempotencyKey: record["idempotencyKey"] } }
10908
+ ));
10909
+ if (refusal !== void 0) return chunkHQU2SE74_cjs.err(refusal);
10910
+ const normalized = evidence;
10911
+ const canonicalDigest = await computeDurableOperationDigest(normalized);
10912
+ if (normalized.operationDigest !== canonicalDigest) {
10913
+ return chunkHQU2SE74_cjs.err(
10914
+ new DurableOperationEvidenceError(
10915
+ "Durable operation evidence digest disagrees with its canonical content.",
10916
+ {
10917
+ details: {
10918
+ idempotencyKey: normalized.idempotencyKey,
10919
+ expectedDigest: canonicalDigest,
10920
+ receivedDigest: normalized.operationDigest
10921
+ }
10922
+ }
10923
+ )
10924
+ );
10925
+ }
10926
+ return chunkHQU2SE74_cjs.ok(normalized);
10927
+ }
10928
+ async function validateEvidenceForOperation(evidence, expected) {
10929
+ const normalized = await normalizeStoredEvidence(
10930
+ evidence,
10931
+ expected.idempotencyKey
10932
+ );
10933
+ if (chunkHQU2SE74_cjs.isErr(normalized)) return normalized;
10934
+ if (normalized.data.operationDigest !== expected.operationDigest) {
10935
+ return chunkHQU2SE74_cjs.err(
10936
+ new DurableOperationEvidenceError(
10937
+ "Durable operation evidence digest disagrees with the canonical request digest.",
10938
+ {
10939
+ details: {
10940
+ idempotencyKey: expected.idempotencyKey,
10941
+ expectedDigest: expected.operationDigest,
10942
+ receivedDigest: normalized.data.operationDigest
10943
+ }
10944
+ }
10945
+ )
10946
+ );
10947
+ }
10948
+ if (canonicalValueKey(normalized.data.metadata) !== canonicalValueKey(expected.metadata) || canonicalValueKey(normalized.data.mutation) !== canonicalValueKey(expected.mutation)) {
10949
+ return chunkHQU2SE74_cjs.err(
10950
+ new DurableOperationEvidenceError(
10951
+ "Durable operation evidence does not echo the canonical request content.",
10952
+ { details: { idempotencyKey: expected.idempotencyKey } }
10953
+ )
10954
+ );
10955
+ }
10956
+ return normalized;
10957
+ }
10958
+ var DURABLE_OPERATION_UNSUPPORTED_DIMENSIONS = /* @__PURE__ */ new Set([
10959
+ "atomicMutation",
10960
+ "evidenceStore",
10961
+ "host"
10962
+ ]);
10963
+ function isDurableOperationUnsupportedDimension(value) {
10964
+ return typeof value === "string" && DURABLE_OPERATION_UNSUPPORTED_DIMENSIONS.has(
10965
+ value
10966
+ );
10967
+ }
10968
+ async function normalizeOperationOutcome(outcome, expected) {
10969
+ if (typeof outcome !== "object" || outcome === null || Array.isArray(outcome)) {
10970
+ return chunkHQU2SE74_cjs.err(
10971
+ new DurableOperationEvidenceError(
10972
+ "Durable operation host returned a malformed outcome envelope.",
10973
+ { details: { idempotencyKey: expected.idempotencyKey } }
10974
+ )
10975
+ );
10976
+ }
10977
+ const record = outcome;
10978
+ const outcomeKind = record["outcome"];
10979
+ if (outcomeKind === "unsupported") {
10980
+ const dimensions = record["dimensions"];
10981
+ const normalizedDimensions = Array.isArray(dimensions) ? dimensions.filter(
10982
+ (dimension) => isDurableOperationUnsupportedDimension(dimension)
10983
+ ) : [];
10984
+ const [firstDimension, ...remainingDimensions] = normalizedDimensions;
10985
+ if (!Array.isArray(dimensions) || firstDimension === void 0 || normalizedDimensions.length !== dimensions.length || new Set(normalizedDimensions).size !== normalizedDimensions.length) {
10986
+ return chunkHQU2SE74_cjs.err(
10987
+ new DurableOperationEvidenceError(
10988
+ "Durable operation host returned malformed unsupported dimensions.",
10989
+ { details: { idempotencyKey: expected.idempotencyKey } }
10990
+ )
10991
+ );
10992
+ }
10993
+ return chunkHQU2SE74_cjs.ok({
10994
+ outcome: "unsupported",
10995
+ dimensions: [firstDimension, ...remainingDimensions]
10996
+ });
10997
+ }
10998
+ if (outcomeKind !== "applied" && outcomeKind !== "replayed") {
10999
+ return chunkHQU2SE74_cjs.err(
11000
+ new DurableOperationEvidenceError(
11001
+ "Durable operation host returned an unknown outcome.",
11002
+ {
11003
+ details: {
11004
+ idempotencyKey: expected.idempotencyKey,
11005
+ outcome: outcomeKind
11006
+ }
11007
+ }
11008
+ )
11009
+ );
11010
+ }
11011
+ const evidence = await validateEvidenceForOperation(
11012
+ record["evidence"],
11013
+ expected
11014
+ );
11015
+ if (chunkHQU2SE74_cjs.isErr(evidence)) return evidence;
11016
+ if (outcomeKind === "applied" && evidence.data.delivered) {
11017
+ return chunkHQU2SE74_cjs.err(
11018
+ new DurableOperationEvidenceError(
11019
+ "Newly applied durable operation evidence must be undelivered.",
11020
+ { details: { idempotencyKey: expected.idempotencyKey } }
11021
+ )
11022
+ );
11023
+ }
11024
+ return chunkHQU2SE74_cjs.ok({ outcome: outcomeKind, evidence: evidence.data });
11025
+ }
11026
+ function validateCoordinates(coordinates, evidence, side) {
11027
+ const idempotencyKey = evidence["idempotencyKey"];
11028
+ if (typeof coordinates !== "object" || coordinates === null || Array.isArray(coordinates)) {
11029
+ return new DurableOperationEvidenceError(
11030
+ `Durable operation evidence ${side} coordinates are malformed.`,
11031
+ { details: { idempotencyKey, side } }
11032
+ );
11033
+ }
11034
+ const record = coordinates;
11035
+ if (typeof record["base"] !== "string" || record["base"].length === 0) {
11036
+ return new DurableOperationEvidenceError(
11037
+ `Durable operation evidence ${side} coordinates need a non-empty base.`,
11038
+ { details: { idempotencyKey, side } }
11039
+ );
11040
+ }
11041
+ if (record["revision"] !== void 0 && (typeof record["revision"] !== "string" || record["revision"].length === 0)) {
11042
+ return new DurableOperationEvidenceError(
11043
+ `Durable operation evidence ${side} coordinates revision must be a non-empty string.`,
11044
+ { details: { idempotencyKey, side } }
11045
+ );
11046
+ }
11047
+ return void 0;
11048
+ }
11049
+ function unsupportedError(member, strategyType) {
11050
+ return new DurableOperationUnsupportedError(
11051
+ `Durable strategy "${strategyType}" does not provide the "${member}" operation capability.`,
11052
+ {
11053
+ details: { strategyType, member },
11054
+ suggestion: "Use a strategy whose `operations` capability provides atomic mutation-plus-evidence and evidence access; TypeGraph never emulates the atomic guarantee."
11055
+ }
11056
+ );
11057
+ }
11058
+ async function operateDurableBranch(descriptor, strategy, request) {
11059
+ const owner = requireDescriptorOwner(descriptor, strategy);
11060
+ if (!owner.ok) return chunkHQU2SE74_cjs.err(owner.error);
11061
+ const normalized = await normalizeOperationRequest(request);
11062
+ if (chunkHQU2SE74_cjs.isErr(normalized)) return normalized;
11063
+ if (strategy.operations === void 0) {
11064
+ return chunkHQU2SE74_cjs.ok({
11065
+ outcome: "unsupported",
11066
+ dimensions: ["atomicMutation"]
11067
+ });
11068
+ }
11069
+ try {
11070
+ const outcome = await strategy.operations.operate({
11071
+ descriptor: descriptor.store,
11072
+ expectedOrigin: owner.origin,
11073
+ request: normalized.data
11074
+ });
11075
+ return await normalizeOperationOutcome(outcome, normalized.data);
11076
+ } catch (error) {
11077
+ return chunkHQU2SE74_cjs.err(
11078
+ error instanceof DurableOperationError ? error : new DurableOperationError(
11079
+ `Durable operation failed: ${describeCause(error)}`,
11080
+ {
11081
+ cause: error,
11082
+ details: { idempotencyKey: request.idempotencyKey }
11083
+ }
11084
+ )
11085
+ );
11086
+ }
11087
+ }
11088
+ async function getDurableOperation(descriptor, strategy, idempotencyKey) {
11089
+ const owner = requireDescriptorOwner(descriptor, strategy);
11090
+ if (!owner.ok) return chunkHQU2SE74_cjs.err(owner.error);
11091
+ if (strategy.operations === void 0) {
11092
+ return chunkHQU2SE74_cjs.err(unsupportedError("get", strategy.type));
11093
+ }
11094
+ try {
11095
+ const evidence = await strategy.operations.get({
11096
+ descriptor: descriptor.store,
11097
+ expectedOrigin: owner.origin,
11098
+ idempotencyKey
11099
+ });
11100
+ if (evidence === void 0) return chunkHQU2SE74_cjs.ok(void 0);
11101
+ return await normalizeStoredEvidence(evidence, idempotencyKey);
11102
+ } catch (error) {
11103
+ return chunkHQU2SE74_cjs.err(
11104
+ error instanceof DurableOperationError ? error : new DurableOperationError(
11105
+ `Failed to read durable operation "${idempotencyKey}": ${describeCause(error)}`,
11106
+ { cause: error, details: { idempotencyKey } }
11107
+ )
11108
+ );
11109
+ }
11110
+ }
11111
+ async function scanDurableOperations(descriptor, strategy, options = {}) {
11112
+ const owner = requireDescriptorOwner(descriptor, strategy);
11113
+ if (!owner.ok) return chunkHQU2SE74_cjs.err(owner.error);
11114
+ const limit = options.limit ?? DURABLE_OPERATION_SCAN_DEFAULT_LIMIT;
11115
+ if (!Number.isInteger(limit) || limit < 1) {
11116
+ return chunkHQU2SE74_cjs.err(
11117
+ new DurableOperationRequestError(
11118
+ "Durable operation scan limit must be a positive integer.",
11119
+ { details: { limit } }
11120
+ )
11121
+ );
11122
+ }
11123
+ if (limit > DURABLE_OPERATION_SCAN_MAX_LIMIT) {
11124
+ return chunkHQU2SE74_cjs.err(
11125
+ new DurableOperationRequestError(
11126
+ `Durable operation scan limit ${limit} exceeds the maximum of ${DURABLE_OPERATION_SCAN_MAX_LIMIT}.`,
11127
+ {
11128
+ details: { limit, max: DURABLE_OPERATION_SCAN_MAX_LIMIT },
11129
+ suggestion: `Request at most ${DURABLE_OPERATION_SCAN_MAX_LIMIT} operations per page and page with the returned cursor.`
11130
+ }
11131
+ )
11132
+ );
11133
+ }
11134
+ if (strategy.operations === void 0) {
11135
+ return chunkHQU2SE74_cjs.err(unsupportedError("scan", strategy.type));
11136
+ }
11137
+ try {
11138
+ const rawPage = await strategy.operations.scan({
11139
+ descriptor: descriptor.store,
11140
+ expectedOrigin: owner.origin,
11141
+ after: options.after,
11142
+ limit
11143
+ });
11144
+ if (typeof rawPage !== "object" || rawPage === null || Array.isArray(rawPage)) {
11145
+ return chunkHQU2SE74_cjs.err(
11146
+ new DurableOperationEvidenceError(
11147
+ "Durable operation scan returned a malformed page.",
11148
+ { details: { limit } }
11149
+ )
11150
+ );
11151
+ }
11152
+ const page = rawPage;
11153
+ const rawOperations = page["operations"];
11154
+ const cursor = page["cursor"];
11155
+ if (!Array.isArray(rawOperations) || rawOperations.length > limit || cursor !== void 0 && (typeof cursor !== "string" || cursor.length === 0)) {
11156
+ return chunkHQU2SE74_cjs.err(
11157
+ new DurableOperationEvidenceError(
11158
+ "Durable operation scan returned a malformed page.",
11159
+ { details: { limit } }
11160
+ )
11161
+ );
11162
+ }
11163
+ const operations = [];
11164
+ for (const evidence of rawOperations) {
11165
+ const normalized = await normalizeStoredEvidence(evidence);
11166
+ if (chunkHQU2SE74_cjs.isErr(normalized)) return normalized;
11167
+ operations.push(normalized.data);
11168
+ }
11169
+ return chunkHQU2SE74_cjs.ok(
11170
+ cursor === void 0 ? { operations } : { operations, cursor }
11171
+ );
11172
+ } catch (error) {
11173
+ return chunkHQU2SE74_cjs.err(
11174
+ error instanceof DurableOperationError ? error : new DurableOperationError(
11175
+ `Failed to scan durable operations: ${describeCause(error)}`,
11176
+ { cause: error, details: { limit } }
11177
+ )
11178
+ );
11179
+ }
11180
+ }
11181
+ async function markDurableOperationDelivered(descriptor, strategy, idempotencyKey) {
11182
+ const owner = requireDescriptorOwner(descriptor, strategy);
11183
+ if (!owner.ok) return chunkHQU2SE74_cjs.err(owner.error);
11184
+ if (strategy.operations === void 0) {
11185
+ return chunkHQU2SE74_cjs.err(unsupportedError("markDelivered", strategy.type));
11186
+ }
11187
+ try {
11188
+ const evidence = await strategy.operations.markDelivered({
11189
+ descriptor: descriptor.store,
11190
+ expectedOrigin: owner.origin,
11191
+ idempotencyKey
11192
+ });
11193
+ if (evidence === void 0) return chunkHQU2SE74_cjs.ok(void 0);
11194
+ const normalized = await normalizeStoredEvidence(evidence, idempotencyKey);
11195
+ if (chunkHQU2SE74_cjs.isErr(normalized)) return normalized;
11196
+ if (!normalized.data.delivered) {
11197
+ return chunkHQU2SE74_cjs.err(
11198
+ new DurableOperationEvidenceError(
11199
+ "Durable operation delivery marking returned undelivered evidence.",
11200
+ { details: { idempotencyKey } }
11201
+ )
11202
+ );
11203
+ }
11204
+ return normalized;
11205
+ } catch (error) {
11206
+ return chunkHQU2SE74_cjs.err(
11207
+ error instanceof DurableOperationError ? error : new DurableOperationError(
11208
+ `Failed to mark durable operation "${idempotencyKey}" delivered: ${describeCause(error)}`,
11209
+ { cause: error, details: { idempotencyKey } }
11210
+ )
11211
+ );
11212
+ }
11213
+ }
11214
+ async function durableBranchHasUndeliveredEvidence(descriptor, strategy) {
11215
+ const owner = requireDescriptorOwner(descriptor, strategy);
11216
+ if (!owner.ok) return chunkHQU2SE74_cjs.err(owner.error);
11217
+ if (strategy.operations === void 0) {
11218
+ return chunkHQU2SE74_cjs.err(unsupportedError("hasUndelivered", strategy.type));
11219
+ }
11220
+ try {
11221
+ const hasUndelivered = await strategy.operations.hasUndelivered({
11222
+ descriptor: descriptor.store,
11223
+ expectedOrigin: owner.origin
11224
+ });
11225
+ return typeof hasUndelivered === "boolean" ? chunkHQU2SE74_cjs.ok(hasUndelivered) : chunkHQU2SE74_cjs.err(
11226
+ new DurableOperationEvidenceError(
11227
+ "Durable operation undelivered query returned a non-boolean value."
11228
+ )
11229
+ );
11230
+ } catch (error) {
11231
+ return chunkHQU2SE74_cjs.err(
11232
+ error instanceof DurableOperationError ? error : new DurableOperationError(
11233
+ `Failed to query undelivered durable evidence: ${describeCause(error)}`,
11234
+ { cause: error }
11235
+ )
11236
+ );
11237
+ }
11238
+ }
11239
+
10736
11240
  // src/graph-merge/evolution-branch.ts
10737
11241
  async function branchForEvolution(store, plan, makeBackend, options) {
10738
11242
  try {
@@ -10769,6 +11273,14 @@ exports.CandidateSourceError = CandidateSourceError;
10769
11273
  exports.CandidateWriteSetError = CandidateWriteSetError;
10770
11274
  exports.CandidateWriteSetSchema = CandidateWriteSetSchema;
10771
11275
  exports.CandidateWriteSetTargetSchema = CandidateWriteSetTargetSchema;
11276
+ exports.DURABLE_OPERATION_SCAN_DEFAULT_LIMIT = DURABLE_OPERATION_SCAN_DEFAULT_LIMIT;
11277
+ exports.DURABLE_OPERATION_SCAN_MAX_LIMIT = DURABLE_OPERATION_SCAN_MAX_LIMIT;
11278
+ exports.DurableEvidenceUndeliveredError = DurableEvidenceUndeliveredError;
11279
+ exports.DurableOperationConflictError = DurableOperationConflictError;
11280
+ exports.DurableOperationError = DurableOperationError;
11281
+ exports.DurableOperationEvidenceError = DurableOperationEvidenceError;
11282
+ exports.DurableOperationRequestError = DurableOperationRequestError;
11283
+ exports.DurableOperationUnsupportedError = DurableOperationUnsupportedError;
10772
11284
  exports.IdentityMergeConflictError = IdentityMergeConflictError;
10773
11285
  exports.InvalidMergeOptionsError = InvalidMergeOptionsError;
10774
11286
  exports.InvalidMergePlanError = InvalidMergePlanError;
@@ -10804,13 +11316,18 @@ exports.captureCandidateWriteSetTarget = captureCandidateWriteSetTarget;
10804
11316
  exports.captureCandidateWriteSetTargetForEvolution = captureCandidateWriteSetTargetForEvolution;
10805
11317
  exports.cloneWorkingCopyStrategy = cloneWorkingCopyStrategy;
10806
11318
  exports.computeBaseVersion = computeBaseVersion;
11319
+ exports.computeDurableOperationDigest = computeDurableOperationDigest;
10807
11320
  exports.destroyDurableBranch = destroyDurableBranch;
11321
+ exports.durableBranchHasUndeliveredEvidence = durableBranchHasUndeliveredEvidence;
10808
11322
  exports.forkedWorkingCopyStrategy = forkedWorkingCopyStrategy;
11323
+ exports.getDurableOperation = getDurableOperation;
10809
11324
  exports.ingestionBranch = ingestionBranch;
11325
+ exports.markDurableOperationDelivered = markDurableOperationDelivered;
10810
11326
  exports.merge = merge;
10811
11327
  exports.mergeIncremental = mergeIncremental;
10812
11328
  exports.normalizeMergeOptions = normalizeMergeOptions;
10813
11329
  exports.openProvenanceStore = openProvenanceStore;
11330
+ exports.operateDurableBranch = operateDurableBranch;
10814
11331
  exports.persistProvenanceRecords = persistProvenanceRecords;
10815
11332
  exports.planCandidateWriteSet = planCandidateWriteSet;
10816
11333
  exports.planCandidateWriteSetForEvolution = planCandidateWriteSetForEvolution;
@@ -10822,5 +11339,6 @@ exports.provenanceGraphId = provenanceGraphId;
10822
11339
  exports.readProvenance = readProvenance;
10823
11340
  exports.reopenDurableBranch = reopenDurableBranch;
10824
11341
  exports.revalidateCandidateWriteSetReview = revalidateCandidateWriteSetReview;
11342
+ exports.scanDurableOperations = scanDurableOperations;
10825
11343
  //# sourceMappingURL=index.cjs.map
10826
11344
  //# sourceMappingURL=index.cjs.map