@nicia-ai/typegraph 0.66.1 → 0.67.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 (65) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +15 -0
  3. package/dist/backend/drizzle/engine/index.cjs +6 -6
  4. package/dist/backend/drizzle/engine/index.js +1 -1
  5. package/dist/backend/postgres/index.cjs +15 -15
  6. package/dist/backend/postgres/index.js +1 -1
  7. package/dist/backend/postgres/pglite-store.cjs +1 -1
  8. package/dist/backend/postgres/pglite-store.js +1 -1
  9. package/dist/backend/postgres/pglite.cjs +3 -3
  10. package/dist/backend/postgres/pglite.js +2 -2
  11. package/dist/backend/sqlite/index.cjs +14 -14
  12. package/dist/backend/sqlite/index.js +1 -1
  13. package/dist/backend/sqlite/libsql.cjs +6 -6
  14. package/dist/backend/sqlite/libsql.js +1 -1
  15. package/dist/backend/sqlite/local-store.cjs +1 -1
  16. package/dist/backend/sqlite/local-store.js +1 -1
  17. package/dist/backend/sqlite/local.cjs +3 -3
  18. package/dist/backend/sqlite/local.js +2 -2
  19. package/dist/{chunk-TR7QTODF.js → chunk-55DGFZYC.js} +3 -3
  20. package/dist/{chunk-TR7QTODF.js.map → chunk-55DGFZYC.js.map} +1 -1
  21. package/dist/{chunk-WB55URNM.js → chunk-6CKSTY2D.js} +7 -3
  22. package/dist/chunk-6CKSTY2D.js.map +1 -0
  23. package/dist/{chunk-ZONDBN6H.js → chunk-6DY26DPE.js} +3 -3
  24. package/dist/{chunk-ZONDBN6H.js.map → chunk-6DY26DPE.js.map} +1 -1
  25. package/dist/{chunk-YHMXF7OZ.js → chunk-6J3VUPI6.js} +3 -3
  26. package/dist/{chunk-YHMXF7OZ.js.map → chunk-6J3VUPI6.js.map} +1 -1
  27. package/dist/{chunk-MN325MG4.cjs → chunk-7MQL7FEN.cjs} +11 -2
  28. package/dist/chunk-7MQL7FEN.cjs.map +1 -0
  29. package/dist/{chunk-WWSYGZED.cjs → chunk-E6XL3KMZ.cjs} +6 -6
  30. package/dist/{chunk-WWSYGZED.cjs.map → chunk-E6XL3KMZ.cjs.map} +1 -1
  31. package/dist/{chunk-SSDHR2C2.js → chunk-EFSXK3DW.js} +3 -3
  32. package/dist/{chunk-SSDHR2C2.js.map → chunk-EFSXK3DW.js.map} +1 -1
  33. package/dist/{chunk-2DJKHZQ4.js → chunk-EORFWD6O.js} +11 -2
  34. package/dist/chunk-EORFWD6O.js.map +1 -0
  35. package/dist/{chunk-Y4X6ODVY.cjs → chunk-FS2GVO2T.cjs} +56 -56
  36. package/dist/{chunk-Y4X6ODVY.cjs.map → chunk-FS2GVO2T.cjs.map} +1 -1
  37. package/dist/{chunk-K7YACILO.cjs → chunk-GXHEGNI6.cjs} +9 -9
  38. package/dist/{chunk-K7YACILO.cjs.map → chunk-GXHEGNI6.cjs.map} +1 -1
  39. package/dist/{chunk-BX42F7IJ.cjs → chunk-SSDLQPMY.cjs} +7 -2
  40. package/dist/chunk-SSDLQPMY.cjs.map +1 -0
  41. package/dist/{chunk-ANMCKLZQ.cjs → chunk-ZRIXU33S.cjs} +12 -12
  42. package/dist/{chunk-ANMCKLZQ.cjs.map → chunk-ZRIXU33S.cjs.map} +1 -1
  43. package/dist/graph-merge/index.cjs +500 -26
  44. package/dist/graph-merge/index.cjs.map +1 -1
  45. package/dist/graph-merge/index.d.cts +384 -2
  46. package/dist/graph-merge/index.d.ts +384 -2
  47. package/dist/graph-merge/index.js +485 -15
  48. package/dist/graph-merge/index.js.map +1 -1
  49. package/dist/index.cjs +63 -63
  50. package/dist/index.js +3 -3
  51. package/dist/{local-store-impl-ERPNYOCL.js → local-store-impl-CCMWTLGY.js} +6 -6
  52. package/dist/{local-store-impl-ERPNYOCL.js.map → local-store-impl-CCMWTLGY.js.map} +1 -1
  53. package/dist/{local-store-impl-OUINMCYI.cjs → local-store-impl-GI6S4J6B.cjs} +9 -9
  54. package/dist/{local-store-impl-OUINMCYI.cjs.map → local-store-impl-GI6S4J6B.cjs.map} +1 -1
  55. package/dist/{pglite-store-impl-Z3SOOP75.cjs → pglite-store-impl-HAPAJUIO.cjs} +9 -9
  56. package/dist/{pglite-store-impl-Z3SOOP75.cjs.map → pglite-store-impl-HAPAJUIO.cjs.map} +1 -1
  57. package/dist/{pglite-store-impl-DUJBQZS5.js → pglite-store-impl-HDLFOZWS.js} +6 -6
  58. package/dist/{pglite-store-impl-DUJBQZS5.js.map → pglite-store-impl-HDLFOZWS.js.map} +1 -1
  59. package/dist/schema/index.cjs +27 -27
  60. package/dist/schema/index.js +2 -2
  61. package/package.json +1 -1
  62. package/dist/chunk-2DJKHZQ4.js.map +0 -1
  63. package/dist/chunk-BX42F7IJ.cjs.map +0 -1
  64. package/dist/chunk-MN325MG4.cjs.map +0 -1
  65. package/dist/chunk-WB55URNM.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkY4X6ODVY_cjs = require('../chunk-Y4X6ODVY.cjs');
