@nicia-ai/typegraph 0.67.1 → 0.68.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.
- package/CHANGELOG.md +18 -0
- package/dist/graph-merge/index.cjs +520 -2
- package/dist/graph-merge/index.cjs.map +1 -1
- package/dist/graph-merge/index.d.cts +298 -1
- package/dist/graph-merge/index.d.ts +298 -1
- package/dist/graph-merge/index.js +507 -3
- package/dist/graph-merge/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -39,7 +39,7 @@ import '../chunk-PC2UBAUB.js';
|
|
|
39
39
|
import { ok, err, isErr, computeTransitiveClosure, isReachable } from '../chunk-YIB2EVIL.js';
|
|
40
40
|
export { isErr, isOk, unwrap } from '../chunk-YIB2EVIL.js';
|
|
41
41
|
import { META_EDGE_EQUIVALENT_TO, META_EDGE_SAME_AS } from '../chunk-JXXDZTMN.js';
|
|
42
|
-
import '../chunk-OTJNUB6M.js';
|
|
42
|
+
import { assertJsonValue } from '../chunk-OTJNUB6M.js';
|
|
43
43
|
import { compareStrings, compareCodePoints } from '../chunk-CRVSZ7PA.js';
|
|
44
44
|
import '../chunk-LOVRELYJ.js';
|
|
45
45
|
import { createDataKeyedBag, hasOwnKey, requireDefined, readOwnProperty } from '../chunk-QD2JFTSL.js';
|
|
@@ -134,7 +134,13 @@ var MERGE_ERROR_CODES = {
|
|
|
134
134
|
candidateSource: "GRAPH_MERGE_CANDIDATE_SOURCE",
|
|
135
135
|
evidence: "GRAPH_MERGE_EVIDENCE",
|
|
136
136
|
candidateWriteSet: "GRAPH_MERGE_CANDIDATE_WRITE_SET",
|
|
137
|
-
review: "GRAPH_MERGE_REVIEW"
|
|
137
|
+
review: "GRAPH_MERGE_REVIEW",
|
|
138
|
+
operation: "GRAPH_MERGE_OPERATION",
|
|
139
|
+
operationRequest: "GRAPH_MERGE_OPERATION_REQUEST",
|
|
140
|
+
operationConflict: "GRAPH_MERGE_OPERATION_CONFLICT",
|
|
141
|
+
operationUnsupported: "GRAPH_MERGE_OPERATION_UNSUPPORTED",
|
|
142
|
+
operationEvidence: "GRAPH_MERGE_OPERATION_EVIDENCE",
|
|
143
|
+
operationUndelivered: "GRAPH_MERGE_OPERATION_UNDELIVERED"
|
|
138
144
|
};
|
|
139
145
|
function toTypeGraphErrorOptions(category, options) {
|
|
140
146
|
return {
|
|
@@ -341,6 +347,51 @@ var MatchEvidenceError = class extends MergeError {
|
|
|
341
347
|
this.name = "MatchEvidenceError";
|
|
342
348
|
}
|
|
343
349
|
};
|
|
350
|
+
var DurableOperationError = class extends MergeError {
|
|
351
|
+
code = MERGE_ERROR_CODES.operation;
|
|
352
|
+
constructor(message, options = {}) {
|
|
353
|
+
super(message, options);
|
|
354
|
+
this.name = "DurableOperationError";
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
var DurableOperationRequestError = class extends DurableOperationError {
|
|
358
|
+
static errorCategory = "user";
|
|
359
|
+
code = MERGE_ERROR_CODES.operationRequest;
|
|
360
|
+
constructor(message, options = {}) {
|
|
361
|
+
super(message, options);
|
|
362
|
+
this.name = "DurableOperationRequestError";
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
var DurableOperationConflictError = class extends DurableOperationError {
|
|
366
|
+
static errorCategory = "constraint";
|
|
367
|
+
code = MERGE_ERROR_CODES.operationConflict;
|
|
368
|
+
constructor(message, options = {}) {
|
|
369
|
+
super(message, options);
|
|
370
|
+
this.name = "DurableOperationConflictError";
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
var DurableOperationUnsupportedError = class extends DurableOperationError {
|
|
374
|
+
static errorCategory = "user";
|
|
375
|
+
code = MERGE_ERROR_CODES.operationUnsupported;
|
|
376
|
+
constructor(message, options = {}) {
|
|
377
|
+
super(message, options);
|
|
378
|
+
this.name = "DurableOperationUnsupportedError";
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
var DurableOperationEvidenceError = class extends DurableOperationError {
|
|
382
|
+
code = MERGE_ERROR_CODES.operationEvidence;
|
|
383
|
+
constructor(message, options = {}) {
|
|
384
|
+
super(message, options);
|
|
385
|
+
this.name = "DurableOperationEvidenceError";
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
var DurableEvidenceUndeliveredError = class extends BranchError {
|
|
389
|
+
code = MERGE_ERROR_CODES.operationUndelivered;
|
|
390
|
+
constructor(message, options = {}) {
|
|
391
|
+
super(message, options);
|
|
392
|
+
this.name = "DurableEvidenceUndeliveredError";
|
|
393
|
+
}
|
|
394
|
+
};
|
|
344
395
|
function describeCause(cause) {
|
|
345
396
|
return cause instanceof Error ? cause.message : String(cause);
|
|
346
397
|
}
|
|
@@ -10478,6 +10529,7 @@ async function destroyDurableBranch(descriptor, strategy) {
|
|
|
10478
10529
|
);
|
|
10479
10530
|
return ok(void 0);
|
|
10480
10531
|
} catch (error) {
|
|
10532
|
+
if (error instanceof DurableEvidenceUndeliveredError) return err(error);
|
|
10481
10533
|
return err(
|
|
10482
10534
|
new BranchError(
|
|
10483
10535
|
`Failed to destroy durable working copy for branch "${descriptor.branchId}": ${describeCause(error)}`,
|
|
@@ -10732,6 +10784,458 @@ async function applyDurableMergePlan(args) {
|
|
|
10732
10784
|
);
|
|
10733
10785
|
}
|
|
10734
10786
|
|
|
10787
|
+
// src/graph-merge/durable-operation.ts
|
|
10788
|
+
var DURABLE_OPERATION_SCAN_DEFAULT_LIMIT = 100;
|
|
10789
|
+
var DURABLE_OPERATION_SCAN_MAX_LIMIT = 1e3;
|
|
10790
|
+
var OPERATION_DIGEST_BYTE_LENGTH = 16;
|
|
10791
|
+
async function computeDurableOperationDigest(request) {
|
|
10792
|
+
const canonical = canonicalValueKey({
|
|
10793
|
+
metadata: request.metadata,
|
|
10794
|
+
mutation: request.mutation
|
|
10795
|
+
});
|
|
10796
|
+
return sha256Hex(canonical, OPERATION_DIGEST_BYTE_LENGTH);
|
|
10797
|
+
}
|
|
10798
|
+
function requireDescriptorOwner(descriptor, strategy) {
|
|
10799
|
+
const refusal = durableDescriptorRefusal(descriptor, strategy);
|
|
10800
|
+
if (refusal !== void 0) {
|
|
10801
|
+
return {
|
|
10802
|
+
ok: false,
|
|
10803
|
+
error: new DurableOperationRequestError(
|
|
10804
|
+
"Durable operation descriptor validation failed.",
|
|
10805
|
+
{ cause: refusal }
|
|
10806
|
+
)
|
|
10807
|
+
};
|
|
10808
|
+
}
|
|
10809
|
+
return { ok: true, origin: durableOriginOfDescriptor(descriptor) };
|
|
10810
|
+
}
|
|
10811
|
+
async function normalizeOperationRequest(request) {
|
|
10812
|
+
const rawRequest = request;
|
|
10813
|
+
if (typeof rawRequest !== "object" || rawRequest === null || Array.isArray(rawRequest)) {
|
|
10814
|
+
return err(
|
|
10815
|
+
new DurableOperationRequestError(
|
|
10816
|
+
"Durable operation request must be a JSON object."
|
|
10817
|
+
)
|
|
10818
|
+
);
|
|
10819
|
+
}
|
|
10820
|
+
if (typeof request.idempotencyKey !== "string" || request.idempotencyKey.length === 0) {
|
|
10821
|
+
return err(
|
|
10822
|
+
new DurableOperationRequestError(
|
|
10823
|
+
"Durable operation request is malformed: idempotencyKey must be a non-empty string.",
|
|
10824
|
+
{ details: { idempotencyKey: request.idempotencyKey } }
|
|
10825
|
+
)
|
|
10826
|
+
);
|
|
10827
|
+
}
|
|
10828
|
+
try {
|
|
10829
|
+
assertJsonValue(request.metadata, "metadata", "Durable operation");
|
|
10830
|
+
assertJsonValue(request.mutation, "mutation", "Durable operation");
|
|
10831
|
+
} catch (error) {
|
|
10832
|
+
return err(
|
|
10833
|
+
new DurableOperationRequestError(
|
|
10834
|
+
`Durable operation request is not JSON-safe: ${describeCause(error)}`,
|
|
10835
|
+
{ cause: error, details: { idempotencyKey: request.idempotencyKey } }
|
|
10836
|
+
)
|
|
10837
|
+
);
|
|
10838
|
+
}
|
|
10839
|
+
return ok({
|
|
10840
|
+
idempotencyKey: request.idempotencyKey,
|
|
10841
|
+
metadata: request.metadata,
|
|
10842
|
+
mutation: request.mutation,
|
|
10843
|
+
operationDigest: await computeDurableOperationDigest(request)
|
|
10844
|
+
});
|
|
10845
|
+
}
|
|
10846
|
+
async function normalizeStoredEvidence(evidence, expectedIdempotencyKey) {
|
|
10847
|
+
if (typeof evidence !== "object" || evidence === null || Array.isArray(evidence)) {
|
|
10848
|
+
return err(
|
|
10849
|
+
new DurableOperationEvidenceError(
|
|
10850
|
+
"Durable operation evidence must be a JSON object.",
|
|
10851
|
+
{ details: { idempotencyKey: expectedIdempotencyKey } }
|
|
10852
|
+
)
|
|
10853
|
+
);
|
|
10854
|
+
}
|
|
10855
|
+
const record = evidence;
|
|
10856
|
+
if (typeof record["idempotencyKey"] !== "string" || record["idempotencyKey"].length === 0) {
|
|
10857
|
+
return err(
|
|
10858
|
+
new DurableOperationEvidenceError(
|
|
10859
|
+
"Durable operation evidence needs a non-empty idempotency key.",
|
|
10860
|
+
{ details: { expectedKey: expectedIdempotencyKey } }
|
|
10861
|
+
)
|
|
10862
|
+
);
|
|
10863
|
+
}
|
|
10864
|
+
if (expectedIdempotencyKey !== void 0 && record["idempotencyKey"] !== expectedIdempotencyKey) {
|
|
10865
|
+
return err(
|
|
10866
|
+
new DurableOperationEvidenceError(
|
|
10867
|
+
"Durable operation evidence does not carry the requested idempotency key.",
|
|
10868
|
+
{
|
|
10869
|
+
details: {
|
|
10870
|
+
expectedKey: expectedIdempotencyKey,
|
|
10871
|
+
receivedKey: record["idempotencyKey"]
|
|
10872
|
+
}
|
|
10873
|
+
}
|
|
10874
|
+
)
|
|
10875
|
+
);
|
|
10876
|
+
}
|
|
10877
|
+
if (typeof record["operationDigest"] !== "string" || record["operationDigest"].length === 0) {
|
|
10878
|
+
return err(
|
|
10879
|
+
new DurableOperationEvidenceError(
|
|
10880
|
+
"Durable operation evidence needs a non-empty operation digest.",
|
|
10881
|
+
{ details: { idempotencyKey: record["idempotencyKey"] } }
|
|
10882
|
+
)
|
|
10883
|
+
);
|
|
10884
|
+
}
|
|
10885
|
+
try {
|
|
10886
|
+
assertJsonValue(
|
|
10887
|
+
record["metadata"],
|
|
10888
|
+
"metadata",
|
|
10889
|
+
"Durable operation evidence"
|
|
10890
|
+
);
|
|
10891
|
+
assertJsonValue(
|
|
10892
|
+
record["mutation"],
|
|
10893
|
+
"mutation",
|
|
10894
|
+
"Durable operation evidence"
|
|
10895
|
+
);
|
|
10896
|
+
} catch (error) {
|
|
10897
|
+
return err(
|
|
10898
|
+
new DurableOperationEvidenceError(
|
|
10899
|
+
`Durable operation evidence content is not JSON-safe: ${describeCause(error)}`,
|
|
10900
|
+
{ cause: error, details: { idempotencyKey: record["idempotencyKey"] } }
|
|
10901
|
+
)
|
|
10902
|
+
);
|
|
10903
|
+
}
|
|
10904
|
+
const refusal = validateCoordinates(record["before"], record, "before") ?? validateCoordinates(record["after"], record, "after") ?? (typeof record["delivered"] === "boolean" ? void 0 : new DurableOperationEvidenceError(
|
|
10905
|
+
"Durable operation evidence is missing its delivered flag.",
|
|
10906
|
+
{ details: { idempotencyKey: record["idempotencyKey"] } }
|
|
10907
|
+
));
|
|
10908
|
+
if (refusal !== void 0) return err(refusal);
|
|
10909
|
+
const normalized = evidence;
|
|
10910
|
+
const canonicalDigest = await computeDurableOperationDigest(normalized);
|
|
10911
|
+
if (normalized.operationDigest !== canonicalDigest) {
|
|
10912
|
+
return err(
|
|
10913
|
+
new DurableOperationEvidenceError(
|
|
10914
|
+
"Durable operation evidence digest disagrees with its canonical content.",
|
|
10915
|
+
{
|
|
10916
|
+
details: {
|
|
10917
|
+
idempotencyKey: normalized.idempotencyKey,
|
|
10918
|
+
expectedDigest: canonicalDigest,
|
|
10919
|
+
receivedDigest: normalized.operationDigest
|
|
10920
|
+
}
|
|
10921
|
+
}
|
|
10922
|
+
)
|
|
10923
|
+
);
|
|
10924
|
+
}
|
|
10925
|
+
return ok(normalized);
|
|
10926
|
+
}
|
|
10927
|
+
async function validateEvidenceForOperation(evidence, expected) {
|
|
10928
|
+
const normalized = await normalizeStoredEvidence(
|
|
10929
|
+
evidence,
|
|
10930
|
+
expected.idempotencyKey
|
|
10931
|
+
);
|
|
10932
|
+
if (isErr(normalized)) return normalized;
|
|
10933
|
+
if (normalized.data.operationDigest !== expected.operationDigest) {
|
|
10934
|
+
return err(
|
|
10935
|
+
new DurableOperationEvidenceError(
|
|
10936
|
+
"Durable operation evidence digest disagrees with the canonical request digest.",
|
|
10937
|
+
{
|
|
10938
|
+
details: {
|
|
10939
|
+
idempotencyKey: expected.idempotencyKey,
|
|
10940
|
+
expectedDigest: expected.operationDigest,
|
|
10941
|
+
receivedDigest: normalized.data.operationDigest
|
|
10942
|
+
}
|
|
10943
|
+
}
|
|
10944
|
+
)
|
|
10945
|
+
);
|
|
10946
|
+
}
|
|
10947
|
+
if (canonicalValueKey(normalized.data.metadata) !== canonicalValueKey(expected.metadata) || canonicalValueKey(normalized.data.mutation) !== canonicalValueKey(expected.mutation)) {
|
|
10948
|
+
return err(
|
|
10949
|
+
new DurableOperationEvidenceError(
|
|
10950
|
+
"Durable operation evidence does not echo the canonical request content.",
|
|
10951
|
+
{ details: { idempotencyKey: expected.idempotencyKey } }
|
|
10952
|
+
)
|
|
10953
|
+
);
|
|
10954
|
+
}
|
|
10955
|
+
return normalized;
|
|
10956
|
+
}
|
|
10957
|
+
var DURABLE_OPERATION_UNSUPPORTED_DIMENSIONS = /* @__PURE__ */ new Set([
|
|
10958
|
+
"atomicMutation",
|
|
10959
|
+
"evidenceStore",
|
|
10960
|
+
"host"
|
|
10961
|
+
]);
|
|
10962
|
+
function isDurableOperationUnsupportedDimension(value) {
|
|
10963
|
+
return typeof value === "string" && DURABLE_OPERATION_UNSUPPORTED_DIMENSIONS.has(
|
|
10964
|
+
value
|
|
10965
|
+
);
|
|
10966
|
+
}
|
|
10967
|
+
async function normalizeOperationOutcome(outcome, expected) {
|
|
10968
|
+
if (typeof outcome !== "object" || outcome === null || Array.isArray(outcome)) {
|
|
10969
|
+
return err(
|
|
10970
|
+
new DurableOperationEvidenceError(
|
|
10971
|
+
"Durable operation host returned a malformed outcome envelope.",
|
|
10972
|
+
{ details: { idempotencyKey: expected.idempotencyKey } }
|
|
10973
|
+
)
|
|
10974
|
+
);
|
|
10975
|
+
}
|
|
10976
|
+
const record = outcome;
|
|
10977
|
+
const outcomeKind = record["outcome"];
|
|
10978
|
+
if (outcomeKind === "unsupported") {
|
|
10979
|
+
const dimensions = record["dimensions"];
|
|
10980
|
+
const normalizedDimensions = Array.isArray(dimensions) ? dimensions.filter(
|
|
10981
|
+
(dimension) => isDurableOperationUnsupportedDimension(dimension)
|
|
10982
|
+
) : [];
|
|
10983
|
+
const [firstDimension, ...remainingDimensions] = normalizedDimensions;
|
|
10984
|
+
if (!Array.isArray(dimensions) || firstDimension === void 0 || normalizedDimensions.length !== dimensions.length || new Set(normalizedDimensions).size !== normalizedDimensions.length) {
|
|
10985
|
+
return err(
|
|
10986
|
+
new DurableOperationEvidenceError(
|
|
10987
|
+
"Durable operation host returned malformed unsupported dimensions.",
|
|
10988
|
+
{ details: { idempotencyKey: expected.idempotencyKey } }
|
|
10989
|
+
)
|
|
10990
|
+
);
|
|
10991
|
+
}
|
|
10992
|
+
return ok({
|
|
10993
|
+
outcome: "unsupported",
|
|
10994
|
+
dimensions: [firstDimension, ...remainingDimensions]
|
|
10995
|
+
});
|
|
10996
|
+
}
|
|
10997
|
+
if (outcomeKind !== "applied" && outcomeKind !== "replayed") {
|
|
10998
|
+
return err(
|
|
10999
|
+
new DurableOperationEvidenceError(
|
|
11000
|
+
"Durable operation host returned an unknown outcome.",
|
|
11001
|
+
{
|
|
11002
|
+
details: {
|
|
11003
|
+
idempotencyKey: expected.idempotencyKey,
|
|
11004
|
+
outcome: outcomeKind
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
11007
|
+
)
|
|
11008
|
+
);
|
|
11009
|
+
}
|
|
11010
|
+
const evidence = await validateEvidenceForOperation(
|
|
11011
|
+
record["evidence"],
|
|
11012
|
+
expected
|
|
11013
|
+
);
|
|
11014
|
+
if (isErr(evidence)) return evidence;
|
|
11015
|
+
if (outcomeKind === "applied" && evidence.data.delivered) {
|
|
11016
|
+
return err(
|
|
11017
|
+
new DurableOperationEvidenceError(
|
|
11018
|
+
"Newly applied durable operation evidence must be undelivered.",
|
|
11019
|
+
{ details: { idempotencyKey: expected.idempotencyKey } }
|
|
11020
|
+
)
|
|
11021
|
+
);
|
|
11022
|
+
}
|
|
11023
|
+
return ok({ outcome: outcomeKind, evidence: evidence.data });
|
|
11024
|
+
}
|
|
11025
|
+
function validateCoordinates(coordinates, evidence, side) {
|
|
11026
|
+
const idempotencyKey = evidence["idempotencyKey"];
|
|
11027
|
+
if (typeof coordinates !== "object" || coordinates === null || Array.isArray(coordinates)) {
|
|
11028
|
+
return new DurableOperationEvidenceError(
|
|
11029
|
+
`Durable operation evidence ${side} coordinates are malformed.`,
|
|
11030
|
+
{ details: { idempotencyKey, side } }
|
|
11031
|
+
);
|
|
11032
|
+
}
|
|
11033
|
+
const record = coordinates;
|
|
11034
|
+
if (typeof record["base"] !== "string" || record["base"].length === 0) {
|
|
11035
|
+
return new DurableOperationEvidenceError(
|
|
11036
|
+
`Durable operation evidence ${side} coordinates need a non-empty base.`,
|
|
11037
|
+
{ details: { idempotencyKey, side } }
|
|
11038
|
+
);
|
|
11039
|
+
}
|
|
11040
|
+
if (record["revision"] !== void 0 && (typeof record["revision"] !== "string" || record["revision"].length === 0)) {
|
|
11041
|
+
return new DurableOperationEvidenceError(
|
|
11042
|
+
`Durable operation evidence ${side} coordinates revision must be a non-empty string.`,
|
|
11043
|
+
{ details: { idempotencyKey, side } }
|
|
11044
|
+
);
|
|
11045
|
+
}
|
|
11046
|
+
return void 0;
|
|
11047
|
+
}
|
|
11048
|
+
function unsupportedError(member, strategyType) {
|
|
11049
|
+
return new DurableOperationUnsupportedError(
|
|
11050
|
+
`Durable strategy "${strategyType}" does not provide the "${member}" operation capability.`,
|
|
11051
|
+
{
|
|
11052
|
+
details: { strategyType, member },
|
|
11053
|
+
suggestion: "Use a strategy whose `operations` capability provides atomic mutation-plus-evidence and evidence access; TypeGraph never emulates the atomic guarantee."
|
|
11054
|
+
}
|
|
11055
|
+
);
|
|
11056
|
+
}
|
|
11057
|
+
async function operateDurableBranch(descriptor, strategy, request) {
|
|
11058
|
+
const owner = requireDescriptorOwner(descriptor, strategy);
|
|
11059
|
+
if (!owner.ok) return err(owner.error);
|
|
11060
|
+
const normalized = await normalizeOperationRequest(request);
|
|
11061
|
+
if (isErr(normalized)) return normalized;
|
|
11062
|
+
if (strategy.operations === void 0) {
|
|
11063
|
+
return ok({
|
|
11064
|
+
outcome: "unsupported",
|
|
11065
|
+
dimensions: ["atomicMutation"]
|
|
11066
|
+
});
|
|
11067
|
+
}
|
|
11068
|
+
try {
|
|
11069
|
+
const outcome = await strategy.operations.operate({
|
|
11070
|
+
descriptor: descriptor.store,
|
|
11071
|
+
expectedOrigin: owner.origin,
|
|
11072
|
+
request: normalized.data
|
|
11073
|
+
});
|
|
11074
|
+
return await normalizeOperationOutcome(outcome, normalized.data);
|
|
11075
|
+
} catch (error) {
|
|
11076
|
+
return err(
|
|
11077
|
+
error instanceof DurableOperationError ? error : new DurableOperationError(
|
|
11078
|
+
`Durable operation failed: ${describeCause(error)}`,
|
|
11079
|
+
{
|
|
11080
|
+
cause: error,
|
|
11081
|
+
details: { idempotencyKey: request.idempotencyKey }
|
|
11082
|
+
}
|
|
11083
|
+
)
|
|
11084
|
+
);
|
|
11085
|
+
}
|
|
11086
|
+
}
|
|
11087
|
+
async function getDurableOperation(descriptor, strategy, idempotencyKey) {
|
|
11088
|
+
const owner = requireDescriptorOwner(descriptor, strategy);
|
|
11089
|
+
if (!owner.ok) return err(owner.error);
|
|
11090
|
+
if (strategy.operations === void 0) {
|
|
11091
|
+
return err(unsupportedError("get", strategy.type));
|
|
11092
|
+
}
|
|
11093
|
+
try {
|
|
11094
|
+
const evidence = await strategy.operations.get({
|
|
11095
|
+
descriptor: descriptor.store,
|
|
11096
|
+
expectedOrigin: owner.origin,
|
|
11097
|
+
idempotencyKey
|
|
11098
|
+
});
|
|
11099
|
+
if (evidence === void 0) return ok(void 0);
|
|
11100
|
+
return await normalizeStoredEvidence(evidence, idempotencyKey);
|
|
11101
|
+
} catch (error) {
|
|
11102
|
+
return err(
|
|
11103
|
+
error instanceof DurableOperationError ? error : new DurableOperationError(
|
|
11104
|
+
`Failed to read durable operation "${idempotencyKey}": ${describeCause(error)}`,
|
|
11105
|
+
{ cause: error, details: { idempotencyKey } }
|
|
11106
|
+
)
|
|
11107
|
+
);
|
|
11108
|
+
}
|
|
11109
|
+
}
|
|
11110
|
+
async function scanDurableOperations(descriptor, strategy, options = {}) {
|
|
11111
|
+
const owner = requireDescriptorOwner(descriptor, strategy);
|
|
11112
|
+
if (!owner.ok) return err(owner.error);
|
|
11113
|
+
const limit = options.limit ?? DURABLE_OPERATION_SCAN_DEFAULT_LIMIT;
|
|
11114
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
11115
|
+
return err(
|
|
11116
|
+
new DurableOperationRequestError(
|
|
11117
|
+
"Durable operation scan limit must be a positive integer.",
|
|
11118
|
+
{ details: { limit } }
|
|
11119
|
+
)
|
|
11120
|
+
);
|
|
11121
|
+
}
|
|
11122
|
+
if (limit > DURABLE_OPERATION_SCAN_MAX_LIMIT) {
|
|
11123
|
+
return err(
|
|
11124
|
+
new DurableOperationRequestError(
|
|
11125
|
+
`Durable operation scan limit ${limit} exceeds the maximum of ${DURABLE_OPERATION_SCAN_MAX_LIMIT}.`,
|
|
11126
|
+
{
|
|
11127
|
+
details: { limit, max: DURABLE_OPERATION_SCAN_MAX_LIMIT },
|
|
11128
|
+
suggestion: `Request at most ${DURABLE_OPERATION_SCAN_MAX_LIMIT} operations per page and page with the returned cursor.`
|
|
11129
|
+
}
|
|
11130
|
+
)
|
|
11131
|
+
);
|
|
11132
|
+
}
|
|
11133
|
+
if (strategy.operations === void 0) {
|
|
11134
|
+
return err(unsupportedError("scan", strategy.type));
|
|
11135
|
+
}
|
|
11136
|
+
try {
|
|
11137
|
+
const rawPage = await strategy.operations.scan({
|
|
11138
|
+
descriptor: descriptor.store,
|
|
11139
|
+
expectedOrigin: owner.origin,
|
|
11140
|
+
after: options.after,
|
|
11141
|
+
limit
|
|
11142
|
+
});
|
|
11143
|
+
if (typeof rawPage !== "object" || rawPage === null || Array.isArray(rawPage)) {
|
|
11144
|
+
return err(
|
|
11145
|
+
new DurableOperationEvidenceError(
|
|
11146
|
+
"Durable operation scan returned a malformed page.",
|
|
11147
|
+
{ details: { limit } }
|
|
11148
|
+
)
|
|
11149
|
+
);
|
|
11150
|
+
}
|
|
11151
|
+
const page = rawPage;
|
|
11152
|
+
const rawOperations = page["operations"];
|
|
11153
|
+
const cursor = page["cursor"];
|
|
11154
|
+
if (!Array.isArray(rawOperations) || rawOperations.length > limit || cursor !== void 0 && (typeof cursor !== "string" || cursor.length === 0)) {
|
|
11155
|
+
return err(
|
|
11156
|
+
new DurableOperationEvidenceError(
|
|
11157
|
+
"Durable operation scan returned a malformed page.",
|
|
11158
|
+
{ details: { limit } }
|
|
11159
|
+
)
|
|
11160
|
+
);
|
|
11161
|
+
}
|
|
11162
|
+
const operations = [];
|
|
11163
|
+
for (const evidence of rawOperations) {
|
|
11164
|
+
const normalized = await normalizeStoredEvidence(evidence);
|
|
11165
|
+
if (isErr(normalized)) return normalized;
|
|
11166
|
+
operations.push(normalized.data);
|
|
11167
|
+
}
|
|
11168
|
+
return ok(
|
|
11169
|
+
cursor === void 0 ? { operations } : { operations, cursor }
|
|
11170
|
+
);
|
|
11171
|
+
} catch (error) {
|
|
11172
|
+
return err(
|
|
11173
|
+
error instanceof DurableOperationError ? error : new DurableOperationError(
|
|
11174
|
+
`Failed to scan durable operations: ${describeCause(error)}`,
|
|
11175
|
+
{ cause: error, details: { limit } }
|
|
11176
|
+
)
|
|
11177
|
+
);
|
|
11178
|
+
}
|
|
11179
|
+
}
|
|
11180
|
+
async function markDurableOperationDelivered(descriptor, strategy, idempotencyKey) {
|
|
11181
|
+
const owner = requireDescriptorOwner(descriptor, strategy);
|
|
11182
|
+
if (!owner.ok) return err(owner.error);
|
|
11183
|
+
if (strategy.operations === void 0) {
|
|
11184
|
+
return err(unsupportedError("markDelivered", strategy.type));
|
|
11185
|
+
}
|
|
11186
|
+
try {
|
|
11187
|
+
const evidence = await strategy.operations.markDelivered({
|
|
11188
|
+
descriptor: descriptor.store,
|
|
11189
|
+
expectedOrigin: owner.origin,
|
|
11190
|
+
idempotencyKey
|
|
11191
|
+
});
|
|
11192
|
+
if (evidence === void 0) return ok(void 0);
|
|
11193
|
+
const normalized = await normalizeStoredEvidence(evidence, idempotencyKey);
|
|
11194
|
+
if (isErr(normalized)) return normalized;
|
|
11195
|
+
if (!normalized.data.delivered) {
|
|
11196
|
+
return err(
|
|
11197
|
+
new DurableOperationEvidenceError(
|
|
11198
|
+
"Durable operation delivery marking returned undelivered evidence.",
|
|
11199
|
+
{ details: { idempotencyKey } }
|
|
11200
|
+
)
|
|
11201
|
+
);
|
|
11202
|
+
}
|
|
11203
|
+
return normalized;
|
|
11204
|
+
} catch (error) {
|
|
11205
|
+
return err(
|
|
11206
|
+
error instanceof DurableOperationError ? error : new DurableOperationError(
|
|
11207
|
+
`Failed to mark durable operation "${idempotencyKey}" delivered: ${describeCause(error)}`,
|
|
11208
|
+
{ cause: error, details: { idempotencyKey } }
|
|
11209
|
+
)
|
|
11210
|
+
);
|
|
11211
|
+
}
|
|
11212
|
+
}
|
|
11213
|
+
async function durableBranchHasUndeliveredEvidence(descriptor, strategy) {
|
|
11214
|
+
const owner = requireDescriptorOwner(descriptor, strategy);
|
|
11215
|
+
if (!owner.ok) return err(owner.error);
|
|
11216
|
+
if (strategy.operations === void 0) {
|
|
11217
|
+
return err(unsupportedError("hasUndelivered", strategy.type));
|
|
11218
|
+
}
|
|
11219
|
+
try {
|
|
11220
|
+
const hasUndelivered = await strategy.operations.hasUndelivered({
|
|
11221
|
+
descriptor: descriptor.store,
|
|
11222
|
+
expectedOrigin: owner.origin
|
|
11223
|
+
});
|
|
11224
|
+
return typeof hasUndelivered === "boolean" ? ok(hasUndelivered) : err(
|
|
11225
|
+
new DurableOperationEvidenceError(
|
|
11226
|
+
"Durable operation undelivered query returned a non-boolean value."
|
|
11227
|
+
)
|
|
11228
|
+
);
|
|
11229
|
+
} catch (error) {
|
|
11230
|
+
return err(
|
|
11231
|
+
error instanceof DurableOperationError ? error : new DurableOperationError(
|
|
11232
|
+
`Failed to query undelivered durable evidence: ${describeCause(error)}`,
|
|
11233
|
+
{ cause: error }
|
|
11234
|
+
)
|
|
11235
|
+
);
|
|
11236
|
+
}
|
|
11237
|
+
}
|
|
11238
|
+
|
|
10735
11239
|
// src/graph-merge/evolution-branch.ts
|
|
10736
11240
|
async function branchForEvolution(store, plan, makeBackend, options) {
|
|
10737
11241
|
try {
|
|
@@ -10749,6 +11253,6 @@ async function branchForEvolution(store, plan, makeBackend, options) {
|
|
|
10749
11253
|
}
|
|
10750
11254
|
}
|
|
10751
11255
|
|
|
10752
|
-
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, applyDurableMergePlan, applyMergePlan, applyMergePlanInTransaction, asBaseVersion, asBranchId, branch, branchDurable, branchForEvolution, captureCandidateWriteSetTarget, captureCandidateWriteSetTargetForEvolution, cloneWorkingCopyStrategy, computeBaseVersion, destroyDurableBranch, forkedWorkingCopyStrategy, ingestionBranch, merge, mergeIncremental, normalizeMergeOptions, openProvenanceStore, persistProvenanceRecords, planCandidateWriteSet, planCandidateWriteSetForEvolution, planCandidateWriteSetReview, planMerge, planMergeForEvolution, planMergeIncremental, provenanceGraphId, readProvenance, reopenDurableBranch, revalidateCandidateWriteSetReview };
|
|
11256
|
+
export { BaseVersionMismatchError, BranchError, CANDIDATE_WRITE_SET_FORMAT_VERSION, CandidateSourceError, CandidateWriteSetError, CandidateWriteSetSchema, CandidateWriteSetTargetSchema, DURABLE_OPERATION_SCAN_DEFAULT_LIMIT, DURABLE_OPERATION_SCAN_MAX_LIMIT, DurableEvidenceUndeliveredError, DurableOperationConflictError, DurableOperationError, DurableOperationEvidenceError, DurableOperationRequestError, DurableOperationUnsupportedError, 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, applyDurableMergePlan, applyMergePlan, applyMergePlanInTransaction, asBaseVersion, asBranchId, branch, branchDurable, branchForEvolution, captureCandidateWriteSetTarget, captureCandidateWriteSetTargetForEvolution, cloneWorkingCopyStrategy, computeBaseVersion, computeDurableOperationDigest, destroyDurableBranch, durableBranchHasUndeliveredEvidence, forkedWorkingCopyStrategy, getDurableOperation, ingestionBranch, markDurableOperationDelivered, merge, mergeIncremental, normalizeMergeOptions, openProvenanceStore, operateDurableBranch, persistProvenanceRecords, planCandidateWriteSet, planCandidateWriteSetForEvolution, planCandidateWriteSetReview, planMerge, planMergeForEvolution, planMergeIncremental, provenanceGraphId, readProvenance, reopenDurableBranch, revalidateCandidateWriteSetReview, scanDurableOperations };
|
|
10753
11257
|
//# sourceMappingURL=index.js.map
|
|
10754
11258
|
//# sourceMappingURL=index.js.map
|