@lostgradient/weft 0.23.0 → 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-loader.js +2 -2
- package/dist/storage/node-sqlite.js +51 -8
- 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,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applicationCommandIdentityFields,
|
|
3
|
+
computeRetryBackoffMs,
|
|
4
|
+
nonTerminalCommandRecord,
|
|
5
|
+
rejectedTransition,
|
|
6
|
+
succeededTransition
|
|
7
|
+
} from "./mailbox-transition-helpers.js";
|
|
8
|
+
import { requireDerivedInstant } from "./mailbox-validation.js";
|
|
9
|
+
export function recoverExpiredCommand(record, options) {
|
|
10
|
+
const live = nonTerminalCommandRecord(record);
|
|
11
|
+
if (live === null)
|
|
12
|
+
return rejectedTransition("already-terminal");
|
|
13
|
+
if (options.now >= live.absoluteDeadlineAt)
|
|
14
|
+
return succeededTransition(deadlineExceededRecord(live, options.now));
|
|
15
|
+
if (live.state === "accepted" || live.state === "available")
|
|
16
|
+
return rejectedTransition("not-leased");
|
|
17
|
+
if (options.now < live.visibilityExpiresAt)
|
|
18
|
+
return rejectedTransition("not-due");
|
|
19
|
+
if (live.state === "cancellation-requested")
|
|
20
|
+
return succeededTransition({
|
|
21
|
+
...applicationCommandIdentityFields(live),
|
|
22
|
+
state: "cancelled",
|
|
23
|
+
terminalAt: options.now,
|
|
24
|
+
failure: { reason: "cancelled" },
|
|
25
|
+
cancellationRequestedAt: live.cancellationRequestedAt,
|
|
26
|
+
cancellationReason: live.cancellationReason,
|
|
27
|
+
cleanupPending: !0,
|
|
28
|
+
abandonedAttemptToken: live.attemptToken
|
|
29
|
+
});
|
|
30
|
+
if (live.attempt >= live.maxAttempts)
|
|
31
|
+
return succeededTransition({
|
|
32
|
+
...applicationCommandIdentityFields(live),
|
|
33
|
+
state: "dead-lettered",
|
|
34
|
+
terminalAt: options.now,
|
|
35
|
+
failure: { reason: "attempts-exhausted" },
|
|
36
|
+
cleanupPending: !0,
|
|
37
|
+
abandonedAttemptToken: live.attemptToken
|
|
38
|
+
});
|
|
39
|
+
return succeededTransition({
|
|
40
|
+
...applicationCommandIdentityFields(live),
|
|
41
|
+
state: "accepted",
|
|
42
|
+
retryCount: live.retryCount + 1,
|
|
43
|
+
availableAt: requireDerivedInstant(options.now + computeRetryBackoffMs(live.attempt, options.retryBackoffMs, options.maxRetryBackoffMs), "availableAt")
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function deadlineExceededRecord(record, now) {
|
|
47
|
+
const terminal = {
|
|
48
|
+
...applicationCommandIdentityFields(record),
|
|
49
|
+
state: "dead-lettered",
|
|
50
|
+
terminalAt: now,
|
|
51
|
+
failure: { reason: "deadline-exceeded" }
|
|
52
|
+
};
|
|
53
|
+
if (record.state === "cancellation-requested")
|
|
54
|
+
return {
|
|
55
|
+
...terminal,
|
|
56
|
+
cancellationRequestedAt: record.cancellationRequestedAt,
|
|
57
|
+
cancellationReason: record.cancellationReason,
|
|
58
|
+
cleanupPending: !0,
|
|
59
|
+
abandonedAttemptToken: record.attemptToken
|
|
60
|
+
};
|
|
61
|
+
if (record.state === "claimed")
|
|
62
|
+
return { ...terminal, cleanupPending: !0, abandonedAttemptToken: record.attemptToken };
|
|
63
|
+
return terminal;
|
|
64
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure conditional-transition functions for the durable application command
|
|
3
|
+
* mailbox (WFT-84) — one function per legal edge of the mailbox state machine.
|
|
4
|
+
*
|
|
5
|
+
* These functions are storage-agnostic. They take the currently decoded
|
|
6
|
+
* {@link ApplicationCommandRecord} and proposed inputs and return either the
|
|
7
|
+
* next record to persist or a stable rejection reason. They never read or write
|
|
8
|
+
* storage and never see encoded bytes.
|
|
9
|
+
*
|
|
10
|
+
* That last point matters for correctness, not just tidiness.
|
|
11
|
+
* `storage.conditionalBatch` compares whole values byte-for-byte, and
|
|
12
|
+
* `encode(decode(bytes))` is not guaranteed to reproduce the original bytes. The
|
|
13
|
+
* caller that commits a transition must keep the raw `Uint8Array` it read and
|
|
14
|
+
* pass those exact bytes as the compare-and-swap `expectedValue`, using
|
|
15
|
+
* `next` only for what to write.
|
|
16
|
+
*
|
|
17
|
+
* The legal edges are:
|
|
18
|
+
*
|
|
19
|
+
* ```text
|
|
20
|
+
* (none) --admit--> accepted | available
|
|
21
|
+
* accepted --release(now>=due)--> available
|
|
22
|
+
* accepted --claim(now>=due)--> claimed
|
|
23
|
+
* available --claim--> claimed
|
|
24
|
+
* claimed --acknowledge--> applied
|
|
25
|
+
* claimed --reject(final)--> rejected
|
|
26
|
+
* claimed --reject(retry)--> accepted (backoff, attempts remain)
|
|
27
|
+
* claimed --reject(retry)--> dead-lettered (attempts exhausted)
|
|
28
|
+
* claimed --expire--> accepted | dead-lettered
|
|
29
|
+
* claimed --cancel--> cancellation-requested
|
|
30
|
+
* cancellation-requested --settle--> cancelled
|
|
31
|
+
* cancellation-requested --expire--> cancelled (cleanupPending)
|
|
32
|
+
* accepted | available --cancel--> cancelled
|
|
33
|
+
* any non-terminal --deadline--> dead-lettered
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @module core/mailbox-transitions
|
|
37
|
+
*/
|
|
38
|
+
import type { JSONValue } from './json.ts';
|
|
39
|
+
import { type MailboxTransition } from './mailbox-transition-helpers.ts';
|
|
40
|
+
import type { ApplicationCommandAccepted, ApplicationCommandAvailable, ApplicationCommandCancelling, ApplicationCommandClaimed, ApplicationCommandFailure, ApplicationCommandLeasedRecord, ApplicationCommandRecord, ApplicationCommandTerminalRecord, ApplicationCommandWaitingRecord } from './mailbox-types.ts';
|
|
41
|
+
import { type ValidatedCommandInput } from './mailbox-validation.ts';
|
|
42
|
+
export { computeRetryBackoffMs, isTerminalCommandRecord, nonTerminalCommandRecord, } from './mailbox-transition-helpers.ts';
|
|
43
|
+
export type { MailboxTransition, MailboxTransitionRejection, } from './mailbox-transition-helpers.ts';
|
|
44
|
+
/**
|
|
45
|
+
* Build the record for a freshly admitted command.
|
|
46
|
+
*
|
|
47
|
+
* A command with no delay is admitted straight to `available`; one with a delay
|
|
48
|
+
* is admitted `accepted` and released later. Both are durable receipts.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createAdmittedCommandRecord(input: ValidatedCommandInput, context: {
|
|
51
|
+
readonly namespace: string;
|
|
52
|
+
readonly resourceId: string;
|
|
53
|
+
readonly commandId: string;
|
|
54
|
+
readonly sequence: number;
|
|
55
|
+
readonly now: number;
|
|
56
|
+
}): ApplicationCommandAccepted | ApplicationCommandAvailable;
|
|
57
|
+
/**
|
|
58
|
+
* Release a delayed command for delivery once its `availableAt` has passed.
|
|
59
|
+
*/
|
|
60
|
+
export declare function releaseWaitingCommand(record: ApplicationCommandRecord, now: number): MailboxTransition<ApplicationCommandAvailable>;
|
|
61
|
+
/**
|
|
62
|
+
* Lease a waiting command to one attempt.
|
|
63
|
+
*
|
|
64
|
+
* The lease never outlives the absolute command deadline: `visibilityExpiresAt`
|
|
65
|
+
* is clamped to it, so an attempt cannot hold work past the ceiling admission
|
|
66
|
+
* set.
|
|
67
|
+
*/
|
|
68
|
+
export declare function claimWaitingCommand(record: ApplicationCommandRecord, options: {
|
|
69
|
+
readonly now: number;
|
|
70
|
+
readonly attemptToken: string;
|
|
71
|
+
}): MailboxTransition<ApplicationCommandClaimed>;
|
|
72
|
+
/**
|
|
73
|
+
* Extend a lease and record liveness for the current attempt.
|
|
74
|
+
*
|
|
75
|
+
* Renewal is attempt-fenced and clamped: it can never move
|
|
76
|
+
* `absoluteDeadlineAt`, so an indefinitely renewing claimant still hits the
|
|
77
|
+
* command ceiling. `lastActivityAt` is transport liveness and stays separate
|
|
78
|
+
* from `progress`, which is caller-supplied semantic progress and is never used
|
|
79
|
+
* for fencing.
|
|
80
|
+
*/
|
|
81
|
+
export declare function renewCommandLease(record: ApplicationCommandRecord, options: {
|
|
82
|
+
readonly attemptToken: string;
|
|
83
|
+
readonly now: number;
|
|
84
|
+
readonly progress?: JSONValue | undefined;
|
|
85
|
+
}): MailboxTransition<ApplicationCommandLeasedRecord>;
|
|
86
|
+
/**
|
|
87
|
+
* Settle a claimed command successfully.
|
|
88
|
+
*
|
|
89
|
+
* A command whose cancellation was already requested settles as `cancelled`
|
|
90
|
+
* rather than `applied`: the claimant finished cleanup, so cleanup is settled,
|
|
91
|
+
* but the durable cancellation request is not overwritten by a success.
|
|
92
|
+
*
|
|
93
|
+
* The caller's `outcome` is still retained on that `cancelled` receipt. A
|
|
94
|
+
* claimant that completed the work before it observed the cancellation really
|
|
95
|
+
* did produce a result, and discarding it would lose evidence a reader may need
|
|
96
|
+
* to decide whether the effect already happened.
|
|
97
|
+
*/
|
|
98
|
+
export declare function acknowledgeCommand(record: ApplicationCommandRecord, options: {
|
|
99
|
+
readonly attemptToken: string;
|
|
100
|
+
readonly now: number;
|
|
101
|
+
readonly outcome?: JSONValue | undefined;
|
|
102
|
+
}): MailboxTransition<ApplicationCommandTerminalRecord>;
|
|
103
|
+
/**
|
|
104
|
+
* Settle a claimed command as failed, optionally scheduling a retry.
|
|
105
|
+
*
|
|
106
|
+
* A retry that still has attempts left returns the command to `accepted` at its
|
|
107
|
+
* original FIFO position with a backoff; one that does not is dead-lettered
|
|
108
|
+
* with `attempts-exhausted`. A cancellation-requested command always settles as
|
|
109
|
+
* `cancelled` — a failed cleanup is still cleanup.
|
|
110
|
+
*/
|
|
111
|
+
export declare function rejectCommand(record: ApplicationCommandRecord, options: {
|
|
112
|
+
readonly attemptToken: string;
|
|
113
|
+
readonly now: number;
|
|
114
|
+
readonly retry: boolean;
|
|
115
|
+
readonly failure: ApplicationCommandFailure;
|
|
116
|
+
readonly retryBackoffMs: number;
|
|
117
|
+
readonly maxRetryBackoffMs: number;
|
|
118
|
+
}): MailboxTransition<ApplicationCommandAccepted | ApplicationCommandTerminalRecord>;
|
|
119
|
+
/**
|
|
120
|
+
* Record a durable cancellation request.
|
|
121
|
+
*
|
|
122
|
+
* An unclaimed command cancels immediately with nothing to clean up. A claimed
|
|
123
|
+
* one keeps its lease and moves to `cancellation-requested`, so only the
|
|
124
|
+
* current attempt can settle it. Requesting cancellation twice is idempotent:
|
|
125
|
+
* the second request rejects with `not-leased` against a record already in
|
|
126
|
+
* `cancellation-requested`, which the caller reports as the same outcome.
|
|
127
|
+
*/
|
|
128
|
+
export declare function requestCommandCancellation(record: ApplicationCommandRecord, options: {
|
|
129
|
+
readonly now: number;
|
|
130
|
+
readonly reason?: string | undefined;
|
|
131
|
+
}): MailboxTransition<ApplicationCommandCancelling | ApplicationCommandTerminalRecord>;
|
|
132
|
+
/**
|
|
133
|
+
* Whether a waiting or leased record is past its absolute command deadline and
|
|
134
|
+
* must be terminalized before anything else can happen to it.
|
|
135
|
+
*/
|
|
136
|
+
export declare function isCommandPastDeadline(record: ApplicationCommandRecord, now: number): boolean;
|
|
137
|
+
/** Narrowing helper for callers that already proved a record is waiting. */
|
|
138
|
+
export declare function asWaitingRecord(record: ApplicationCommandRecord): ApplicationCommandWaitingRecord | null;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applicationCommandIdentityFields,
|
|
3
|
+
computeRetryBackoffMs,
|
|
4
|
+
nonTerminalCommandRecord,
|
|
5
|
+
rejectedTransition,
|
|
6
|
+
succeededTransition
|
|
7
|
+
} from "./mailbox-transition-helpers.js";
|
|
8
|
+
import { MAILBOX_RECORD_VERSION, isApplicationCommandTerminalState } from "./mailbox-types.js";
|
|
9
|
+
import { requireDerivedInstant } from "./mailbox-validation.js";
|
|
10
|
+
export {
|
|
11
|
+
computeRetryBackoffMs,
|
|
12
|
+
isTerminalCommandRecord,
|
|
13
|
+
nonTerminalCommandRecord
|
|
14
|
+
} from "./mailbox-transition-helpers.js";
|
|
15
|
+
export function createAdmittedCommandRecord(input, context) {
|
|
16
|
+
const availableAt = requireDerivedInstant(context.now + input.availableAfterMs, "availableAt"), absoluteDeadlineAt = requireDerivedInstant(context.now + input.commandTimeoutMs, "absoluteDeadlineAt"), base = {
|
|
17
|
+
recordVersion: MAILBOX_RECORD_VERSION,
|
|
18
|
+
namespace: context.namespace,
|
|
19
|
+
resourceId: context.resourceId,
|
|
20
|
+
commandId: context.commandId,
|
|
21
|
+
sequence: context.sequence,
|
|
22
|
+
idempotencyKey: input.idempotencyKey,
|
|
23
|
+
caller: input.caller,
|
|
24
|
+
target: input.target,
|
|
25
|
+
kind: input.kind,
|
|
26
|
+
payload: input.payload,
|
|
27
|
+
payloadDigest: input.payloadDigest,
|
|
28
|
+
payloadMediaType: input.payloadMediaType,
|
|
29
|
+
payloadSchema: input.payloadSchema,
|
|
30
|
+
causation: input.causation,
|
|
31
|
+
acceptedAt: context.now,
|
|
32
|
+
availableAt,
|
|
33
|
+
absoluteDeadlineAt,
|
|
34
|
+
maxAttempts: input.maxAttempts,
|
|
35
|
+
visibilityTimeoutMs: input.visibilityTimeoutMs,
|
|
36
|
+
generation: 0,
|
|
37
|
+
attempt: 0,
|
|
38
|
+
retryCount: 0
|
|
39
|
+
};
|
|
40
|
+
return availableAt <= context.now ? { ...base, state: "available" } : { ...base, state: "accepted" };
|
|
41
|
+
}
|
|
42
|
+
export function releaseWaitingCommand(record, now) {
|
|
43
|
+
const live = nonTerminalCommandRecord(record);
|
|
44
|
+
if (live === null)
|
|
45
|
+
return rejectedTransition("already-terminal");
|
|
46
|
+
if (live.state !== "accepted")
|
|
47
|
+
return rejectedTransition("not-waiting");
|
|
48
|
+
if (now < live.availableAt)
|
|
49
|
+
return rejectedTransition("not-due");
|
|
50
|
+
return succeededTransition({ ...applicationCommandIdentityFields(live), state: "available" });
|
|
51
|
+
}
|
|
52
|
+
export function claimWaitingCommand(record, options) {
|
|
53
|
+
const live = nonTerminalCommandRecord(record);
|
|
54
|
+
if (live === null)
|
|
55
|
+
return rejectedTransition("already-terminal");
|
|
56
|
+
if (live.state !== "accepted" && live.state !== "available")
|
|
57
|
+
return rejectedTransition("not-waiting");
|
|
58
|
+
if (options.now < live.availableAt)
|
|
59
|
+
return rejectedTransition("not-due");
|
|
60
|
+
if (options.now >= live.absoluteDeadlineAt)
|
|
61
|
+
return rejectedTransition("deadline-exceeded");
|
|
62
|
+
return succeededTransition({
|
|
63
|
+
...applicationCommandIdentityFields(live),
|
|
64
|
+
state: "claimed",
|
|
65
|
+
attempt: live.attempt + 1,
|
|
66
|
+
firstClaimedAt: live.firstClaimedAt ?? options.now,
|
|
67
|
+
attemptToken: options.attemptToken,
|
|
68
|
+
claimedAt: options.now,
|
|
69
|
+
visibilityExpiresAt: Math.min(options.now + live.visibilityTimeoutMs, live.absoluteDeadlineAt),
|
|
70
|
+
lastActivityAt: options.now
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function checkCurrentAttempt(record, attemptToken, now) {
|
|
74
|
+
if (isApplicationCommandTerminalState(record.state))
|
|
75
|
+
return { ok: !1, reason: "already-terminal" };
|
|
76
|
+
if (record.state !== "claimed" && record.state !== "cancellation-requested")
|
|
77
|
+
return { ok: !1, reason: "not-leased" };
|
|
78
|
+
if (record.attemptToken !== attemptToken)
|
|
79
|
+
return { ok: !1, reason: "stale-attempt" };
|
|
80
|
+
if (now >= record.absoluteDeadlineAt)
|
|
81
|
+
return { ok: !1, reason: "deadline-exceeded" };
|
|
82
|
+
return { ok: !0, leased: record };
|
|
83
|
+
}
|
|
84
|
+
export function renewCommandLease(record, options) {
|
|
85
|
+
const checked = checkCurrentAttempt(record, options.attemptToken, options.now);
|
|
86
|
+
if (!checked.ok)
|
|
87
|
+
return rejectedTransition(checked.reason);
|
|
88
|
+
const { leased } = checked, renewed = {
|
|
89
|
+
...leased,
|
|
90
|
+
generation: leased.generation + 1,
|
|
91
|
+
lastActivityAt: options.now,
|
|
92
|
+
visibilityExpiresAt: Math.min(options.now + leased.visibilityTimeoutMs, leased.absoluteDeadlineAt),
|
|
93
|
+
progress: options.progress === void 0 ? leased.progress : options.progress
|
|
94
|
+
};
|
|
95
|
+
return succeededTransition(renewed);
|
|
96
|
+
}
|
|
97
|
+
export function acknowledgeCommand(record, options) {
|
|
98
|
+
const checked = checkCurrentAttempt(record, options.attemptToken, options.now);
|
|
99
|
+
if (!checked.ok)
|
|
100
|
+
return rejectedTransition(checked.reason);
|
|
101
|
+
const { leased } = checked, cancelling = leased.state === "cancellation-requested";
|
|
102
|
+
return succeededTransition({
|
|
103
|
+
...applicationCommandIdentityFields(leased),
|
|
104
|
+
state: cancelling ? "cancelled" : "applied",
|
|
105
|
+
terminalAt: options.now,
|
|
106
|
+
outcome: options.outcome,
|
|
107
|
+
failure: cancelling ? { reason: "cancelled" } : void 0,
|
|
108
|
+
cancellationRequestedAt: cancelling ? leased.cancellationRequestedAt : void 0,
|
|
109
|
+
cancellationReason: cancelling ? leased.cancellationReason : void 0,
|
|
110
|
+
cleanupPending: cancelling ? !1 : void 0
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
export function rejectCommand(record, options) {
|
|
114
|
+
const checked = checkCurrentAttempt(record, options.attemptToken, options.now);
|
|
115
|
+
if (!checked.ok)
|
|
116
|
+
return rejectedTransition(checked.reason);
|
|
117
|
+
const { leased } = checked;
|
|
118
|
+
if (leased.state === "cancellation-requested")
|
|
119
|
+
return succeededTransition({
|
|
120
|
+
...applicationCommandIdentityFields(leased),
|
|
121
|
+
state: "cancelled",
|
|
122
|
+
terminalAt: options.now,
|
|
123
|
+
failure: { reason: "cancelled" },
|
|
124
|
+
cancellationRequestedAt: leased.cancellationRequestedAt,
|
|
125
|
+
cancellationReason: leased.cancellationReason,
|
|
126
|
+
cleanupPending: !1
|
|
127
|
+
});
|
|
128
|
+
if (!options.retry)
|
|
129
|
+
return succeededTransition({
|
|
130
|
+
...applicationCommandIdentityFields(leased),
|
|
131
|
+
state: "rejected",
|
|
132
|
+
terminalAt: options.now,
|
|
133
|
+
failure: options.failure
|
|
134
|
+
});
|
|
135
|
+
if (leased.attempt >= leased.maxAttempts)
|
|
136
|
+
return succeededTransition({
|
|
137
|
+
...applicationCommandIdentityFields(leased),
|
|
138
|
+
state: "dead-lettered",
|
|
139
|
+
terminalAt: options.now,
|
|
140
|
+
failure: { ...options.failure, reason: "attempts-exhausted" }
|
|
141
|
+
});
|
|
142
|
+
return succeededTransition({
|
|
143
|
+
...applicationCommandIdentityFields(leased),
|
|
144
|
+
state: "accepted",
|
|
145
|
+
retryCount: leased.retryCount + 1,
|
|
146
|
+
availableAt: requireDerivedInstant(options.now + computeRetryBackoffMs(leased.attempt, options.retryBackoffMs, options.maxRetryBackoffMs), "availableAt")
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
export function requestCommandCancellation(record, options) {
|
|
150
|
+
const live = nonTerminalCommandRecord(record);
|
|
151
|
+
if (live === null)
|
|
152
|
+
return rejectedTransition("already-terminal");
|
|
153
|
+
if (options.now >= live.absoluteDeadlineAt)
|
|
154
|
+
return rejectedTransition("deadline-exceeded");
|
|
155
|
+
if (live.state === "cancellation-requested")
|
|
156
|
+
return rejectedTransition("not-leased");
|
|
157
|
+
if (live.state === "claimed")
|
|
158
|
+
return succeededTransition({
|
|
159
|
+
...live,
|
|
160
|
+
generation: live.generation + 1,
|
|
161
|
+
state: "cancellation-requested",
|
|
162
|
+
cancellationRequestedAt: options.now,
|
|
163
|
+
cancellationReason: options.reason
|
|
164
|
+
});
|
|
165
|
+
return succeededTransition({
|
|
166
|
+
...applicationCommandIdentityFields(live),
|
|
167
|
+
state: "cancelled",
|
|
168
|
+
terminalAt: options.now,
|
|
169
|
+
failure: { reason: "cancelled" },
|
|
170
|
+
cancellationRequestedAt: options.now,
|
|
171
|
+
cancellationReason: options.reason,
|
|
172
|
+
cleanupPending: !1
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
export function isCommandPastDeadline(record, now) {
|
|
176
|
+
return !isApplicationCommandTerminalState(record.state) && now >= record.absoluteDeadlineAt;
|
|
177
|
+
}
|
|
178
|
+
export function asWaitingRecord(record) {
|
|
179
|
+
return record.state === "accepted" || record.state === "available" ? record : null;
|
|
180
|
+
}
|