3
+ var chunkFS2GVO2T_cjs = require('../chunk-FS2GVO2T.cjs');
4
4
  require('../chunk-76OB5RSH.cjs');
5
5
  var chunk3HMEGR7U_cjs = require('../chunk-3HMEGR7U.cjs');
6
6
  require('../chunk-2XQYRCPM.cjs');
@@ -11,7 +11,7 @@ require('../chunk-I7SBZJI2.cjs');
11
11
  require('../chunk-G7OKJDMG.cjs');
12
12
  require('../chunk-R255UE5U.cjs');
13
13
  require('../chunk-MRUOOAIQ.cjs');
14
- var chunkBX42F7IJ_cjs = require('../chunk-BX42F7IJ.cjs');
14
+ var chunkSSDLQPMY_cjs = require('../chunk-SSDLQPMY.cjs');
15
15
  require('../chunk-6YKISECL.cjs');
16
16
  var chunkICOTLZBV_cjs = require('../chunk-ICOTLZBV.cjs');
17
17
  var chunkEBQX7MYL_cjs = require('../chunk-EBQX7MYL.cjs');
@@ -1867,7 +1867,7 @@ async function computeSchemaComponent(store) {
1867
1867
  chunk6B3LQUYG_cjs.storeBackend(store),
1868
1868
  store.graphId
1869
1869
  );
1870
- return chunkBX42F7IJ_cjs.computeSchemaHash(chunkBX42F7IJ_cjs.serializeSchema(store.graph, version));
1870
+ return chunkSSDLQPMY_cjs.computeSchemaHash(chunkSSDLQPMY_cjs.serializeSchema(store.graph, version));
1871
1871
  }
