@lostgradient/weft 0.23.1 → 0.24.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/README.md +72 -4
- package/dist/cli/codegen-emit-dedup.d.ts +81 -0
- package/dist/cli/codegen-emit-dedup.js +45 -0
- package/dist/cli/codegen-emit-registry.d.ts +90 -0
- package/dist/cli/codegen-emit-registry.js +50 -0
- package/dist/cli/codegen-emit.d.ts +26 -39
- package/dist/cli/codegen-emit.js +4 -27
- package/dist/cli/codegen-validate.d.ts +49 -0
- package/dist/cli/codegen-validate.js +186 -0
- package/dist/cli/codegen.js +6 -87
- package/dist/cli/generated/operation-catalog.snapshot.json +287 -3
- package/dist/cli/generated/operation-client.generated.d.ts +324 -10
- package/dist/cli/generated/operation-client.generated.js +12 -0
- package/dist/cli/output.js +1 -1
- package/dist/cli/storage-factory.js +2 -0
- package/dist/cli/workflow-commands.js +2 -0
- package/dist/cli-main.js +1 -1
- package/dist/core/application-payload-digest.d.ts +42 -0
- package/dist/core/application-payload-digest.js +76 -0
- package/dist/core/application-primitive-abort.d.ts +50 -0
- package/dist/core/application-primitive-abort.js +40 -0
- package/dist/core/application-primitive-attempt-registry.d.ts +74 -0
- package/dist/core/application-primitive-attempt-registry.js +73 -0
- package/dist/core/application-primitive-codec.d.ts +36 -0
- package/dist/core/application-primitive-codec.js +56 -0
- package/dist/core/application-primitive-commit.d.ts +67 -0
- package/dist/core/application-primitive-commit.js +66 -0
- package/dist/core/application-primitive-guards.d.ts +62 -0
- package/dist/core/application-primitive-guards.js +89 -0
- package/dist/core/application-primitive-payload.d.ts +29 -0
- package/dist/core/application-primitive-payload.js +65 -0
- package/dist/core/application-primitive-timing.d.ts +18 -0
- package/dist/core/application-primitive-timing.js +22 -0
- package/dist/core/atomic-state.js +2 -0
- package/dist/core/catalog/codec.d.ts +40 -0
- package/dist/core/catalog/codec.js +45 -0
- package/dist/core/catalog/errors.d.ts +104 -0
- package/dist/core/catalog/errors.js +41 -0
- package/dist/core/catalog/index.d.ts +25 -0
- package/dist/core/catalog/index.js +15 -0
- package/dist/core/catalog/reference-counts.d.ts +105 -0
- package/dist/core/catalog/reference-counts.js +28 -0
- package/dist/core/catalog/removal.d.ts +52 -0
- package/dist/core/catalog/removal.js +14 -0
- package/dist/core/catalog/storage-io.d.ts +78 -0
- package/dist/core/catalog/storage-io.js +106 -0
- package/dist/core/catalog/types.d.ts +108 -0
- package/dist/core/catalog/types.js +0 -0
- package/dist/core/catalog/workflow-catalog.d.ts +165 -0
- package/dist/core/catalog/workflow-catalog.js +198 -0
- package/dist/core/compare-codepoint.d.ts +13 -0
- package/dist/core/compare-codepoint.js +7 -0
- package/dist/core/compression.js +2 -0
- package/dist/core/context/attributes.d.ts +1 -1
- package/dist/core/context/durable-operations.d.ts +2 -2
- package/dist/core/context/index.js +5 -3
- package/dist/core/context/state-namespace.d.ts +1 -1
- package/dist/core/contract/build.d.ts +64 -0
- package/dist/core/contract/build.js +99 -0
- package/dist/core/contract/compatibility.d.ts +187 -0
- package/dist/core/contract/compatibility.js +37 -0
- package/dist/core/contract/failure.d.ts +64 -0
- package/dist/core/contract/failure.js +4 -0
- package/dist/core/contract/hash.d.ts +92 -0
- package/dist/core/contract/hash.js +34 -0
- package/dist/core/contract/index.d.ts +21 -0
- package/dist/core/contract/index.js +22 -0
- package/dist/core/contract/limits.d.ts +74 -0
- package/dist/core/contract/limits.js +1 -0
- package/dist/core/contract/manifest-parse-schema.d.ts +37 -0
- package/dist/core/contract/manifest-parse-schema.js +106 -0
- package/dist/core/contract/manifest-parse.d.ts +76 -0
- package/dist/core/contract/manifest-parse.js +189 -0
- package/dist/core/contract/manifest.d.ts +56 -0
- package/dist/core/contract/manifest.js +31 -0
- package/dist/core/contract/normalize.d.ts +97 -0
- package/dist/core/contract/normalize.js +127 -0
- package/dist/core/contract/revision.d.ts +29 -0
- package/dist/core/contract/revision.js +5 -0
- package/dist/core/contract/types.d.ts +274 -0
- package/dist/core/contract/types.js +1 -0
- package/dist/core/engine/catalog-activation.d.ts +40 -0
- package/dist/core/engine/catalog-activation.js +17 -0
- package/dist/core/engine/catalog-events.d.ts +36 -0
- package/dist/core/engine/catalog-events.js +15 -0
- package/dist/core/engine/catalog-readiness.d.ts +49 -0
- package/dist/core/engine/catalog-readiness.js +59 -0
- package/dist/core/engine/catalog-removal.d.ts +132 -0
- package/dist/core/engine/catalog-removal.js +70 -0
- package/dist/core/engine/construction.d.ts +1 -1
- package/dist/core/engine/construction.js +4 -2
- package/dist/core/engine/disposal.js +9 -0
- package/dist/core/engine/engine-workflows-namespace.d.ts +130 -0
- package/dist/core/engine/engine-workflows-namespace.js +49 -0
- package/dist/core/engine/finalizer-metadata.d.ts +22 -0
- package/dist/core/engine/finalizer-metadata.js +12 -0
- package/dist/core/engine/handle-result.js +2 -0
- package/dist/core/engine/index.d.ts +83 -0
- package/dist/core/engine/index.js +61 -0
- package/dist/core/engine/internals.d.ts +44 -1
- package/dist/core/engine/internals.js +6 -0
- package/dist/core/engine/lifecycle/start.js +3 -0
- package/dist/core/engine/registration.d.ts +76 -0
- package/dist/core/engine/registration.js +12 -6
- package/dist/core/engine/source-registration.d.ts +42 -0
- package/dist/core/engine/source-registration.js +36 -0
- package/dist/core/engine/source-resolution.d.ts +85 -0
- package/dist/core/engine/source-resolution.js +119 -0
- package/dist/core/engine/validation.js +2 -2
- package/dist/core/events/catalog-events.d.ts +117 -0
- package/dist/core/events/catalog-events.js +62 -0
- package/dist/core/events/event-map.d.ts +6 -0
- package/dist/core/events/index.d.ts +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/mailbox-admission.d.ts +26 -0
- package/dist/core/mailbox-admission.js +130 -0
- package/dist/core/mailbox-claims.d.ts +251 -0
- package/dist/core/mailbox-claims.js +0 -0
- package/dist/core/mailbox-codec.d.ts +32 -0
- package/dist/core/mailbox-codec.js +221 -0
- package/dist/core/mailbox-contract.d.ts +290 -0
- package/dist/core/mailbox-contract.js +0 -0
- package/dist/core/mailbox-delivery.d.ts +37 -0
- package/dist/core/mailbox-delivery.js +193 -0
- package/dist/core/mailbox-guards.d.ts +78 -0
- package/dist/core/mailbox-guards.js +58 -0
- package/dist/core/mailbox-index-codec.d.ts +41 -0
- package/dist/core/mailbox-index-codec.js +71 -0
- package/dist/core/mailbox-internals.d.ts +156 -0
- package/dist/core/mailbox-internals.js +154 -0
- package/dist/core/mailbox-maintenance.d.ts +29 -0
- package/dist/core/mailbox-maintenance.js +196 -0
- package/dist/core/mailbox-settlement.d.ts +69 -0
- package/dist/core/mailbox-settlement.js +206 -0
- package/dist/core/mailbox-storage.d.ts +117 -0
- package/dist/core/mailbox-storage.js +115 -0
- package/dist/core/mailbox-transition-helpers.d.ts +70 -0
- package/dist/core/mailbox-transition-helpers.js +43 -0
- package/dist/core/mailbox-transitions-recovery.d.ts +28 -0
- package/dist/core/mailbox-transitions-recovery.js +64 -0
- package/dist/core/mailbox-transitions.d.ts +138 -0
- package/dist/core/mailbox-transitions.js +180 -0
- package/dist/core/mailbox-types.d.ts +406 -0
- package/dist/core/mailbox-types.js +16 -0
- package/dist/core/mailbox-validation.d.ts +65 -0
- package/dist/core/mailbox-validation.js +73 -0
- package/dist/core/mailbox-waits.d.ts +50 -0
- package/dist/core/mailbox-waits.js +97 -0
- package/dist/core/mailbox.d.ts +163 -0
- package/dist/core/mailbox.js +211 -0
- package/dist/core/outbox-claims.d.ts +307 -0
- package/dist/core/outbox-claims.js +0 -0
- package/dist/core/outbox-codec.d.ts +24 -0
- package/dist/core/outbox-codec.js +257 -0
- package/dist/core/outbox-contract.d.ts +346 -0
- package/dist/core/outbox-contract.js +0 -0
- package/dist/core/outbox-delivery.d.ts +34 -0
- package/dist/core/outbox-delivery.js +149 -0
- package/dist/core/outbox-drain.d.ts +29 -0
- package/dist/core/outbox-drain.js +158 -0
- package/dist/core/outbox-enqueue.d.ts +24 -0
- package/dist/core/outbox-enqueue.js +115 -0
- package/dist/core/outbox-guards.d.ts +76 -0
- package/dist/core/outbox-guards.js +60 -0
- package/dist/core/outbox-index-codec.d.ts +33 -0
- package/dist/core/outbox-index-codec.js +71 -0
- package/dist/core/outbox-internals.d.ts +99 -0
- package/dist/core/outbox-internals.js +159 -0
- package/dist/core/outbox-listing.d.ts +12 -0
- package/dist/core/outbox-listing.js +38 -0
- package/dist/core/outbox-maintenance.d.ts +28 -0
- package/dist/core/outbox-maintenance.js +191 -0
- package/dist/core/outbox-operations.d.ts +18 -0
- package/dist/core/outbox-operations.js +46 -0
- package/dist/core/outbox-runner.d.ts +30 -0
- package/dist/core/outbox-runner.js +217 -0
- package/dist/core/outbox-settlement.d.ts +57 -0
- package/dist/core/outbox-settlement.js +183 -0
- package/dist/core/outbox-storage.d.ts +107 -0
- package/dist/core/outbox-storage.js +127 -0
- package/dist/core/outbox-transition-helpers.d.ts +83 -0
- package/dist/core/outbox-transition-helpers.js +63 -0
- package/dist/core/outbox-transitions-recovery.d.ts +30 -0
- package/dist/core/outbox-transitions-recovery.js +42 -0
- package/dist/core/outbox-transitions.d.ts +145 -0
- package/dist/core/outbox-transitions.js +236 -0
- package/dist/core/outbox-types.d.ts +400 -0
- package/dist/core/outbox-types.js +20 -0
- package/dist/core/outbox-validation.d.ts +101 -0
- package/dist/core/outbox-validation.js +127 -0
- package/dist/core/outbox-waits.d.ts +39 -0
- package/dist/core/outbox-waits.js +88 -0
- package/dist/core/outbox.d.ts +156 -0
- package/dist/core/outbox.js +234 -0
- package/dist/core/registry-limits.d.ts +49 -0
- package/dist/core/registry-limits.js +10 -0
- package/dist/core/registry-schema-conversion.d.ts +20 -0
- package/dist/core/registry-schema-conversion.js +22 -0
- package/dist/core/registry-snapshot.d.ts +91 -42
- package/dist/core/registry-snapshot.js +39 -77
- package/dist/core/registry-workflow-contract-draft.d.ts +32 -0
- package/dist/core/registry-workflow-contract-draft.js +28 -0
- package/dist/core/registry-workflow-manifest.d.ts +122 -0
- package/dist/core/registry-workflow-manifest.js +92 -0
- package/dist/core/source/errors.d.ts +55 -0
- package/dist/core/source/errors.js +13 -0
- package/dist/core/source/index.d.ts +19 -0
- package/dist/core/source/index.js +4 -0
- package/dist/core/source/resolvers.d.ts +45 -0
- package/dist/core/source/resolvers.js +9 -0
- package/dist/core/source/types.d.ts +211 -0
- package/dist/core/source/types.js +0 -0
- package/dist/core/source/validate.d.ts +91 -0
- package/dist/core/source/validate.js +62 -0
- package/dist/core/source/workflow-source.d.ts +43 -0
- package/dist/core/source/workflow-source.js +16 -0
- package/dist/core/types/workflow-registries.d.ts +7 -0
- package/dist/core/types/workflow-registry.d.ts +12 -0
- package/dist/core/versioning.js +2 -0
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +9 -1
- package/dist/http.js +2 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +50 -0
- package/dist/indexeddb.js +1 -1
- package/dist/json-schema.js +3 -3
- package/dist/mcp/resources.js +2 -0
- package/dist/runtime/portable.d.ts +9 -1
- package/dist/server/fault-to-json-rpc.js +3 -1
- package/dist/server/handler/auth-context-principal.js +4 -0
- package/dist/server/json-rpc-http.js +2 -0
- package/dist/server/json-rpc-websocket.js +6 -4
- package/dist/server/operation-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/pipeline-helpers.js +2 -0
- package/dist/server/operation-catalog/types.d.ts +17 -0
- package/dist/server/operation-fault.d.ts +3 -0
- package/dist/server/operation-fault.js +3 -1
- package/dist/server/operations/activate-workflow-revision.d.ts +30 -0
- package/dist/server/operations/activate-workflow-revision.js +69 -0
- package/dist/server/operations/fleet-events-subscription.js +1 -1
- package/dist/server/operations/fork-workflow.js +1 -1
- package/dist/server/operations/get-active-workflow-revision.d.ts +32 -0
- package/dist/server/operations/get-active-workflow-revision.js +46 -0
- package/dist/server/operations/get-catalog-diagnostics.d.ts +85 -0
- package/dist/server/operations/get-catalog-diagnostics.js +57 -0
- package/dist/server/operations/get-registry.js +17 -4
- package/dist/server/operations/get-workflow-revision.d.ts +25 -0
- package/dist/server/operations/get-workflow-revision.js +50 -0
- package/dist/server/operations/install-workflow-revision.d.ts +27 -0
- package/dist/server/operations/install-workflow-revision.js +46 -0
- package/dist/server/operations/list-workflow-revisions.d.ts +20 -0
- package/dist/server/operations/list-workflow-revisions.js +40 -0
- package/dist/server/operations/start-or-signal-workflow.js +1 -1
- package/dist/server/operations/start-workflow.js +1 -1
- package/dist/server/operations/static-registrations.js +36 -0
- package/dist/server/operations/storage.js +2 -2
- package/dist/server/operations/submit-review-decision.js +1 -1
- package/dist/server/operations/workflow-catalog-operation-helpers.d.ts +59 -0
- package/dist/server/operations/workflow-catalog-operation-helpers.js +135 -0
- package/dist/server/runtime/websocket-upgrade.js +2 -0
- package/dist/storage/bun-sql.js +49 -6
- package/dist/storage/catalog-keys.d.ts +45 -0
- package/dist/storage/catalog-keys.js +6 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/derived-operations.js +1 -1
- package/dist/storage/index.d.ts +26 -1
- package/dist/storage/interface.d.ts +26 -1
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-encoding.d.ts +15 -0
- package/dist/storage/key-encoding.js +3 -0
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +15 -0
- package/dist/storage/lmdb.d.ts +26 -1
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/mailbox-keys.d.ts +80 -0
- package/dist/storage/mailbox-keys.js +14 -0
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +2 -2
- package/dist/storage/node-sqlite-loader.d.ts +1 -1
- package/dist/storage/node-sqlite.js +49 -6
- package/dist/storage/outbox-keys.d.ts +77 -0
- package/dist/storage/outbox-keys.js +14 -0
- package/dist/storage/postgres.js +2 -2
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/storage-configuration.d.ts +6 -0
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/manifest/registry-contract-builder.d.ts +21 -3
- package/dist/worker/manifest/registry-contract-builder.js +40 -31
- package/package.json +1 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { requireDerivedInstant } from "./outbox-guards.js";
|
|
2
|
+
import {
|
|
3
|
+
applicationDeliveryIdentityFields,
|
|
4
|
+
nonTerminalDeliveryRecord,
|
|
5
|
+
rejectedTransition,
|
|
6
|
+
rescheduleOrDeadLetter,
|
|
7
|
+
succeededTransition
|
|
8
|
+
} from "./outbox-transition-helpers.js";
|
|
9
|
+
import {
|
|
10
|
+
OUTBOX_RECORD_VERSION,
|
|
11
|
+
isApplicationDeliveryLeased,
|
|
12
|
+
isApplicationDeliveryTerminalState
|
|
13
|
+
} from "./outbox-types.js";
|
|
14
|
+
export {
|
|
15
|
+
isTerminalDeliveryRecord,
|
|
16
|
+
nonTerminalDeliveryRecord
|
|
17
|
+
} from "./outbox-transition-helpers.js";
|
|
18
|
+
export function createEnqueuedDeliveryRecord(input, context) {
|
|
19
|
+
return {
|
|
20
|
+
recordVersion: OUTBOX_RECORD_VERSION,
|
|
21
|
+
namespace: context.namespace,
|
|
22
|
+
ownerId: context.ownerId,
|
|
23
|
+
deliveryId: context.deliveryId,
|
|
24
|
+
sequence: context.sequence,
|
|
25
|
+
idempotencyKey: input.idempotencyKey,
|
|
26
|
+
destinationRef: input.destinationRef,
|
|
27
|
+
credentialRef: input.credentialRef,
|
|
28
|
+
kind: input.kind,
|
|
29
|
+
payload: input.payload,
|
|
30
|
+
payloadDigest: input.payloadDigest,
|
|
31
|
+
payloadMediaType: input.payloadMediaType,
|
|
32
|
+
payloadSchema: input.payloadSchema,
|
|
33
|
+
causation: input.causation,
|
|
34
|
+
externalIdempotencyKey: input.externalIdempotencyKey,
|
|
35
|
+
unknownOutcomePolicy: input.unknownOutcomePolicy,
|
|
36
|
+
enqueuedAt: context.now,
|
|
37
|
+
availableAt: requireDerivedInstant(context.now + input.availableAfterMs, "availableAt"),
|
|
38
|
+
maxAttempts: input.maxAttempts,
|
|
39
|
+
visibilityTimeoutMs: input.visibilityTimeoutMs,
|
|
40
|
+
attemptTimeoutMs: input.attemptTimeoutMs,
|
|
41
|
+
generation: 0,
|
|
42
|
+
attempt: 0,
|
|
43
|
+
retryCount: 0,
|
|
44
|
+
state: "queued"
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function claimWaitingDelivery(record, options) {
|
|
48
|
+
const live = nonTerminalDeliveryRecord(record);
|
|
49
|
+
if (live === null)
|
|
50
|
+
return rejectedTransition("already-terminal");
|
|
51
|
+
if (live.state !== "queued" && live.state !== "retry-scheduled")
|
|
52
|
+
return rejectedTransition("not-waiting");
|
|
53
|
+
if (options.now < live.availableAt)
|
|
54
|
+
return rejectedTransition("not-due");
|
|
55
|
+
const attemptDeadlineAt = requireDerivedInstant(options.now + live.attemptTimeoutMs, "attemptDeadlineAt");
|
|
56
|
+
return succeededTransition({
|
|
57
|
+
...applicationDeliveryIdentityFields(live),
|
|
58
|
+
state: "claimed",
|
|
59
|
+
attempt: live.attempt + 1,
|
|
60
|
+
firstClaimedAt: live.firstClaimedAt ?? options.now,
|
|
61
|
+
attemptToken: options.attemptToken,
|
|
62
|
+
claimedAt: options.now,
|
|
63
|
+
attemptDeadlineAt,
|
|
64
|
+
visibilityExpiresAt: Math.min(options.now + live.visibilityTimeoutMs, attemptDeadlineAt),
|
|
65
|
+
lastActivityAt: options.now
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function checkCurrentAttempt(record, attemptToken, now) {
|
|
69
|
+
if (isApplicationDeliveryTerminalState(record.state))
|
|
70
|
+
return { ok: !1, reason: "already-terminal" };
|
|
71
|
+
if (!isApplicationDeliveryLeased(record))
|
|
72
|
+
return { ok: !1, reason: "not-leased" };
|
|
73
|
+
if (record.attemptToken !== attemptToken)
|
|
74
|
+
return { ok: !1, reason: "stale-attempt" };
|
|
75
|
+
if (now >= record.attemptDeadlineAt)
|
|
76
|
+
return { ok: !1, reason: "deadline-exceeded" };
|
|
77
|
+
return { ok: !0, leased: record };
|
|
78
|
+
}
|
|
79
|
+
export function beginDeliveryAttempt(record, options) {
|
|
80
|
+
const checked = checkCurrentAttempt(record, options.attemptToken, options.now);
|
|
81
|
+
if (!checked.ok)
|
|
82
|
+
return rejectedTransition(checked.reason);
|
|
83
|
+
const { leased } = checked;
|
|
84
|
+
if (leased.state === "cancellation-requested")
|
|
85
|
+
return rejectedTransition("cancellation-requested");
|
|
86
|
+
if (leased.state !== "claimed")
|
|
87
|
+
return rejectedTransition("not-applicable");
|
|
88
|
+
return succeededTransition({
|
|
89
|
+
...leased,
|
|
90
|
+
generation: leased.generation + 1,
|
|
91
|
+
state: "attempting",
|
|
92
|
+
attemptStartedAt: options.now,
|
|
93
|
+
lastActivityAt: options.now,
|
|
94
|
+
visibilityExpiresAt: Math.min(options.now + leased.visibilityTimeoutMs, leased.attemptDeadlineAt)
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export function heartbeatDeliveryAttempt(record, options) {
|
|
98
|
+
const checked = checkCurrentAttempt(record, options.attemptToken, options.now);
|
|
99
|
+
if (!checked.ok)
|
|
100
|
+
return rejectedTransition(checked.reason);
|
|
101
|
+
const { leased } = checked;
|
|
102
|
+
return succeededTransition({
|
|
103
|
+
...leased,
|
|
104
|
+
generation: leased.generation + 1,
|
|
105
|
+
lastActivityAt: options.now,
|
|
106
|
+
visibilityExpiresAt: Math.min(options.now + leased.visibilityTimeoutMs, leased.attemptDeadlineAt),
|
|
107
|
+
transportActivity: options.transportActivity === void 0 ? leased.transportActivity : options.transportActivity
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function cancellationFields(leased) {
|
|
111
|
+
return leased.state === "cancellation-requested" ? {
|
|
112
|
+
cancellationRequestedAt: leased.cancellationRequestedAt,
|
|
113
|
+
cancellationReason: leased.cancellationReason
|
|
114
|
+
} : {};
|
|
115
|
+
}
|
|
116
|
+
export function applyUnknownOutcomePolicy(leased, options) {
|
|
117
|
+
const cancelling = leased.state === "cancellation-requested", abandoned = options.abandonedAttemptToken === void 0 ? {} : { cleanupPending: !0, abandonedAttemptToken: options.abandonedAttemptToken };
|
|
118
|
+
if (leased.unknownOutcomePolicy === "dead-letter")
|
|
119
|
+
return {
|
|
120
|
+
...applicationDeliveryIdentityFields(leased),
|
|
121
|
+
state: "dead-lettered",
|
|
122
|
+
terminalAt: options.now,
|
|
123
|
+
failure: options.failure,
|
|
124
|
+
...cancellationFields(leased),
|
|
125
|
+
...abandoned
|
|
126
|
+
};
|
|
127
|
+
if (leased.unknownOutcomePolicy === "retry-with-idempotency" && !cancelling) {
|
|
128
|
+
const next = rescheduleOrDeadLetter(leased, { ...options, failure: options.failure });
|
|
129
|
+
return next.state === "dead-lettered" ? { ...next, ...abandoned } : next;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
...applicationDeliveryIdentityFields(leased),
|
|
133
|
+
state: "unknown-outcome",
|
|
134
|
+
terminalAt: options.now,
|
|
135
|
+
failure: options.failure,
|
|
136
|
+
...cancellationFields(leased),
|
|
137
|
+
...abandoned
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
export function settleDeliveryAttempt(record, options) {
|
|
141
|
+
const checked = checkCurrentAttempt(record, options.attemptToken, options.now);
|
|
142
|
+
if (!checked.ok)
|
|
143
|
+
return rejectedTransition(checked.reason);
|
|
144
|
+
const { leased } = checked;
|
|
145
|
+
if (leased.state === "claimed")
|
|
146
|
+
return rejectedTransition("not-attempting");
|
|
147
|
+
const { outcome } = options;
|
|
148
|
+
if (outcome.status === "acknowledged")
|
|
149
|
+
return succeededTransition({
|
|
150
|
+
...applicationDeliveryIdentityFields(leased),
|
|
151
|
+
state: "acknowledged",
|
|
152
|
+
terminalAt: options.now,
|
|
153
|
+
evidence: outcome.evidence,
|
|
154
|
+
...cancellationFields(leased)
|
|
155
|
+
});
|
|
156
|
+
if (outcome.status === "unknown")
|
|
157
|
+
return succeededTransition(applyUnknownOutcomePolicy(leased, {
|
|
158
|
+
now: options.now,
|
|
159
|
+
retryBackoffMs: options.retryBackoffMs,
|
|
160
|
+
maxRetryBackoffMs: options.maxRetryBackoffMs,
|
|
161
|
+
failure: { reason: "unknown-outcome", message: outcome.failure.message }
|
|
162
|
+
}));
|
|
163
|
+
if (leased.state === "cancellation-requested")
|
|
164
|
+
return succeededTransition({
|
|
165
|
+
...applicationDeliveryIdentityFields(leased),
|
|
166
|
+
state: "cancelled",
|
|
167
|
+
terminalAt: options.now,
|
|
168
|
+
failure: { reason: "cancelled" },
|
|
169
|
+
...cancellationFields(leased),
|
|
170
|
+
cleanupPending: !1
|
|
171
|
+
});
|
|
172
|
+
if (outcome.status === "rejected")
|
|
173
|
+
return succeededTransition({
|
|
174
|
+
...applicationDeliveryIdentityFields(leased),
|
|
175
|
+
state: "rejected",
|
|
176
|
+
terminalAt: options.now,
|
|
177
|
+
failure: outcome.failure
|
|
178
|
+
});
|
|
179
|
+
return succeededTransition(rescheduleOrDeadLetter(leased, {
|
|
180
|
+
...options,
|
|
181
|
+
failure: outcome.failure,
|
|
182
|
+
retryAfterMs: outcome.retryAfterMs
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
export function requestDeliveryCancellation(record, options) {
|
|
186
|
+
const live = nonTerminalDeliveryRecord(record);
|
|
187
|
+
if (live === null)
|
|
188
|
+
return rejectedTransition("already-terminal");
|
|
189
|
+
if (live.state === "cancellation-requested")
|
|
190
|
+
return rejectedTransition("not-leased");
|
|
191
|
+
if (live.state === "attempting")
|
|
192
|
+
return succeededTransition({
|
|
193
|
+
...live,
|
|
194
|
+
generation: live.generation + 1,
|
|
195
|
+
state: "cancellation-requested",
|
|
196
|
+
cancellationRequestedAt: options.now,
|
|
197
|
+
cancellationReason: options.reason
|
|
198
|
+
});
|
|
199
|
+
return succeededTransition({
|
|
200
|
+
...applicationDeliveryIdentityFields(live),
|
|
201
|
+
state: "cancelled",
|
|
202
|
+
terminalAt: options.now,
|
|
203
|
+
failure: { reason: "cancelled" },
|
|
204
|
+
cancellationRequestedAt: options.now,
|
|
205
|
+
cancellationReason: options.reason,
|
|
206
|
+
cleanupPending: !1
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
export function retryDeliveryByOperator(record, options) {
|
|
210
|
+
if (record.state !== "unknown-outcome" && record.state !== "dead-lettered" && record.state !== "rejected")
|
|
211
|
+
return rejectedTransition("not-applicable");
|
|
212
|
+
return succeededTransition({
|
|
213
|
+
...applicationDeliveryIdentityFields(record),
|
|
214
|
+
state: "queued",
|
|
215
|
+
maxAttempts: Math.max(record.maxAttempts, record.attempt + 1),
|
|
216
|
+
availableAt: options.now
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
export function deadLetterDeliveryByOperator(record, options) {
|
|
220
|
+
if (record.state !== "unknown-outcome")
|
|
221
|
+
return rejectedTransition("not-applicable");
|
|
222
|
+
return succeededTransition({
|
|
223
|
+
...applicationDeliveryIdentityFields(record),
|
|
224
|
+
state: "dead-lettered",
|
|
225
|
+
terminalAt: options.now,
|
|
226
|
+
failure: {
|
|
227
|
+
reason: "unknown-outcome",
|
|
228
|
+
message: options.reason ?? record.failure?.message,
|
|
229
|
+
details: record.failure?.details
|
|
230
|
+
},
|
|
231
|
+
cancellationRequestedAt: record.cancellationRequestedAt,
|
|
232
|
+
cancellationReason: record.cancellationReason,
|
|
233
|
+
cleanupPending: record.cleanupPending,
|
|
234
|
+
abandonedAttemptToken: record.abandonedAttemptToken
|
|
235
|
+
});
|
|
236
|
+
}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable record types for the application delivery outbox (WFT-85).
|
|
3
|
+
*
|
|
4
|
+
* A delivery is one intent to send one payload to one opaque destination. Its
|
|
5
|
+
* record is the single authority for what has been attempted, what the
|
|
6
|
+
* transport reported, and what disposition the outbox committed on that
|
|
7
|
+
* evidence. Transport completion is never a disposition on its own: a socket
|
|
8
|
+
* or HTTP write finishing is evidence the adapter reports, and only the
|
|
9
|
+
* durable settlement the outbox commits on it moves the record.
|
|
10
|
+
*
|
|
11
|
+
* The shapes mirror the command mailbox's; what differs is the vocabulary:
|
|
12
|
+
* `attempting` is a durable disposition committed before the adapter runs,
|
|
13
|
+
* `unknown-outcome` parks a lost transport result, and there is no
|
|
14
|
+
* per-delivery deadline — each attempt has its own.
|
|
15
|
+
*
|
|
16
|
+
* @module core/outbox-types
|
|
17
|
+
*/
|
|
18
|
+
import type { JSONValue } from './json.ts';
|
|
19
|
+
import type { ApplicationCommandCausation, ApplicationCommandPayload } from './mailbox-types.ts';
|
|
20
|
+
/** The record schema version every outbox record carries. */
|
|
21
|
+
export declare const OUTBOX_RECORD_VERSION = 1;
|
|
22
|
+
/**
|
|
23
|
+
* The payload of a delivery: the same inline-or-reference shape the command
|
|
24
|
+
* mailbox uses, so one content-addressed store can back both primitives.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import type { ApplicationDeliveryPayload } from '@lostgradient/weft';
|
|
29
|
+
*
|
|
30
|
+
* const payload: ApplicationDeliveryPayload = { form: 'inline', value: { event: 'task.completed' } };
|
|
31
|
+
* console.log(payload.form); // 'inline'
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export type ApplicationDeliveryPayload = ApplicationCommandPayload;
|
|
35
|
+
/**
|
|
36
|
+
* Causal metadata carried on a delivery, identical in shape to the mailbox's.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import type { ApplicationDeliveryCausation } from '@lostgradient/weft';
|
|
41
|
+
*
|
|
42
|
+
* const causation: ApplicationDeliveryCausation = { correlationId: 'run-1' };
|
|
43
|
+
* console.log(causation.correlationId); // 'run-1'
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export type ApplicationDeliveryCausation = ApplicationCommandCausation;
|
|
47
|
+
/**
|
|
48
|
+
* Every disposition a delivery record can occupy.
|
|
49
|
+
*
|
|
50
|
+
* ```text
|
|
51
|
+
* queued / retry-scheduled waiting in the due index
|
|
52
|
+
* claimed leased; the adapter has NOT been called
|
|
53
|
+
* attempting leased; the adapter call durably began
|
|
54
|
+
* cancellation-requested attempting, with cancellation durably requested
|
|
55
|
+
* acknowledged terminal: the transport reported acknowledgement
|
|
56
|
+
* rejected terminal: the transport reported a permanent refusal
|
|
57
|
+
* cancelled terminal: cancelled before any effect was confirmed
|
|
58
|
+
* unknown-outcome terminal: the transport result was lost; parked
|
|
59
|
+
* dead-lettered terminal: attempts exhausted, or unknown by policy
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* import type { ApplicationDeliveryState } from '@lostgradient/weft';
|
|
65
|
+
*
|
|
66
|
+
* const state: ApplicationDeliveryState = 'queued';
|
|
67
|
+
* console.log(state); // 'queued'
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export type ApplicationDeliveryState = 'queued' | 'retry-scheduled' | 'claimed' | 'attempting' | 'cancellation-requested' | 'acknowledged' | 'rejected' | 'cancelled' | 'unknown-outcome' | 'dead-lettered';
|
|
71
|
+
/**
|
|
72
|
+
* The terminal subset of {@link ApplicationDeliveryState}.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* import type { ApplicationDeliveryTerminalState } from '@lostgradient/weft';
|
|
77
|
+
*
|
|
78
|
+
* const state: ApplicationDeliveryTerminalState = 'acknowledged';
|
|
79
|
+
* console.log(state); // 'acknowledged'
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export type ApplicationDeliveryTerminalState = 'acknowledged' | 'rejected' | 'cancelled' | 'unknown-outcome' | 'dead-lettered';
|
|
83
|
+
/** Every terminal state, in a stable order. */
|
|
84
|
+
export declare const APPLICATION_DELIVERY_TERMINAL_STATES: readonly ApplicationDeliveryTerminalState[];
|
|
85
|
+
/**
|
|
86
|
+
* What the outbox does when a transport result is lost — an adapter that
|
|
87
|
+
* reported `unknown`, threw, or whose attempt lease expired after the send
|
|
88
|
+
* durably began.
|
|
89
|
+
*
|
|
90
|
+
* `park` leaves the delivery in `unknown-outcome` for an operator to `retry()`
|
|
91
|
+
* or `deadLetter()`. `dead-letter` terminalizes it at once. `retry-with-
|
|
92
|
+
* idempotency` schedules another attempt, and is accepted at enqueue only when
|
|
93
|
+
* the delivery carries an `externalIdempotencyKey`: without stable external
|
|
94
|
+
* idempotency evidence a retry could duplicate an effect that already happened.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* import type { ApplicationDeliveryUnknownOutcomePolicy } from '@lostgradient/weft';
|
|
99
|
+
*
|
|
100
|
+
* const policy: ApplicationDeliveryUnknownOutcomePolicy = 'park';
|
|
101
|
+
* console.log(policy); // 'park'
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export type ApplicationDeliveryUnknownOutcomePolicy = 'park' | 'dead-letter' | 'retry-with-idempotency';
|
|
105
|
+
/**
|
|
106
|
+
* Why a delivery failed, rescheduled, or parked. Every reason names one
|
|
107
|
+
* outbox-owned mechanism except `application`, which the transport supplied.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* import type { ApplicationDeliveryFailure } from '@lostgradient/weft';
|
|
112
|
+
*
|
|
113
|
+
* const failure: ApplicationDeliveryFailure = { reason: 'retryable', message: '503' };
|
|
114
|
+
* console.log(failure.reason); // 'retryable'
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export type ApplicationDeliveryFailure = Readonly<{
|
|
118
|
+
reason: 'application' | 'retryable' | 'attempts-exhausted' | 'unknown-outcome' | 'cancelled';
|
|
119
|
+
message?: string | undefined;
|
|
120
|
+
details?: JSONValue | undefined;
|
|
121
|
+
}>;
|
|
122
|
+
/**
|
|
123
|
+
* Fields every delivery record carries in every state: the identity and policy
|
|
124
|
+
* fixed at enqueue. Only `maxAttempts` is ever rewritten, by an operator
|
|
125
|
+
* `retry()` granting one more attempt. `credentialRef` is persisted because
|
|
126
|
+
* every attempt needs it and is projected into no receipt, event, or diagnostic.
|
|
127
|
+
*/
|
|
128
|
+
export type ApplicationDeliveryBase = Readonly<{
|
|
129
|
+
recordVersion: typeof OUTBOX_RECORD_VERSION;
|
|
130
|
+
namespace: string;
|
|
131
|
+
ownerId: string;
|
|
132
|
+
deliveryId: string;
|
|
133
|
+
/** Enqueue order within the outbox. Listing order only; never a delivery order. */
|
|
134
|
+
sequence: number;
|
|
135
|
+
idempotencyKey?: string | undefined;
|
|
136
|
+
destinationRef: string;
|
|
137
|
+
credentialRef?: string | undefined;
|
|
138
|
+
kind: string;
|
|
139
|
+
payload: ApplicationDeliveryPayload;
|
|
140
|
+
payloadDigest: string;
|
|
141
|
+
payloadMediaType?: string | undefined;
|
|
142
|
+
payloadSchema?: string | undefined;
|
|
143
|
+
causation?: ApplicationDeliveryCausation | undefined;
|
|
144
|
+
/** Stable external idempotency evidence the transport can present on a retry. */
|
|
145
|
+
externalIdempotencyKey?: string | undefined;
|
|
146
|
+
unknownOutcomePolicy: ApplicationDeliveryUnknownOutcomePolicy;
|
|
147
|
+
enqueuedAt: number;
|
|
148
|
+
maxAttempts: number;
|
|
149
|
+
/** Lease renewal window in milliseconds. Heartbeat extends visibility by this much. */
|
|
150
|
+
visibilityTimeoutMs: number;
|
|
151
|
+
/** Ceiling on one attempt in milliseconds from its claim. Heartbeat cannot move it. */
|
|
152
|
+
attemptTimeoutMs: number;
|
|
153
|
+
/** Monotonic transition counter. Diagnostic provenance; whole-record byte equality is the real fence. */
|
|
154
|
+
generation: number;
|
|
155
|
+
}>;
|
|
156
|
+
/** Attempt provenance preserved across claim, expiry, retry, and recovery. */
|
|
157
|
+
export type ApplicationDeliveryAttemptFields = Readonly<{
|
|
158
|
+
/** Number of claims issued so far. `0` until the first claim. */
|
|
159
|
+
attempt: number;
|
|
160
|
+
/** Number of reschedules caused by retryable outcomes, unknown outcomes, or lease expiry. */
|
|
161
|
+
retryCount: number;
|
|
162
|
+
/** First time any attempt claimed this delivery. Absent until the first claim. */
|
|
163
|
+
firstClaimedAt?: number | undefined;
|
|
164
|
+
}>;
|
|
165
|
+
/** A delivery waiting for its first attempt.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* import type { ApplicationDeliveryQueued } from '@lostgradient/weft';
|
|
170
|
+
*
|
|
171
|
+
* declare const record: ApplicationDeliveryQueued;
|
|
172
|
+
* console.log(record.state, record.availableAt); // 'queued', when it is due
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export type ApplicationDeliveryQueued = ApplicationDeliveryBase & ApplicationDeliveryAttemptFields & Readonly<{
|
|
176
|
+
state: 'queued';
|
|
177
|
+
availableAt: number;
|
|
178
|
+
}>;
|
|
179
|
+
/** A delivery waiting for a further attempt after a retryable, unknown, or expired one.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* import type { ApplicationDeliveryRetryScheduled } from '@lostgradient/weft';
|
|
184
|
+
*
|
|
185
|
+
* declare const record: ApplicationDeliveryRetryScheduled;
|
|
186
|
+
* console.log(record.lastFailure?.reason);
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export type ApplicationDeliveryRetryScheduled = ApplicationDeliveryBase & ApplicationDeliveryAttemptFields & Readonly<{
|
|
190
|
+
state: 'retry-scheduled';
|
|
191
|
+
availableAt: number;
|
|
192
|
+
/** Why the previous attempt did not acknowledge. */
|
|
193
|
+
lastFailure: ApplicationDeliveryFailure;
|
|
194
|
+
}>;
|
|
195
|
+
/** Lease fields held while one attempt owns a delivery. */
|
|
196
|
+
export type ApplicationDeliveryLeaseFields = Readonly<{
|
|
197
|
+
/** Opaque per-attempt fencing token. Every mutation from a claimant must present it. */
|
|
198
|
+
attemptToken: string;
|
|
199
|
+
claimedAt: number;
|
|
200
|
+
/** When an unrenewed claim becomes reclaimable. Never later than `attemptDeadlineAt`. */
|
|
201
|
+
visibilityExpiresAt: number;
|
|
202
|
+
/** The ceiling on this attempt. Fixed at claim; heartbeat clamps to it and never moves it. */
|
|
203
|
+
attemptDeadlineAt: number;
|
|
204
|
+
/** Latest liveness evidence from the claimant. Distinct from acknowledgement. */
|
|
205
|
+
lastActivityAt: number;
|
|
206
|
+
/** Optional bounded transport activity evidence (bytes written, a request id). Never used for fencing. */
|
|
207
|
+
transportActivity?: JSONValue | undefined;
|
|
208
|
+
}>;
|
|
209
|
+
/** A delivery leased to an attempt that has not yet durably begun its send.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* import type { ApplicationDeliveryClaimed } from '@lostgradient/weft';
|
|
214
|
+
*
|
|
215
|
+
* declare const record: ApplicationDeliveryClaimed;
|
|
216
|
+
* console.log(record.attemptToken, record.attemptDeadlineAt);
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export type ApplicationDeliveryClaimed = ApplicationDeliveryBase & ApplicationDeliveryAttemptFields & ApplicationDeliveryLeaseFields & Readonly<{
|
|
220
|
+
state: 'claimed';
|
|
221
|
+
availableAt: number;
|
|
222
|
+
}>;
|
|
223
|
+
/**
|
|
224
|
+
* A delivery whose attempt durably began its send. From here on a lost result
|
|
225
|
+
* is an unknown outcome, never a safe retry.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```ts
|
|
229
|
+
* import type { ApplicationDeliveryAttempting } from '@lostgradient/weft';
|
|
230
|
+
*
|
|
231
|
+
* declare const record: ApplicationDeliveryAttempting;
|
|
232
|
+
* console.log(record.attemptStartedAt);
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export type ApplicationDeliveryAttempting = ApplicationDeliveryBase & ApplicationDeliveryAttemptFields & ApplicationDeliveryLeaseFields & Readonly<{
|
|
236
|
+
state: 'attempting';
|
|
237
|
+
availableAt: number;
|
|
238
|
+
attemptStartedAt: number;
|
|
239
|
+
}>;
|
|
240
|
+
/**
|
|
241
|
+
* An attempting delivery whose cancellation is durably requested and whose
|
|
242
|
+
* claimant has not yet settled; only the current attempt can report what the
|
|
243
|
+
* transport did.
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```ts
|
|
247
|
+
* import type { ApplicationDeliveryCancelling } from '@lostgradient/weft';
|
|
248
|
+
*
|
|
249
|
+
* declare const record: ApplicationDeliveryCancelling;
|
|
250
|
+
* console.log(record.cancellationRequestedAt);
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
export type ApplicationDeliveryCancelling = ApplicationDeliveryBase & ApplicationDeliveryAttemptFields & ApplicationDeliveryLeaseFields & Readonly<{
|
|
254
|
+
state: 'cancellation-requested';
|
|
255
|
+
availableAt: number;
|
|
256
|
+
attemptStartedAt: number;
|
|
257
|
+
cancellationRequestedAt: number;
|
|
258
|
+
cancellationReason?: string | undefined;
|
|
259
|
+
}>;
|
|
260
|
+
/**
|
|
261
|
+
* A delivery in a terminal disposition. `cleanupPending` is `true` when an
|
|
262
|
+
* attempt still held it and never settled; `abandonedAttemptToken` names that
|
|
263
|
+
* attempt. The outbox records that it stopped waiting, never that the transport
|
|
264
|
+
* stopped.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* import type { ApplicationDeliveryTerminalRecord } from '@lostgradient/weft';
|
|
269
|
+
*
|
|
270
|
+
* declare const record: ApplicationDeliveryTerminalRecord;
|
|
271
|
+
* console.log(record.state, record.terminalAt);
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
export type ApplicationDeliveryTerminalRecord = ApplicationDeliveryBase & ApplicationDeliveryAttemptFields & Readonly<{
|
|
275
|
+
state: ApplicationDeliveryTerminalState;
|
|
276
|
+
availableAt: number;
|
|
277
|
+
terminalAt: number;
|
|
278
|
+
/** Bounded acknowledgement evidence the transport returned. */
|
|
279
|
+
evidence?: JSONValue | undefined;
|
|
280
|
+
failure?: ApplicationDeliveryFailure | undefined;
|
|
281
|
+
cancellationRequestedAt?: number | undefined;
|
|
282
|
+
cancellationReason?: string | undefined;
|
|
283
|
+
cleanupPending?: boolean | undefined;
|
|
284
|
+
abandonedAttemptToken?: string | undefined;
|
|
285
|
+
}>;
|
|
286
|
+
/**
|
|
287
|
+
* The canonical durable record for one delivery, in whichever state it
|
|
288
|
+
* currently occupies.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```ts
|
|
292
|
+
* import type { ApplicationDeliveryRecord } from '@lostgradient/weft';
|
|
293
|
+
*
|
|
294
|
+
* declare const record: ApplicationDeliveryRecord;
|
|
295
|
+
* console.log(record.deliveryId, record.state);
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
export type ApplicationDeliveryRecord = ApplicationDeliveryQueued | ApplicationDeliveryRetryScheduled | ApplicationDeliveryClaimed | ApplicationDeliveryAttempting | ApplicationDeliveryCancelling | ApplicationDeliveryTerminalRecord;
|
|
299
|
+
/**
|
|
300
|
+
* Any record still holding a lease.
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```ts
|
|
304
|
+
* import type { ApplicationDeliveryLeasedRecord } from '@lostgradient/weft';
|
|
305
|
+
*
|
|
306
|
+
* declare const record: ApplicationDeliveryLeasedRecord;
|
|
307
|
+
* console.log(record.attemptToken, record.attemptDeadlineAt);
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
export type ApplicationDeliveryLeasedRecord = ApplicationDeliveryClaimed | ApplicationDeliveryAttempting | ApplicationDeliveryCancelling;
|
|
311
|
+
/**
|
|
312
|
+
* Any record waiting in the due index.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* import type { ApplicationDeliveryWaitingRecord } from '@lostgradient/weft';
|
|
317
|
+
*
|
|
318
|
+
* declare const record: ApplicationDeliveryWaitingRecord;
|
|
319
|
+
* console.log(record.availableAt);
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
export type ApplicationDeliveryWaitingRecord = ApplicationDeliveryQueued | ApplicationDeliveryRetryScheduled;
|
|
323
|
+
/**
|
|
324
|
+
* The per-outbox header holding the listing sequence allocator and the
|
|
325
|
+
* open-backlog counter enqueue backpressure reads.
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* import type { OutboxRecord } from '@lostgradient/weft';
|
|
330
|
+
*
|
|
331
|
+
* declare const header: OutboxRecord;
|
|
332
|
+
* console.log(header.nextSequence, header.openCount);
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
export type OutboxRecord = Readonly<{
|
|
336
|
+
recordVersion: typeof OUTBOX_RECORD_VERSION;
|
|
337
|
+
namespace: string;
|
|
338
|
+
ownerId: string;
|
|
339
|
+
nextSequence: number;
|
|
340
|
+
/** Deliveries enqueued and not yet terminal. */
|
|
341
|
+
openCount: number;
|
|
342
|
+
/** Lifetime enqueues. Never decremented; diagnostic provenance only. */
|
|
343
|
+
enqueuedCount: number;
|
|
344
|
+
}>;
|
|
345
|
+
/** The idempotency index record binding a retry identity to one enqueued delivery. */
|
|
346
|
+
export type ApplicationDeliveryIdempotencyRecord = Readonly<{
|
|
347
|
+
recordVersion: typeof OUTBOX_RECORD_VERSION;
|
|
348
|
+
deliveryId: string;
|
|
349
|
+
/** The digest of `(destinationRef, kind, payloadDigest)` this key is bound to. */
|
|
350
|
+
identityDigest: string;
|
|
351
|
+
}>;
|
|
352
|
+
/**
|
|
353
|
+
* Whether a delivery state is terminal.
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```ts
|
|
357
|
+
* import { isApplicationDeliveryTerminalState } from '@lostgradient/weft';
|
|
358
|
+
*
|
|
359
|
+
* console.log(isApplicationDeliveryTerminalState('acknowledged')); // true
|
|
360
|
+
* console.log(isApplicationDeliveryTerminalState('attempting')); // false
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
export declare function isApplicationDeliveryTerminalState(state: string): state is ApplicationDeliveryTerminalState;
|
|
364
|
+
/**
|
|
365
|
+
* Whether a record still holds an attempt lease.
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* ```ts
|
|
369
|
+
* import { isApplicationDeliveryLeased, type ApplicationDeliveryRecord } from '@lostgradient/weft';
|
|
370
|
+
*
|
|
371
|
+
* declare const record: ApplicationDeliveryRecord;
|
|
372
|
+
* if (isApplicationDeliveryLeased(record)) console.log(record.attemptToken);
|
|
373
|
+
* ```
|
|
374
|
+
*/
|
|
375
|
+
export declare function isApplicationDeliveryLeased(record: ApplicationDeliveryRecord): record is ApplicationDeliveryLeasedRecord;
|
|
376
|
+
/**
|
|
377
|
+
* Whether a record is waiting in the due index.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```ts
|
|
381
|
+
* import { isApplicationDeliveryWaiting, type ApplicationDeliveryRecord } from '@lostgradient/weft';
|
|
382
|
+
*
|
|
383
|
+
* declare const record: ApplicationDeliveryRecord;
|
|
384
|
+
* if (isApplicationDeliveryWaiting(record)) console.log(record.availableAt);
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
export declare function isApplicationDeliveryWaiting(record: ApplicationDeliveryRecord): record is ApplicationDeliveryWaitingRecord;
|
|
388
|
+
/**
|
|
389
|
+
* Whether a record's attempt durably began its send, so a lost result is an
|
|
390
|
+
* unknown outcome rather than a safe retry.
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```ts
|
|
394
|
+
* import { isApplicationDeliveryAttempting, type ApplicationDeliveryRecord } from '@lostgradient/weft';
|
|
395
|
+
*
|
|
396
|
+
* declare const record: ApplicationDeliveryRecord;
|
|
397
|
+
* if (isApplicationDeliveryAttempting(record)) console.log(record.attemptStartedAt);
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
export declare function isApplicationDeliveryAttempting(record: ApplicationDeliveryRecord): record is ApplicationDeliveryAttempting | ApplicationDeliveryCancelling;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const OUTBOX_RECORD_VERSION = 1, APPLICATION_DELIVERY_TERMINAL_STATES = [
|
|
2
|
+
"acknowledged",
|
|
3
|
+
"rejected",
|
|
4
|
+
"cancelled",
|
|
5
|
+
"unknown-outcome",
|
|
6
|
+
"dead-lettered"
|
|
7
|
+
];
|
|
8
|
+
const TERMINAL_STATE_SET = new Set(APPLICATION_DELIVERY_TERMINAL_STATES);
|
|
9
|
+
export function isApplicationDeliveryTerminalState(state) {
|
|
10
|
+
return TERMINAL_STATE_SET.has(state);
|
|
11
|
+
}
|
|
12
|
+
export function isApplicationDeliveryLeased(record) {
|
|
13
|
+
return record.state === "claimed" || record.state === "attempting" || record.state === "cancellation-requested";
|
|
14
|
+
}
|
|
15
|
+
export function isApplicationDeliveryWaiting(record) {
|
|
16
|
+
return record.state === "queued" || record.state === "retry-scheduled";
|
|
17
|
+
}
|
|
18
|
+
export function isApplicationDeliveryAttempting(record) {
|
|
19
|
+
return record.state === "attempting" || record.state === "cancellation-requested";
|
|
20
|
+
}
|