@fabricorg/platform-host 7.1.0 → 7.1.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.
- package/CHANGELOG.md +6 -0
- package/README.md +3 -1
- package/dist/index.cjs +16 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -348,6 +348,14 @@ interface ExternalCompletion {
|
|
|
348
348
|
}
|
|
349
349
|
interface RecordedExternalCompletion extends ExternalCompletion {
|
|
350
350
|
recordedAt: Date;
|
|
351
|
+
/**
|
|
352
|
+
* Canonical digest of provider, reference, outcome, result, error, and
|
|
353
|
+
* evidence. A repeat with the same digest is the same news; a repeat with
|
|
354
|
+
* the same outcome and a different digest is changed evidence, and is a
|
|
355
|
+
* contradiction like a flipped outcome. Observation time is left out,
|
|
356
|
+
* since a redelivery legitimately carries a new one.
|
|
357
|
+
*/
|
|
358
|
+
digest: string;
|
|
351
359
|
}
|
|
352
360
|
interface ReconcileOverdueCompletionsInput {
|
|
353
361
|
tenantId?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -348,6 +348,14 @@ interface ExternalCompletion {
|
|
|
348
348
|
}
|
|
349
349
|
interface RecordedExternalCompletion extends ExternalCompletion {
|
|
350
350
|
recordedAt: Date;
|
|
351
|
+
/**
|
|
352
|
+
* Canonical digest of provider, reference, outcome, result, error, and
|
|
353
|
+
* evidence. A repeat with the same digest is the same news; a repeat with
|
|
354
|
+
* the same outcome and a different digest is changed evidence, and is a
|
|
355
|
+
* contradiction like a flipped outcome. Observation time is left out,
|
|
356
|
+
* since a redelivery legitimately carries a new one.
|
|
357
|
+
*/
|
|
358
|
+
digest: string;
|
|
351
359
|
}
|
|
352
360
|
interface ReconcileOverdueCompletionsInput {
|
|
353
361
|
tenantId?: string;
|
package/dist/index.js
CHANGED
|
@@ -1350,11 +1350,12 @@ function createGovernedActionHost(options) {
|
|
|
1350
1350
|
if (completion.provider !== void 0 && recorded.provider !== void 0 && completion.provider !== recorded.provider) {
|
|
1351
1351
|
throw new ExternalCompletionError("provider_mismatch", `ActionInvocation ${actionInvocationId} was completed by "${recorded.provider}", not "${completion.provider}".`);
|
|
1352
1352
|
}
|
|
1353
|
-
|
|
1353
|
+
const incomingDigest = completionDigest(completion, recorded.provider ?? completion.provider);
|
|
1354
|
+
if (recorded.digest === incomingDigest) {
|
|
1354
1355
|
return withConsistency(actionResult(invocation), invocation.actionId);
|
|
1355
1356
|
}
|
|
1356
|
-
const message = `External operation "${completion.externalReference}" reported ${completion.outcome} after reporting ${recorded.outcome}.`;
|
|
1357
|
-
await recordCompletionReconciliation(invocation, { ...completion, kind: `contradicted:${
|
|
1357
|
+
const message = recorded.outcome === completion.outcome ? `External operation "${completion.externalReference}" reported ${completion.outcome} again with different evidence.` : `External operation "${completion.externalReference}" reported ${completion.outcome} after reporting ${recorded.outcome}.`;
|
|
1358
|
+
await recordCompletionReconciliation(invocation, { ...completion, kind: `contradicted:${incomingDigest.slice(0, 16)}` }, message);
|
|
1358
1359
|
await appendEvent(invocation, {
|
|
1359
1360
|
eventType: "ExternalOperationContradicted",
|
|
1360
1361
|
subjectType: "AdapterInvocation",
|
|
@@ -1384,7 +1385,8 @@ function createGovernedActionHost(options) {
|
|
|
1384
1385
|
...completion,
|
|
1385
1386
|
provider: completion.provider ?? pending.provider,
|
|
1386
1387
|
observedAt: completion.observedAt instanceof Date ? completion.observedAt.toISOString() : completion.observedAt,
|
|
1387
|
-
recordedAt
|
|
1388
|
+
recordedAt,
|
|
1389
|
+
digest: completionDigest(completion, completion.provider ?? pending.provider)
|
|
1388
1390
|
};
|
|
1389
1391
|
const subject = { subjectType: "AdapterInvocation", subjectId: pending.adapterInvocationId };
|
|
1390
1392
|
const settles = invocation.status === "running" && pending.parkedAt !== void 0 || invocation.status === "reconciliation_required" && invocation.error?.includes("did not complete by") === true;
|
|
@@ -1423,6 +1425,16 @@ function createGovernedActionHost(options) {
|
|
|
1423
1425
|
if (settles) emitInvocationStatusTelemetry(invocation, "failed", options.telemetry, now(), invocation.status);
|
|
1424
1426
|
return withConsistency(actionResult({ ...invocation, ...patch }), invocation.actionId);
|
|
1425
1427
|
}
|
|
1428
|
+
function completionDigest(completion, provider) {
|
|
1429
|
+
return createHash("sha256").update(canonicalJson({
|
|
1430
|
+
provider: provider ?? null,
|
|
1431
|
+
externalReference: completion.externalReference,
|
|
1432
|
+
outcome: completion.outcome,
|
|
1433
|
+
result: completion.result ?? null,
|
|
1434
|
+
error: completion.error ?? null,
|
|
1435
|
+
evidenceReferences: completion.evidenceReferences ?? null
|
|
1436
|
+
})).digest("hex");
|
|
1437
|
+
}
|
|
1426
1438
|
async function recordCompletionReconciliation(invocation, completion, reason) {
|
|
1427
1439
|
const governanceStore = asGovernanceStore(options.store);
|
|
1428
1440
|
if (!governanceStore) throw new Error("External completion reconciliation requires a governance-capable store.");
|