1872
1872
  function byDigestEntry(left, right) {
1873
1873
  const byKind = chunkNYWU6CBZ_cjs.compareStrings(left.kind, right.kind);
@@ -2084,6 +2084,14 @@ async function lineageDeltaSinceAnchor(baseStore, base) {
2084
2084
 
2085
2085
  // src/graph-merge/working-copy.ts
2086
2086
  var CLONE_IMPORT_BATCH_SIZE = 1e3;
2087
+ async function assertWorkingCopyMatchesBase(workingCopy, base) {
2088
+ const workingCopyVersion = await computeBaseVersion(workingCopy);
2089
+ if (workingCopyVersion === base) return;
2090
+ throw new BranchError(
2091
+ "Working copy does not match its base: computeBaseVersion disagrees between the host-created store and the base store it was forked from. The host may have forked a different revision or the source may have advanced while the fork was being allocated.",
2092
+ { details: { workingCopyVersion, baseVersion: base } }
2093
+ );
2094
+ }
2087
2095
  function cloneWorkingCopyStrategy(makeBackend) {
2088
2096
  return cloneWorkingCopyWithGraphStrategy(
2089
2097
  makeBackend,
@@ -2101,7 +2109,7 @@ function cloneWorkingCopyWithGraphStrategy(makeBackend, graphForClone) {
2101
2109
  create: async (baseStore) => {
2102
2110
  const backend = await makeBackend();
2103
2111
  try {
2104
- const [freshStore] = await chunkY4X6ODVY_cjs.createStoreWithSchema(
2112
+ const [freshStore] = await chunkFS2GVO2T_cjs.createStoreWithSchema(
2105
2113
  graphForClone(baseStore),
2106
2114
  backend,
2107
2115
  {
@@ -2235,14 +2243,8 @@ function forkedWorkingCopyStrategy(options) {
2235
2243
  { details: { inheritedTables, connectedTables } }
2236
2244
  );
2237
2245
  }
2238
- const forkStore = chunkY4X6ODVY_cjs.createStore(baseStore.graph, backend, forkOptions);
2239
- const forkVersion = await computeBaseVersion(forkStore);
2240
- if (forkVersion !== base) {
2241
- throw new BranchError(
2242
- "Fork does not match its base: computeBaseVersion disagrees between the forked store and the base store it was forked from. This fence proves base-token equality (schema plus a revision anchor, or a live-content fingerprint) at the instant the fork was taken, not byte-for-byte physical identity \u2014 a working-copy fork is trusted to provide that.",
2243
- { details: { forkVersion, baseVersion: base } }
2244
- );
2245
- }
2246
+ const forkStore = chunkFS2GVO2T_cjs.createStore(baseStore.graph, backend, forkOptions);
2247
+ await assertWorkingCopyMatchesBase(forkStore, base);
2246
2248
  return forkStore;
2247
2249
  } catch (error) {
2248
2250
  try {
@@ -2305,11 +2307,7 @@ async function branch(baseStore, makeBackend, options, strategy) {
2305
2307
  }
2306
2308
  async function captureBranchForkState(store) {
2307
2309
  try {
2308
- const schemaRow = await chunk6B3LQUYG_cjs.storeBackend(store).getActiveSchema(store.graphId);
2309
- const schemaAnchor = schemaRow === void 0 ? void 0 : { version: schemaRow.version, hash: schemaRow.schema_hash };
2310
- const lineage = chunk6B3LQUYG_cjs.resolveLineage(store);
2311
- const forkRevision = lineage === void 0 ? void 0 : await lineage.revision(chunk6B3LQUYG_cjs.storeBackend(store));
2312
- return { schemaAnchor, forkRevision };
2310
+ return await readBranchForkState(store);
2313
2311
  } catch (error) {
2314
2312
  try {
2315
2313
  await chunk6B3LQUYG_cjs.storeBackend(store).close();
@@ -2318,6 +2316,13 @@ async function captureBranchForkState(store) {
2318
2316
  throw error;
2319
2317
  }
2320
2318
  }
2319
+ async function readBranchForkState(store) {
2320
+ const schemaRow = await chunk6B3LQUYG_cjs.storeBackend(store).getActiveSchema(store.graphId);
2321
+ const schemaAnchor = schemaRow === void 0 ? void 0 : { version: schemaRow.version, hash: schemaRow.schema_hash };
2322
+ const lineage = chunk6B3LQUYG_cjs.resolveLineage(store);
2323
+ const forkRevision = lineage === void 0 ? void 0 : await lineage.revision(chunk6B3LQUYG_cjs.storeBackend(store));
2324
+ return { schemaAnchor, forkRevision };
2325
+ }
2321
2326
 
2322
2327
  // src/graph-merge/evolution-target.ts
2323
2328
  function evolutionPlanningTarget(store, plan) {
@@ -2426,8 +2431,8 @@ async function assertMergeTransactionPristine(target, txBackend) {
2426
2431
 
2427
2432
  // src/graph-merge/apply-callbacks.ts
2428
2433
  var NODE_READ_NAMES = [
2429
- ...chunkY4X6ODVY_cjs.NODE_TEMPORAL_READ_NAMES,
2430
- ...chunkY4X6ODVY_cjs.CURRENT_ONLY_READ_NAMES
2434
+ ...chunkFS2GVO2T_cjs.NODE_TEMPORAL_READ_NAMES,
2435
+ ...chunkFS2GVO2T_cjs.CURRENT_ONLY_READ_NAMES
2431
2436
  ];
2432
2437
  function pickReadMethods(source, names) {
2433
2438
  return Object.fromEntries(names.map((name) => [name, source[name]]));
@@ -2445,12 +2450,12 @@ function mergePlanReadContext(tx, graph) {
2445
2450
  kind,
2446
2451
  pickReadMethods(
2447
2452
  chunkBXHAPCQG_cjs.requireDefined(tx.edges[kind]),
2448
- chunkY4X6ODVY_cjs.EDGE_TEMPORAL_READ_NAMES
2453
+ chunkFS2GVO2T_cjs.EDGE_TEMPORAL_READ_NAMES
2449
2454
  )
2450
2455
  ])
2451
2456
  ),
2452
2457
  ..."identity" in tx ? {
2453
- identity: pickReadMethods(tx.identity, chunkY4X6ODVY_cjs.IDENTITY_READ_NAMES)
2458
+ identity: pickReadMethods(tx.identity, chunkFS2GVO2T_cjs.IDENTITY_READ_NAMES)
2454
2459
  } : {}
2455
2460
  };
2456
2461
  }
@@ -5280,7 +5285,7 @@ async function openProvenanceStore(...args) {
5280
5285
  throw provenanceGraphIdCollision(graph.id, targetGraphId, claim.reason);
5281
5286
  }
5282
5287
  }
5283
- const [store] = await chunkY4X6ODVY_cjs.createStoreWithSchema(graph, backend);
5288
+ const [store] = await chunkFS2GVO2T_cjs.createStoreWithSchema(graph, backend);
5284
5289
  return store;
5285
5290
  }
5286
5291
  async function claimSidecarOwnership(backend, graph, targetGraphId) {
@@ -5350,14 +5355,14 @@ async function inspectSidecarGraphId(port, graph, targetGraphId) {
5350
5355
  if (activeSchema === void 0) {
5351
5356
  return { state: "refuse", reason: "application-graph" };
5352
5357
  }
5353
- const ownedHash = await chunkBX42F7IJ_cjs.computeSchemaHash(
5354
- chunkBX42F7IJ_cjs.serializeSchema(graph, activeSchema.version)
5358
+ const ownedHash = await chunkSSDLQPMY_cjs.computeSchemaHash(
5359
+ chunkSSDLQPMY_cjs.serializeSchema(graph, activeSchema.version)
5355
5360
  );
5356
5361
  if (activeSchema.schema_hash === ownedHash) {
5357
5362
  return { state: "refuse", reason: "unowned-exact-schema-graph" };
5358
5363
  }
5359
- const legacyHash = await chunkBX42F7IJ_cjs.computeSchemaHash(
5360
- chunkBX42F7IJ_cjs.serializeSchema(buildProvenanceGraph(targetGraphId), activeSchema.version)
5364
+ const legacyHash = await chunkSSDLQPMY_cjs.computeSchemaHash(
5365
+ chunkSSDLQPMY_cjs.serializeSchema(buildProvenanceGraph(targetGraphId), activeSchema.version)
5361
5366
  );
5362
5367
  if (activeSchema.schema_hash !== legacyHash) {
5363
5368
  return { state: "refuse", reason: "application-graph" };
@@ -10263,6 +10268,471 @@ function asReviewError(error) {
10263
10268
  );
10264
10269
  }
10265
10270
 
10271
+ // src/graph-merge/durable-branch.ts
10272
+ async function branchDurable(baseStore, strategy, options) {
10273
+ let base;
10274
+ let id;
10275
+ try {
10276
+ base = await computeBaseVersion(baseStore);
10277
+ id = options?.id ?? asBranchId(chunk6B3LQUYG_cjs.generateId());
10278
+ } catch (error) {
10279
+ return chunkHQU2SE74_cjs.err(
10280
+ new BranchError(
10281
+ "Failed to stamp the durable branch base version for the base store.",
10282
+ { cause: error }
10283
+ )
10284
+ );
10285
+ }
10286
+ let created;
10287
+ try {
10288
+ created = await strategy.create(baseStore, base, id);
10289
+ } catch (error) {
10290
+ return chunkHQU2SE74_cjs.err(
10291
+ new BranchError(
10292
+ "Failed to create durable working-copy branch of base store",
10293
+ { cause: error }
10294
+ )
10295
+ );
10296
+ }
10297
+ let forkState;
10298
+ let definitionHash;
10299
+ try {
10300
+ await assertDurableWorkingCopyMatchesBase(baseStore, created.store, base);
10301
+ forkState = await readBranchForkState(created.store);
10302
+ definitionHash = await chunkSSDLQPMY_cjs.getGraphDefinitionHash(created.store.graph);
10303
+ } catch (error) {
10304
+ return chunkHQU2SE74_cjs.err(await abandonAllocation(strategy, created, id, error));
10305
+ }
10306
+ const origin = {
10307
+ graphId: created.store.graphId,
10308
+ definitionHash,
10309
+ branchId: id,
10310
+ base,
10311
+ schemaAnchor: forkState.schemaAnchor,
10312
+ forkRevision: forkState.forkRevision
10313
+ };
10314
+ try {
10315
+ await strategy.seal(created.descriptor, origin);
10316
+ } catch (error) {
10317
+ return chunkHQU2SE74_cjs.err(await abandonAllocation(strategy, created, id, error));
10318
+ }
10319
+ const branch2 = {
10320
+ id,
10321
+ base,
10322
+ store: created.store,
10323
+ close: coalescedDurableClose(created.store, created.access),
10324
+ ...forkState.schemaAnchor === void 0 ? { schemaAnchor: void 0 } : { schemaAnchor: forkState.schemaAnchor },
10325
+ ...forkState.forkRevision === void 0 ? {} : { forkRevision: forkState.forkRevision }
10326
+ };
10327
+ const descriptor = {
10328
+ kind: strategy.type,
10329
+ version: strategy.version,
10330
+ graphId: created.store.graphId,
10331
+ definitionHash,
10332
+ branchId: id,
10333
+ base,
10334
+ store: created.descriptor,
10335
+ ...forkState.schemaAnchor === void 0 ? { schemaAnchor: void 0 } : { schemaAnchor: forkState.schemaAnchor },
10336
+ ...forkState.forkRevision === void 0 ? {} : { forkRevision: forkState.forkRevision }
10337
+ };
10338
+ return chunkHQU2SE74_cjs.ok({ branch: branch2, descriptor });
10339
+ }
10340
+ async function assertDurableWorkingCopyMatchesBase(baseStore, workingCopy, base) {
10341
+ const sourceVersionBeforeDiff = await computeBaseVersion(baseStore);
10342
+ if (sourceVersionBeforeDiff !== base) {
10343
+ throw new BranchError(
10344
+ "Base store changed while the durable working copy was being allocated.",
10345
+ {
10346
+ details: {
10347
+ baseVersion: base,
10348
+ liveBaseVersion: sourceVersionBeforeDiff
10349
+ }
10350
+ }
10351
+ );
10352
+ }
10353
+ if (workingCopy.graphId !== baseStore.graphId) {
10354
+ throw new BranchError(
10355
+ "Durable working copy belongs to a different graph than its base store.",
10356
+ {
10357
+ details: {
10358
+ expectedGraphId: baseStore.graphId,
10359
+ receivedGraphId: workingCopy.graphId
10360
+ }
10361
+ }
10362
+ );
10363
+ }
10364
+ const workingCopyVersion = await computeBaseVersion(workingCopy);
10365
+ if (workingCopyVersion === base) return;
10366
+ if (schemaComponentOf(workingCopyVersion) !== schemaComponentOf(base)) {
10367
+ throw new BranchError(
10368
+ "Durable working copy schema does not match its stamped base schema.",
10369
+ {
10370
+ details: {
10371
+ baseSchema: schemaComponentOf(base),
10372
+ workingCopySchema: schemaComponentOf(workingCopyVersion)
10373
+ }
10374
+ }
10375
+ );
10376
+ }
10377
+ const diff = await diffAgainstBase(baseStore, workingCopy, false);
10378
+ const sourceVersionAfterDiff = await computeBaseVersion(baseStore);
10379
+ if (sourceVersionAfterDiff !== base) {
10380
+ throw new BranchError(
10381
+ "Base store changed while the durable working copy was being verified.",
10382
+ {
10383
+ details: {
10384
+ baseVersion: base,
10385
+ liveBaseVersion: sourceVersionAfterDiff
10386
+ }
10387
+ }
10388
+ );
10389
+ }
10390
+ const changed = diff.nodes.new.length > 0 || diff.nodes.modified.length > 0 || diff.nodes.deleted.length > 0 || diff.nodes.windowed.length > 0 || diff.edges.new.length > 0 || diff.edges.modified.length > 0 || diff.edges.deleted.length > 0 || diff.edges.windowed.length > 0 || diff.identity.new.length > 0 || diff.identity.retracted.length > 0;
10391
+ if (!changed) return;
10392
+ throw new BranchError(
10393
+ "Durable working copy does not match its base: the stamped graph state differs.",
10394
+ {
10395
+ details: {
10396
+ baseVersion: base,
10397
+ workingCopyVersion,
10398
+ changedNodes: diff.nodes.new.length + diff.nodes.modified.length + diff.nodes.deleted.length + diff.nodes.windowed.length,
10399
+ changedEdges: diff.edges.new.length + diff.edges.modified.length + diff.edges.deleted.length + diff.edges.windowed.length,
10400
+ changedIdentityAssertions: diff.identity.new.length + diff.identity.retracted.length
10401
+ }
10402
+ }
10403
+ );
10404
+ }
10405
+ async function reopenDurableBranch(graph, descriptor, strategy) {
10406
+ const refusal = durableDescriptorRefusal(descriptor, strategy);
10407
+ if (refusal !== void 0) return chunkHQU2SE74_cjs.err(refusal);
10408
+ if (descriptor.graphId !== graph.id) {
10409
+ return chunkHQU2SE74_cjs.err(
10410
+ new BranchError(
10411
+ `Durable branch descriptor belongs to graph "${descriptor.graphId}", not "${graph.id}".`,
10412
+ {
10413
+ details: { descriptorGraphId: descriptor.graphId, graphId: graph.id }
10414
+ }
10415
+ )
10416
+ );
10417
+ }
10418
+ let reopened;
10419
+ try {
10420
+ reopened = await strategy.reopen(graph, descriptor.store);
10421
+ } catch (error) {
10422
+ return chunkHQU2SE74_cjs.err(
10423
+ new BranchError(
10424
+ `Failed to reopen durable working copy for branch "${descriptor.branchId}": ${describeCause(error)}`,
10425
+ {
10426
+ cause: error,
10427
+ details: { branchId: descriptor.branchId, graphId: graph.id },
10428
+ suggestion: "Confirm the persistent working copy still exists and is reachable by the strategy, then retry."
10429
+ }
10430
+ )
10431
+ );
10432
+ }
10433
+ const { access, store, origin } = reopened;
10434
+ try {
10435
+ if (store.graphId !== graph.id) {
10436
+ throw new BranchError(
10437
+ `Reopened working copy belongs to graph "${store.graphId}", not "${graph.id}".`,
10438
+ {
10439
+ details: {
10440
+ branchId: descriptor.branchId,
10441
+ reopenedGraphId: store.graphId,
10442
+ graphId: graph.id
10443
+ }
10444
+ }
10445
+ );
10446
+ }
10447
+ const descriptorOrigin = durableOriginOfDescriptor(descriptor);
10448
+ if (!durableOriginsEqual(descriptorOrigin, origin)) {
10449
+ throw new BranchError(
10450
+ `Durable branch descriptor does not match the working copy the host attested for its store locator: the descriptor's TypeGraph fences disagree with the origin recorded at fork. This is a tampered, relabeled, or wrong-branch descriptor.`,
10451
+ {
10452
+ details: {
10453
+ branchId: descriptor.branchId,
10454
+ descriptorOrigin,
10455
+ attestedOrigin: origin
10456
+ }
10457
+ }
10458
+ );
10459
+ }
10460
+ await assertGraphMatchesAttestedOrigin(graph, origin);
10461
+ return chunkHQU2SE74_cjs.ok(rebuildBranch(store, access, descriptor));
10462
+ } catch (error) {
10463
+ await closeDurableQuietly(store, access);
10464
+ return chunkHQU2SE74_cjs.err(
10465
+ error instanceof BranchError ? error : new BranchError(
10466
+ `Failed to reattach durable working copy for branch "${descriptor.branchId}": ${describeCause(error)}`,
10467
+ { cause: error, details: { branchId: descriptor.branchId } }
10468
+ )
10469
+ );
10470
+ }
10471
+ }
10472
+ async function destroyDurableBranch(descriptor, strategy) {
10473
+ const refusal = durableDescriptorRefusal(descriptor, strategy);
10474
+ if (refusal !== void 0) return chunkHQU2SE74_cjs.err(refusal);
10475
+ try {
10476
+ await strategy.destroy(
10477
+ descriptor.store,
10478
+ durableOriginOfDescriptor(descriptor)
10479
+ );
10480
+ return chunkHQU2SE74_cjs.ok(void 0);
10481
+ } catch (error) {
10482
+ return chunkHQU2SE74_cjs.err(
10483
+ new BranchError(
10484
+ `Failed to destroy durable working copy for branch "${descriptor.branchId}": ${describeCause(error)}`,
10485
+ { cause: error, details: { branchId: descriptor.branchId } }
10486
+ )
10487
+ );
10488
+ }
10489
+ }
10490
+ async function abandonAllocation(strategy, created, branchId, cause) {
10491
+ await closeDurableQuietly(created.store, created.access);
10492
+ let aborted = false;
10493
+ try {
10494
+ await strategy.abort(created.descriptor);
10495
+ aborted = true;
10496
+ } catch {
10497
+ }
10498
+ return new BranchError(
10499
+ aborted ? `Failed to finish durable working-copy branch "${branchId}" after the host allocated it; the opened store was closed and the persistent allocation was aborted.` : `Failed to finish durable working-copy branch "${branchId}" after the host allocated it; the opened store was closed, but the host could NOT abort the persistent allocation, which may survive as an orphan.`,
10500
+ {
10501
+ cause,
10502
+ details: {
10503
+ branchId,
10504
+ strategyType: strategy.type,
10505
+ allocationAborted: aborted
10506
+ },
10507
+ ...aborted ? {} : {
10508
+ suggestion: "The strategy's abort failed, so the persistent allocation for `details.branchId` may still exist. Inspect or remove it through the strategy's operator tooling."
10509
+ }
10510
+ }
10511
+ );
10512
+ }
10513
+ function durableDescriptorRefusal(descriptor, strategy) {
10514
+ if (typeof descriptor !== "object" || descriptor === null || Array.isArray(descriptor)) {
10515
+ return new BranchError("Durable branch descriptor must be a JSON object.", {
10516
+ details: { strategyType: strategy.type }
10517
+ });
10518
+ }
10519
+ const record = descriptor;
10520
+ if (record["kind"] !== strategy.type) {
10521
+ return new BranchError(
10522
+ `Durable branch descriptor belongs to strategy "${String(record["kind"])}", not "${strategy.type}".`,
10523
+ {
10524
+ details: {
10525
+ descriptorKind: record["kind"],
10526
+ strategyType: strategy.type
10527
+ }
10528
+ }
10529
+ );
10530
+ }
10531
+ if (record["version"] !== strategy.version) {
10532
+ return new BranchError(
10533
+ `Durable branch descriptor version ${String(record["version"])} is not supported by strategy "${strategy.type}" (expected ${strategy.version}).`,
10534
+ {
10535
+ details: {
10536
+ descriptorVersion: record["version"],
10537
+ strategyVersion: strategy.version
10538
+ }
10539
+ }
10540
+ );
10541
+ }
10542
+ for (const key of [
10543
+ "graphId",
10544
+ "definitionHash",
10545
+ "branchId",
10546
+ "base"
10547
+ ]) {
10548
+ const value = record[key];
10549
+ if (typeof value !== "string" || value.length === 0) {
10550
+ return new BranchError(
10551
+ `Durable branch descriptor is malformed: "${key}" must be a non-empty string.`,
10552
+ { details: { key, strategyType: strategy.type } }
10553
+ );
10554
+ }
10555
+ }
10556
+ if (!("store" in record)) {
10557
+ return new BranchError(
10558
+ "Durable branch descriptor is malformed: no strategy store locator.",
10559
+ { details: { strategyType: strategy.type } }
10560
+ );
10561
+ }
10562
+ if (record["schemaAnchor"] !== void 0) {
10563
+ const anchor = record["schemaAnchor"];
10564
+ if (typeof anchor !== "object" || anchor === null || typeof anchor["version"] !== "number" || typeof anchor["hash"] !== "string") {
10565
+ return new BranchError(
10566
+ "Durable branch descriptor is malformed: schemaAnchor must be { version: number; hash: string }.",
10567
+ { details: { strategyType: strategy.type } }
10568
+ );
10569
+ }
10570
+ }
10571
+ if (record["forkRevision"] !== void 0 && typeof record["forkRevision"] !== "string") {
10572
+ return new BranchError(
10573
+ "Durable branch descriptor is malformed: forkRevision must be a string.",
10574
+ { details: { strategyType: strategy.type } }
10575
+ );
10576
+ }
10577
+ return void 0;
10578
+ }
10579
+ function durableOriginOfDescriptor(descriptor) {
10580
+ return {
10581
+ graphId: descriptor.graphId,
10582
+ definitionHash: descriptor.definitionHash,
10583
+ branchId: descriptor.branchId,
10584
+ base: descriptor.base,
10585
+ schemaAnchor: descriptor.schemaAnchor,
10586
+ forkRevision: descriptor.forkRevision
10587
+ };
10588
+ }
10589
+ function durableOriginsEqual(descriptor, attested) {
10590
+ return descriptor.graphId === attested.graphId && descriptor.definitionHash === attested.definitionHash && descriptor.branchId === attested.branchId && descriptor.base === attested.base && schemaAnchorsEqual(descriptor.schemaAnchor, attested.schemaAnchor) && descriptor.forkRevision === attested.forkRevision;
10591
+ }
10592
+ function schemaAnchorsEqual(left, right) {
10593
+ if (left === void 0 || right === void 0) return left === right;
10594
+ return left.version === right.version && left.hash === right.hash;
10595
+ }
10596
+ async function assertGraphMatchesAttestedOrigin(graph, origin) {
10597
+ if (graph.id !== origin.graphId) {
10598
+ throw new BranchError(
10599
+ `The supplied graph "${graph.id}" is not the graph the durable working copy was forked from ("${origin.graphId}").`,
10600
+ {
10601
+ details: {
10602
+ graphId: graph.id,
10603
+ attestedGraphId: origin.graphId
10604
+ }
10605
+ }
10606
+ );
10607
+ }
10608
+ const graphHash = await chunkSSDLQPMY_cjs.getGraphDefinitionHash(graph);
10609
+ if (graphHash !== origin.definitionHash) {
10610
+ throw new BranchError(
10611
+ `The supplied graph definition is incompatible with the durable working copy's host-attested fork-time definition: it hashes differently, so it is a different graph definition even though it reuses graph id "${graph.id}". This identity check is attested independently of any committed schema anchor, so it also protects an unmanaged working copy.`,
10612
+ {
10613
+ details: {
10614
+ graphId: graph.id,
10615
+ attestedDefinitionHash: origin.definitionHash,
10616
+ graphHash
10617
+ }
10618
+ }
10619
+ );
10620
+ }
10621
+ }
10622
+ function rebuildBranch(store, access, descriptor) {
10623
+ return {
10624
+ id: descriptor.branchId,
10625
+ base: descriptor.base,
10626
+ store,
10627
+ close: coalescedDurableClose(store, access),
10628
+ schemaAnchor: descriptor.schemaAnchor,
10629
+ ...descriptor.forkRevision === void 0 ? {} : { forkRevision: descriptor.forkRevision }
10630
+ };
10631
+ }
10632
+ function coalescedDurableClose(store, access) {
10633
+ const closeBackend = coalescedWorkingCopyClose(store);
10634
+ let complete = false;
10635
+ let accessReleased = false;
10636
+ let inFlight;
10637
+ return async () => {
10638
+ if (complete) return;
10639
+ inFlight ??= (async () => {
10640
+ await closeBackend();
10641
+ if (access.kind === "exclusive" && !accessReleased) {
10642
+ await access.release();
10643
+ accessReleased = true;
10644
+ }
10645
+ complete = true;
10646
+ })().finally(() => {
10647
+ inFlight = void 0;
10648
+ });
10649
+ await inFlight;
10650
+ };
10651
+ }
10652
+ async function closeDurableQuietly(store, access) {
10653
+ try {
10654
+ await coalescedDurableClose(store, access)();
10655
+ } catch {
10656
+ }
10657
+ }
10658
+
10659
+ // src/graph-merge/durable-merge.ts
10660
+ async function applyDurableMergePlan(args) {
10661
+ const { branch: branch2, descriptor, plan, strategy, target } = args;
10662
+ const options = args.options ?? {};
10663
+ const refusal = durableDescriptorRefusal(descriptor, strategy);
10664
+ if (refusal !== void 0) {
10665
+ return chunkHQU2SE74_cjs.err(
10666
+ new MergeError("Durable merge descriptor validation failed.", {
10667
+ cause: refusal
10668
+ })
10669
+ );
10670
+ }
10671
+ let artifact;
10672
+ const descriptorOrigin = durableOriginOfDescriptor(descriptor);
10673
+ try {
10674
+ artifact = await validateMergePlanForTarget(target, plan);
10675
+ const branchOrigin = {
10676
+ graphId: branch2.store.graphId,
10677
+ definitionHash: await chunkSSDLQPMY_cjs.getGraphDefinitionHash(branch2.store.graph),
10678
+ branchId: branch2.id,
10679
+ base: branch2.base,
10680
+ schemaAnchor: branch2.schemaAnchor,
10681
+ forkRevision: branch2.forkRevision
10682
+ };
10683
+ if (!durableOriginsEqual(branchOrigin, descriptorOrigin)) {
10684
+ throw new MergeError(
10685
+ "The durable branch handle does not match the descriptor supplied for native merge.",
10686
+ {
10687
+ details: {
10688
+ branchOrigin,
10689
+ descriptorOrigin
10690
+ }
10691
+ }
10692
+ );
10693
+ }
10694
+ } catch (error) {
10695
+ return chunkHQU2SE74_cjs.err(
10696
+ error instanceof MergeError ? error : new MergeError(
10697
+ `Durable merge validation failed: ${describeCause(error)}`,
10698
+ { cause: error }
10699
+ )
10700
+ );
10701
+ }
10702
+ const usePortableApply = () => applyMergePlan(target, artifact, options);
10703
+ const hasCallbacks = options.beforeApply !== void 0 || options.afterApply !== void 0;
10704
+ if (strategy.merge === void 0 || hasCallbacks || artifact.provenance.persist) {
10705
+ return usePortableApply();
10706
+ }
10707
+ let nativeResult;
10708
+ try {
10709
+ nativeResult = await strategy.merge({
10710
+ target,
10711
+ branch: branch2,
10712
+ descriptor: descriptor.store,
10713
+ expectedOrigin: descriptorOrigin,
10714
+ plan: artifact
10715
+ });
10716
+ } catch (error) {
10717
+ return chunkHQU2SE74_cjs.err(
10718
+ new MergeError(
10719
+ `Host-native durable merge failed: ${describeCause(error)}`,
10720
+ {
10721
+ cause: error,
10722
+ suggestion: "Inspect the host-native merge state before retrying. TypeGraph does not run the portable fallback after an uncertain or failed native attempt because the host may have applied a partial change."
10723
+ }
10724
+ )
10725
+ );
10726
+ }
10727
+ if (nativeResult.outcome === "unsupported") return usePortableApply();
10728
+ return chunkHQU2SE74_cjs.ok(
10729
+ reportFromArtifact(artifact, nativeResult.merged, [
10730
+ ...artifact.review.warnings,
10731
+ ...nativeResult.warnings ?? []
10732
+ ])
10733
+ );
10734
+ }
10735
+
10266
10736
  // src/graph-merge/evolution-branch.ts
10267
10737
  async function branchForEvolution(store, plan, makeBackend, options) {
10268
10738
  try {
@@ -10322,16 +10792,19 @@ exports.SimilarityUnavailableError = SimilarityUnavailableError;
10322
10792
  exports.StaleMergePlanError = StaleMergePlanError;
10323
10793
  exports.UnsupportedMergePlanVersionError = UnsupportedMergePlanVersionError;
10324
10794
  exports.VALIDITY_END_TARGET_PRECEDENCE = VALIDITY_END_TARGET_PRECEDENCE;
10795
+ exports.applyDurableMergePlan = applyDurableMergePlan;
10325
10796
  exports.applyMergePlan = applyMergePlan;
10326
10797
  exports.applyMergePlanInTransaction = applyMergePlanInTransaction;
10327
10798
  exports.asBaseVersion = asBaseVersion;
10328
10799
  exports.asBranchId = asBranchId;
10329
10800
  exports.branch = branch;
10801
+ exports.branchDurable = branchDurable;
10330
10802
  exports.branchForEvolution = branchForEvolution;
10331
10803
  exports.captureCandidateWriteSetTarget = captureCandidateWriteSetTarget;
10332
10804
  exports.captureCandidateWriteSetTargetForEvolution = captureCandidateWriteSetTargetForEvolution;
10333
10805
  exports.cloneWorkingCopyStrategy = cloneWorkingCopyStrategy;
10334
10806
  exports.computeBaseVersion = computeBaseVersion;
10807
+ exports.destroyDurableBranch = destroyDurableBranch;
10335
10808
  exports.forkedWorkingCopyStrategy = forkedWorkingCopyStrategy;
10336
10809
  exports.ingestionBranch = ingestionBranch;
10337
10810
  exports.merge = merge;
@@ -10347,6 +10820,7 @@ exports.planMergeForEvolution = planMergeForEvolution;
10347
10820
  exports.planMergeIncremental = planMergeIncremental;
10348
10821
  exports.provenanceGraphId = provenanceGraphId;
10349
10822
  exports.readProvenance = readProvenance;
10823
+ exports.reopenDurableBranch = reopenDurableBranch;
10350
10824
  exports.revalidateCandidateWriteSetReview = revalidateCandidateWriteSetReview;
10351
10825
  //# sourceMappingURL=index.cjs.map
10352
10826
  //# sourceMappingURL=index.cjs.map