@loomwork/event-runtime 0.0.0-stage → 0.1.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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +95 -2
- package/dist/BranchRegistry.d.ts +140 -0
- package/dist/BranchRegistry.d.ts.map +1 -0
- package/dist/BranchRegistry.js +66 -0
- package/dist/BranchRegistry.js.map +1 -0
- package/dist/CoalescingEventStore.d.ts +97 -0
- package/dist/CoalescingEventStore.d.ts.map +1 -0
- package/dist/CoalescingEventStore.js +180 -0
- package/dist/CoalescingEventStore.js.map +1 -0
- package/dist/InMemoryArchiveStore.d.ts +19 -0
- package/dist/InMemoryArchiveStore.d.ts.map +1 -0
- package/dist/InMemoryArchiveStore.js +49 -0
- package/dist/InMemoryArchiveStore.js.map +1 -0
- package/dist/InMemoryAsyncEventStore.d.ts +111 -0
- package/dist/InMemoryAsyncEventStore.d.ts.map +1 -0
- package/dist/InMemoryAsyncEventStore.js +374 -0
- package/dist/InMemoryAsyncEventStore.js.map +1 -0
- package/dist/InMemoryBranchRegistry.d.ts +31 -0
- package/dist/InMemoryBranchRegistry.d.ts.map +1 -0
- package/dist/InMemoryBranchRegistry.js +167 -0
- package/dist/InMemoryBranchRegistry.js.map +1 -0
- package/dist/ProfilingEventStore.d.ts +75 -0
- package/dist/ProfilingEventStore.d.ts.map +1 -0
- package/dist/ProfilingEventStore.js +133 -0
- package/dist/ProfilingEventStore.js.map +1 -0
- package/dist/ShardPlan.d.ts +87 -0
- package/dist/ShardPlan.d.ts.map +1 -0
- package/dist/ShardPlan.js +193 -0
- package/dist/ShardPlan.js.map +1 -0
- package/dist/ShardedEventStore.d.ts +149 -0
- package/dist/ShardedEventStore.d.ts.map +1 -0
- package/dist/ShardedEventStore.js +468 -0
- package/dist/ShardedEventStore.js.map +1 -0
- package/dist/SubscriberRegistry.d.ts +59 -0
- package/dist/SubscriberRegistry.d.ts.map +1 -0
- package/dist/SubscriberRegistry.js +113 -0
- package/dist/SubscriberRegistry.js.map +1 -0
- package/dist/TenantScopedArchiveStore.d.ts +36 -0
- package/dist/TenantScopedArchiveStore.d.ts.map +1 -0
- package/dist/TenantScopedArchiveStore.js +96 -0
- package/dist/TenantScopedArchiveStore.js.map +1 -0
- package/dist/TenantScopedEventStore.d.ts +59 -0
- package/dist/TenantScopedEventStore.d.ts.map +1 -0
- package/dist/TenantScopedEventStore.js +227 -0
- package/dist/TenantScopedEventStore.js.map +1 -0
- package/dist/archive.d.ts +68 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +207 -0
- package/dist/archive.js.map +1 -0
- package/dist/archiveSpi.d.ts +165 -0
- package/dist/archiveSpi.d.ts.map +1 -0
- package/dist/archiveSpi.js +184 -0
- package/dist/archiveSpi.js.map +1 -0
- package/dist/creationMarker.d.ts +13 -0
- package/dist/creationMarker.d.ts.map +1 -0
- package/dist/creationMarker.js +17 -0
- package/dist/creationMarker.js.map +1 -0
- package/dist/decoratorPlan.typecheck.d.ts +2 -0
- package/dist/decoratorPlan.typecheck.d.ts.map +1 -0
- package/dist/decoratorPlan.typecheck.js +41 -0
- package/dist/decoratorPlan.typecheck.js.map +1 -0
- package/dist/eventKindClass.d.ts +40 -0
- package/dist/eventKindClass.d.ts.map +1 -0
- package/dist/eventKindClass.js +99 -0
- package/dist/eventKindClass.js.map +1 -0
- package/dist/executionIdOrder.d.ts +21 -0
- package/dist/executionIdOrder.d.ts.map +1 -0
- package/dist/executionIdOrder.js +43 -0
- package/dist/executionIdOrder.js.map +1 -0
- package/dist/fencing.d.ts +21 -0
- package/dist/fencing.d.ts.map +1 -0
- package/dist/fencing.js +36 -0
- package/dist/fencing.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/installOptional.d.ts +52 -0
- package/dist/installOptional.d.ts.map +1 -0
- package/dist/installOptional.js +112 -0
- package/dist/installOptional.js.map +1 -0
- package/dist/keyUnavailable.d.ts +67 -0
- package/dist/keyUnavailable.d.ts.map +1 -0
- package/dist/keyUnavailable.js +87 -0
- package/dist/keyUnavailable.js.map +1 -0
- package/dist/leases.d.ts +177 -0
- package/dist/leases.d.ts.map +1 -0
- package/dist/leases.js +142 -0
- package/dist/leases.js.map +1 -0
- package/dist/payloadShredded.d.ts +30 -0
- package/dist/payloadShredded.d.ts.map +1 -0
- package/dist/payloadShredded.js +67 -0
- package/dist/payloadShredded.js.map +1 -0
- package/dist/scaleDecorators.bench.d.ts +2 -0
- package/dist/scaleDecorators.bench.d.ts.map +1 -0
- package/dist/scaleDecorators.bench.js +93 -0
- package/dist/scaleDecorators.bench.js.map +1 -0
- package/dist/sequenceRange.bench.d.ts +2 -0
- package/dist/sequenceRange.bench.d.ts.map +1 -0
- package/dist/sequenceRange.bench.js +46 -0
- package/dist/sequenceRange.bench.js.map +1 -0
- package/dist/sequenceRange.d.ts +10 -0
- package/dist/sequenceRange.d.ts.map +1 -0
- package/dist/sequenceRange.js +35 -0
- package/dist/sequenceRange.js.map +1 -0
- package/dist/timers.d.ts +87 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +68 -0
- package/dist/timers.js.map +1 -0
- package/dist/types.d.ts +634 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +429 -0
- package/dist/types.js.map +1 -0
- package/dist/writeConflicts.d.ts +46 -0
- package/dist/writeConflicts.d.ts.map +1 -0
- package/dist/writeConflicts.js +63 -0
- package/dist/writeConflicts.js.map +1 -0
- package/memory.d.ts +4 -0
- package/memory.js +13 -0
- package/package.json +67 -3
- package/sequence.d.ts +1 -0
- package/sequence.js +5 -0
- package/src/BranchRegistry.ts +161 -0
- package/src/CoalescingEventStore.ts +214 -0
- package/src/InMemoryArchiveStore.ts +69 -0
- package/src/InMemoryAsyncEventStore.ts +425 -0
- package/src/InMemoryBranchRegistry.ts +178 -0
- package/src/ProfilingEventStore.ts +153 -0
- package/src/ShardPlan.ts +235 -0
- package/src/ShardedEventStore.ts +557 -0
- package/src/SubscriberRegistry.ts +115 -0
- package/src/TenantScopedArchiveStore.ts +114 -0
- package/src/TenantScopedEventStore.ts +266 -0
- package/src/archive.ts +248 -0
- package/src/archiveSpi.ts +308 -0
- package/src/creationMarker.ts +15 -0
- package/src/decoratorPlan.typecheck.ts +52 -0
- package/src/eventKindClass.ts +127 -0
- package/src/executionIdOrder.ts +38 -0
- package/src/fencing.ts +31 -0
- package/src/index.ts +151 -0
- package/src/installOptional.ts +136 -0
- package/src/keyUnavailable.ts +98 -0
- package/src/leases.ts +319 -0
- package/src/payloadShredded.ts +63 -0
- package/src/scaleDecorators.bench.ts +107 -0
- package/src/sequenceRange.bench.ts +51 -0
- package/src/sequenceRange.ts +35 -0
- package/src/timers.ts +150 -0
- package/src/types.ts +857 -0
- package/src/writeConflicts.ts +56 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
import type { EventEnvelope } from "@loomwork/core";
|
|
2
|
+
export type { EventEnvelope };
|
|
3
|
+
/**
|
|
4
|
+
* SPI version for the {@link EventStore} contract (ADR 0033). Bump MINOR when adding an
|
|
5
|
+
* optional method, MAJOR when changing a required method's contract. Pinned by
|
|
6
|
+
* `runEventStoreConformance` in `@loomwork/testing`.
|
|
7
|
+
*
|
|
8
|
+
* 1.1.0: added optional `listExecutions()` (enumerate distinct executionIds — powers
|
|
9
|
+
* `loom retention run` / `loom compliance report` over cold storage).
|
|
10
|
+
* 1.2.0: added optional `listExecutionsPage()` (SP-1, db-copilot infra #184 — keyset-paged
|
|
11
|
+
* enumeration so maintenance passes run in bounded memory at year scale). Consumers use
|
|
12
|
+
* {@link iterateExecutionIds}, which prefers pages and falls back to `listExecutions()`.
|
|
13
|
+
* 1.3.0: added optional `appendBatch()` (ADR 0074 D1 — one round-trip for many envelopes,
|
|
14
|
+
* which is what lets `CoalescingEventStore` raise the write ceiling). Consumers use
|
|
15
|
+
* {@link appendBatchOf}, which prefers it and falls back to a per-envelope `append` loop,
|
|
16
|
+
* so a backend that omits it is byte-identical to before.
|
|
17
|
+
* 1.4.0: added optional `head()` (the tip as one indexed `MAX(sequence)` — `fork()` was
|
|
18
|
+
* reading the whole parent log to validate a fork point). Consumers use {@link headOf}.
|
|
19
|
+
* 1.5.0: added optional `truncatePrefixKeeping()` (ADR 0106 — compaction that keeps an app's
|
|
20
|
+
* pinned event kinds, ADR 0055 D1). A store that omits it never loses an event, but
|
|
21
|
+
* `LogLifecycle.compact` then can NEVER compact past the first pinned event (it stops just
|
|
22
|
+
* below it on every pass, and warns): a long-lived execution that records a finding early
|
|
23
|
+
* keeps an unbounded replay tail on such a store.
|
|
24
|
+
* 2.0.0: `listExecutionsPage()` ORDER and CURSOR pinned (L10, ADR 0108). "Lexicographic"
|
|
25
|
+
* named no one order: a Postgres store paged in the database collation (`en_US.UTF-8`:
|
|
26
|
+
* `a_b` < `A1`) while `ShardedEventStore` merged in JavaScript's (`A1` < `a_b`), and
|
|
27
|
+
* resuming every shard from the merged page's last id skipped executions. Ids now page in
|
|
28
|
+
* Unicode CODE POINT order ({@link compareExecutionIds}; = UTF-8 byte order, SQL
|
|
29
|
+
* `COLLATE "C"`, SQLite BINARY); the cursor, which was OPAQUE, is now an executionId — any
|
|
30
|
+
* string, the page holding the ids strictly after it; and `nextCursor` MUST be the page's
|
|
31
|
+
* last id. MAJOR because a conforming 1.x store (any order, any opaque cursor token) can
|
|
32
|
+
* fail the kit, and `TenantScopedEventStore`/`ShardedEventStore` now depend on all three —
|
|
33
|
+
* the same rule that made MemoryStore 2.0.0 (ADR 0091). No method was added or removed: a
|
|
34
|
+
* store that already paged ids in that order with id cursors (SQLite; the in-memory store
|
|
35
|
+
* on well-formed BMP ids) conforms unchanged.
|
|
36
|
+
* 2.1.0: the optional `acquireFenceIf(id, { fence, parkSeq })` (ADR 0118 R8k: an atomic
|
|
37
|
+
* compare-and-set on the fence token AND "no answering event past the park"). The constant
|
|
38
|
+
* moved with the rest of the Wave 2 bump (W2-0); the method, its conformance cases and the
|
|
39
|
+
* decorator forwarding landed with R8k. It reads the classification W2-0 shipped:
|
|
40
|
+
* {@link EVENT_KIND_CLASS} / {@link isAnsweringKind} (every kernel event kind is `answering`
|
|
41
|
+
* or `ignorable`, a required total map). No existing method changed, so a 2.0.0 store conforms.
|
|
42
|
+
* 2.2.0: the optional `appendIfUnchanged(id, event, { head, fence, anchor })` (ADR 0116 amendment, R11:
|
|
43
|
+
* a late reward on a finished execution). ONE atomic step: append `event` iff the execution
|
|
44
|
+
* still EXISTS (sequence 0), its stored head is exactly `expect.head` AND its fence token is
|
|
45
|
+
* exactly `expect.fence`; otherwise change nothing and report the current tip. It never
|
|
46
|
+
* presents or adopts a fence token, so it can neither supersede a live holder nor be
|
|
47
|
+
* written under one it did not observe. A store that omits it makes `recordOutcome` refuse.
|
|
48
|
+
* No existing method changed, so a 2.1.0 store conforms.
|
|
49
|
+
* 2.3.0: a SEMANTIC minor, no signature change (ADR 0129). The `anchor` of an observation MUST
|
|
50
|
+
* differ between two incarnations of an execution id, EVEN WHEN their sequence-0 envelopes
|
|
51
|
+
* are byte-identical (a delete followed by a re-creation under a frozen clock). A store
|
|
52
|
+
* claiming 2.3.0 therefore assigns a monotonic incarnation when it durably creates sequence 0
|
|
53
|
+
* and returns it as the anchor; it lives in STORE METADATA only, never in an event, a fold, a
|
|
54
|
+
* snapshot or a hash, so replay stays byte-identical. A log created before the store gained
|
|
55
|
+
* that metadata may keep the legacy {@link creationMarker} (`timestamp:id`) until it is
|
|
56
|
+
* deleted (no backfill). A store that cannot assign one keeps 2.2.0 behaviour and does not
|
|
57
|
+
* claim 2.3.0.
|
|
58
|
+
* 2.4.0: the optional `storeNow(): Promise<number>` (ADR 0110 amendment, D10a) - the store's OWN
|
|
59
|
+
* clock in epoch ms, the one a multi-node fleet shares (Postgres: database time), the EventStore
|
|
60
|
+
* twin of `LeaseStore.storeNow()` (L29). It lets two nodes agree on an age (a message's TTL is
|
|
61
|
+
* judged against the instant it was stamped) without trusting either node's wall clock. A
|
|
62
|
+
* single-process store (memory, SQLite) need not implement it; a caller then falls back to its
|
|
63
|
+
* injected clock. Values must be finite, non-negative, and non-decreasing across sequential
|
|
64
|
+
* calls. Additive: no existing method changed, so a 2.3.0 store conforms.
|
|
65
|
+
* 2.5.0: the optional `sealingCapability(): SealingCapability | undefined` (ADR 0130 residuals D7,
|
|
66
|
+
* RESERVED - no behaviour yet): what this node's store seals AND therefore opens, so the kernel
|
|
67
|
+
* can compare it to a `metadata.seal` marker ({@link SealMarker}) on a stored envelope. Absent, or
|
|
68
|
+
* returning `undefined`, means "seals nothing, opens nothing" (the correct reading for a store
|
|
69
|
+
* that cannot open sealed data). Every decorator forwards, overrides or refuses it (it is listed
|
|
70
|
+
* in {@link OPTIONAL_EVENT_STORE_METHODS}); `ShardedEventStore` returns a capability only when
|
|
71
|
+
* every shard agrees. Also reserves the control stream prefix {@link QUARANTINE_STREAM_PREFIX}
|
|
72
|
+
* (`__loom_quarantine__:<chainId>`). Also the optional `readAtRest(): AtRestEventReader` (ADR 0130
|
|
73
|
+
* D9): a read-only view of the envelopes AS STORED (never decrypted), so the quarantine verbs can
|
|
74
|
+
* step over a sealed value without asking the KeyStore; replaces a hidden symbol protocol. Every
|
|
75
|
+
* decorator forwards it (`EncryptingEventStore` overrides it with its inner store's raw reads,
|
|
76
|
+
* `ShardedEventStore` routes per stream). Additive: no existing method changed, so a 2.4.0 store
|
|
77
|
+
* conforms.
|
|
78
|
+
* 2.6.0: the optional `deleteThrough(executionId, through)` (ADR 0139 D8): one atomic delete of every
|
|
79
|
+
* event with `sequence <= through`, sequence 0 included. A caller that archived a stream up to
|
|
80
|
+
* `through` (the terminal delete of a durable inbox) removes exactly what it archived, so a message
|
|
81
|
+
* appended in between survives. Every decorator forwards it. Additive: no existing method changed, so a
|
|
82
|
+
* 2.5.0 store conforms (a caller then refuses the delete it cannot make safe).
|
|
83
|
+
*
|
|
84
|
+
* Every optional method is listed in {@link OPTIONAL_EVENT_STORE_METHODS}; adding one here
|
|
85
|
+
* without listing it there is a compile error. `OptionalEventStoreMethod` is derived from this
|
|
86
|
+
* interface, and `DecoratorPlan` makes every one of its keys REQUIRED, so a new optional method
|
|
87
|
+
* is also a compile error in every decorator whose plan `satisfies DecoratorPlan<EventStore,
|
|
88
|
+
* OptionalEventStoreMethod>` until it forwards, overrides or refuses it. A decorator that uses
|
|
89
|
+
* no plan at all is caught by the decorator conformance kit instead (and the `packages/spec`
|
|
90
|
+
* fitness test makes every in-repo decorator run it).
|
|
91
|
+
*/
|
|
92
|
+
export declare const EVENT_STORE_SPI_VERSION = "2.6.0";
|
|
93
|
+
/**
|
|
94
|
+
* Reserved-stream prefix. Control facts (retention `__loom_lifecycle__`, erasure
|
|
95
|
+
* `__loom_erasure__`) are stored under executionIds beginning with this, so
|
|
96
|
+
* {@link listExecutions} surfaces them too. Enumerators over *real* executions filter with
|
|
97
|
+
* {@link isReservedStream}.
|
|
98
|
+
*/
|
|
99
|
+
export declare const RESERVED_STREAM_PREFIX = "__loom_";
|
|
100
|
+
/**
|
|
101
|
+
* Whether an executionId names a reserved control stream rather than a real execution.
|
|
102
|
+
*
|
|
103
|
+
* The blank id `""` is reserved too (ADR 0107). It names no execution, and it is where the
|
|
104
|
+
* pre-ADR-0106 compaction bug wrote the events of every resume that followed a compaction.
|
|
105
|
+
* Reserving it keeps enumerators from treating that stream as an execution to recover, retain
|
|
106
|
+
* or report, and keeps every runtime entry point from writing to it again.
|
|
107
|
+
*/
|
|
108
|
+
export declare function isReservedStream(executionId: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* The reserved control stream a chain's durable inbox lives in (ADR 0110 D1):
|
|
111
|
+
* `__loom_inbox__:<chainId>`. Defined here, beside {@link isReservedStream}, so a store decorator
|
|
112
|
+
* (the crypto plugin's `EncryptingEventStore`) and the compliance erasure can recognise it without
|
|
113
|
+
* depending on the workflow runtime.
|
|
114
|
+
*/
|
|
115
|
+
export declare const INBOX_STREAM_PREFIX = "__loom_inbox__:";
|
|
116
|
+
/**
|
|
117
|
+
* (SPI 2.5.0, ADR 0130 residuals D9; written by `quarantineInbox`): the control stream holding the
|
|
118
|
+
* verbatim copies of a chain's QUARANTINED inbox messages, `__loom_quarantine__:<chainId>`. It
|
|
119
|
+
* belongs to the same chain as the inbox, so {@link inboxChainOf} maps it to the chain (the crypto
|
|
120
|
+
* subject mapping, purge and delete-with-chain then cover it) and {@link InboxStreams.quarantine}
|
|
121
|
+
* names it. Reserved by prefix like every `__loom_` stream.
|
|
122
|
+
*/
|
|
123
|
+
export declare const QUARANTINE_STREAM_PREFIX = "__loom_quarantine__:";
|
|
124
|
+
/** The reserved stream holding `chainId`'s quarantined messages (see {@link QUARANTINE_STREAM_PREFIX}). */
|
|
125
|
+
export declare function quarantineStreamId(chainId: string): string;
|
|
126
|
+
/**
|
|
127
|
+
* The seal marker an envelope may carry at `metadata.seal` (EVENT_SCHEMA 1.25.0, ADR 0130
|
|
128
|
+
* residuals D7; RESERVED - no writer yet, the fold ignores it). Written by a sealing store
|
|
129
|
+
* decorator in the SAME append that seals fields, on exactly the envelopes in which at least one
|
|
130
|
+
* field was sealed.
|
|
131
|
+
*/
|
|
132
|
+
export interface SealMarker {
|
|
133
|
+
readonly v: 1;
|
|
134
|
+
/** The algorithm id the sealed envelopes carry, e.g. `loom/aes-256-gcm`. */
|
|
135
|
+
readonly cipher: string;
|
|
136
|
+
/** Sorted, deduped `EVENT_TYPE.dot.path` entries actually sealed in THIS envelope. */
|
|
137
|
+
readonly covers: readonly string[];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The read-only, at-rest view of an {@link EventStore} (SPI 2.5.0, see {@link EventStore.readAtRest}):
|
|
141
|
+
* envelopes exactly as stored, never decrypted; no write, fence or subscribe.
|
|
142
|
+
*/
|
|
143
|
+
export type AtRestEventReader = Pick<EventStore, "read" | "readFrom" | "readRange" | "head">;
|
|
144
|
+
/** What a store seals and therefore opens (EventStore SPI 2.5.0, see {@link EventStore.sealingCapability}). */
|
|
145
|
+
export interface SealingCapability {
|
|
146
|
+
readonly cipher: string;
|
|
147
|
+
/** Every `EVENT_TYPE.path` this node's store seals AND therefore opens. */
|
|
148
|
+
readonly covers: readonly string[];
|
|
149
|
+
/** True iff this node can open an envelope stamped with `marker` (same cipher, every entry of `marker.covers` is opened here). */
|
|
150
|
+
opens(marker: SealMarker): boolean;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The chain an execution belongs to, read from its sequence 0 alone (the fold's own rule: a valid `forkChain` stamp wins,
|
|
154
|
+
* else the start payload's `chainId`, else the execution itself) — so `send` needs no fold.
|
|
155
|
+
*/
|
|
156
|
+
export declare function chainIdOfFirst(first: EventEnvelope, executionId: string): string;
|
|
157
|
+
/**
|
|
158
|
+
* ADR 0110 amendment, D10b — per-topic inbox streams. A chain's inbox may hold one stream per topic,
|
|
159
|
+
* beside the legacy single stream:
|
|
160
|
+
*
|
|
161
|
+
* - `__loom_inbox__:<chainId>#<16 hex>` — the messages of ONE topic (the first 16 hex digits of the
|
|
162
|
+
* SHA-256 of the topic name);
|
|
163
|
+
* - `__loom_inbox__:<chainId>#reg` — the chain's REGISTRY: one `INBOX_TOPIC` event per topic that
|
|
164
|
+
* ever had a stream, so every stream of a chain is enumerable without `listExecutionsPage`.
|
|
165
|
+
*
|
|
166
|
+
* The cursors stay ONE number space (the fold is unchanged): a topic stream's sequences start at
|
|
167
|
+
* {@link INBOX_TOPIC_SEQ_BASE}, far above any legacy-stream sequence, so a legacy message of a topic
|
|
168
|
+
* (below the base) always precedes its topic-stream messages and the two can never collide.
|
|
169
|
+
*/
|
|
170
|
+
export declare const INBOX_TOPIC_SEQ_BASE: number;
|
|
171
|
+
/** The suffix of a chain's registry stream (see {@link INBOX_TOPIC_SEQ_BASE}). */
|
|
172
|
+
export declare const INBOX_REGISTRY_SUFFIX = "#reg";
|
|
173
|
+
/**
|
|
174
|
+
* The control stream whose existence is the FLEET-WIDE opt-in to per-topic writing (ADR 0110 D10b):
|
|
175
|
+
* one `INBOX_LAYOUT` event, written once by `runtime.enableInboxTopicStreams`. Reserved by prefix.
|
|
176
|
+
*/
|
|
177
|
+
export declare const INBOX_LAYOUT_STREAM = "__loom_inbox_layout__";
|
|
178
|
+
/**
|
|
179
|
+
* ADR 0139 D4: the prefix of an ARCHIVE key (never a live stream) that holds envelopes of a reserved
|
|
180
|
+
* stream which could not extend the stream's main archive run: a straggler appended at or below the
|
|
181
|
+
* archive's last sequence, for example by a send that raced the owner's terminal delete. The key is
|
|
182
|
+
* `__loom_late__:<stream>@<n>`. It begins with {@link RESERVED_STREAM_PREFIX}, which `start` refuses for
|
|
183
|
+
* every execution id, so no live chain or execution can ever have that shape, and {@link inboxChainOf}
|
|
184
|
+
* (live ids only) is untouched: an archive-key context asks {@link archiveChainOf} instead.
|
|
185
|
+
*/
|
|
186
|
+
export declare const RESERVED_LATE_PREFIX = "__loom_late__:";
|
|
187
|
+
/** The archive key of the `n`th (1-based) late run of a reserved stream (see {@link RESERVED_LATE_PREFIX}). */
|
|
188
|
+
export declare function reservedLateKey(streamId: string, n: number): string;
|
|
189
|
+
/** The reserved stream (and run number) an archive key of {@link reservedLateKey} shape belongs to. */
|
|
190
|
+
export declare function reservedLateOrigin(key: string): {
|
|
191
|
+
streamId: string;
|
|
192
|
+
n: number;
|
|
193
|
+
} | undefined;
|
|
194
|
+
/** The 16-hex-digit stream suffix of `topic` (first 8 bytes of its SHA-256). */
|
|
195
|
+
export declare function inboxTopicHash(topic: string): string;
|
|
196
|
+
/** The reserved stream holding `topic`'s messages for `chainId` (see {@link INBOX_TOPIC_SEQ_BASE}). */
|
|
197
|
+
export declare function inboxTopicStreamId(chainId: string, topic: string): string;
|
|
198
|
+
/** The chain's registry stream (see {@link INBOX_TOPIC_SEQ_BASE}). */
|
|
199
|
+
export declare function inboxRegistryStreamId(chainId: string): string;
|
|
200
|
+
/**
|
|
201
|
+
* Would an id, taken as a CHAIN id, alias a topic or registry stream of another chain
|
|
202
|
+
* (`<x>#<16 hex>` or `<x>#reg`)? Such an id is refused at `start` once the inbox is on.
|
|
203
|
+
*/
|
|
204
|
+
export declare function hasInboxStreamShape(id: string): boolean;
|
|
205
|
+
/**
|
|
206
|
+
* The chain id an inbox stream belongs to, or `undefined` when `executionId` is not an inbox
|
|
207
|
+
* stream (or names an empty chain). A chain's id is its generation-0 execution id (or a fork's
|
|
208
|
+
* fresh one), so a decorator that maps executions to erasure subjects can map the chain's streams
|
|
209
|
+
* (legacy, per-topic and registry alike) to the same subject as its owner.
|
|
210
|
+
*/
|
|
211
|
+
export declare function inboxChainOf(executionId: string): string | undefined;
|
|
212
|
+
/**
|
|
213
|
+
* {@link inboxChainOf} for an ARCHIVE key: the same chain for a reserved stream's own key, and, for a
|
|
214
|
+
* late-run key ({@link reservedLateKey}), the chain of the stream it was split from. Archive-key
|
|
215
|
+
* contexts only (the sealing subject of `EncryptingArchiveStore`, the archive listings); a live stream
|
|
216
|
+
* id is never a late key, so live code keeps calling {@link inboxChainOf}.
|
|
217
|
+
*/
|
|
218
|
+
export declare function archiveChainOf(key: string): string | undefined;
|
|
219
|
+
/** The inbox streams of one chain, from {@link inboxStreamsOfChain}. */
|
|
220
|
+
export interface InboxStreams {
|
|
221
|
+
/** The legacy single stream (always named, whether or not it holds anything). */
|
|
222
|
+
legacy: string;
|
|
223
|
+
/** The registry stream, only when it has entries (a chain never written per-topic has none). */
|
|
224
|
+
registry: string | undefined;
|
|
225
|
+
/** One stream per registered topic. */
|
|
226
|
+
topics: string[];
|
|
227
|
+
/** The chain's quarantine stream (ADR 0130 residuals D9, reserved: always named, whether or not it holds anything). */
|
|
228
|
+
quarantine: string;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Every inbox stream a chain has on `store`: the legacy stream, the registry (when it exists) and one
|
|
232
|
+
* stream per registered topic. The registry is bounded by the per-chain topic cap, so this is one small
|
|
233
|
+
* read. Used by every site that must reach ALL of a chain's streams (retirement, erasure, lifecycle
|
|
234
|
+
* deletion) without a second copy of the naming rule. Delete `topics`, then `legacy`, then `registry`
|
|
235
|
+
* LAST: a crash midway then leaves the remaining topic streams still findable.
|
|
236
|
+
*/
|
|
237
|
+
export declare function inboxStreamsOfChain(store: Pick<EventStore, "read">, chainId: string): Promise<InboxStreams>;
|
|
238
|
+
/**
|
|
239
|
+
* {@link inboxStreamsOfChain} PLUS a prefix scan: the topic streams the registry does not name (a
|
|
240
|
+
* sender that crashed between its append and its registration, a registry deleted underneath a
|
|
241
|
+
* sender, a stale "already registered" cache). Reaches them through the store's keyset-paged
|
|
242
|
+
* enumeration when it has one (`listExecutionsPage`, ids in code point order, so the chain's streams are
|
|
243
|
+
* one contiguous run after its prefix); a store without it gets the registry's answer alone. It is a
|
|
244
|
+
* BACKSTOP for erasure and the orphan sweep, not the hot path (the scan is one indexed range query).
|
|
245
|
+
*/
|
|
246
|
+
export declare function inboxStreamsOfChainDeep(store: Pick<EventStore, "read"> & Partial<Pick<EventStore, "listExecutionsPage">>, chainId: string): Promise<InboxStreams>;
|
|
247
|
+
/**
|
|
248
|
+
* Durable, append-only event log. Async-first so any backend plugs in —
|
|
249
|
+
* synchronous stores (SQLite, in-memory) satisfy this trivially by marking
|
|
250
|
+
* methods `async`; async/network stores (Postgres, Redis, DynamoDB) return
|
|
251
|
+
* real Promises.
|
|
252
|
+
*
|
|
253
|
+
* Note there is no `nextSequence` — sequence allocation is owned by the
|
|
254
|
+
* per-execution in-memory sequencer in `@loomwork/workflow-runtime` (ExecutionJournal),
|
|
255
|
+
* so a backend never needs a read-then-write round-trip to append.
|
|
256
|
+
*/
|
|
257
|
+
export interface EventStore {
|
|
258
|
+
/**
|
|
259
|
+
* Erasure: a store that can crypto-shred (or otherwise erase) payloads MUST signal it with an error
|
|
260
|
+
* recognised by `isPayloadShredded` (the real `PayloadShreddedError`, or its own error passed through
|
|
261
|
+
* `brandPayloadShredded`); any other failure, even one named `PayloadShreddedError`, is a fault the
|
|
262
|
+
* kernel treats as retryable and never as proof of erasure.
|
|
263
|
+
*
|
|
264
|
+
* Append one envelope.
|
|
265
|
+
*
|
|
266
|
+
* A log has TWO uniqueness constraints, and a backend MUST enforce both — rejecting,
|
|
267
|
+
* never overwriting and never silently treating the second write as a re-delivery:
|
|
268
|
+
*
|
|
269
|
+
* - **`(executionId, sequence)`**, rejected with {@link DuplicateSequenceError}. Not
|
|
270
|
+
* covered by fencing: fencing engages only once a token has been ACQUIRED for the
|
|
271
|
+
* execution, while sequences are allocated per-process from folded state (see the note
|
|
272
|
+
* above), so two unfenced writers recovering the same execution allocate the same next
|
|
273
|
+
* sequence with neither one a zombie. A backend that accepts both silently interleaves
|
|
274
|
+
* them into a log that every fold reads as truth.
|
|
275
|
+
* - **`id`**, rejected with {@link DuplicateEnvelopeIdError}. Required WITHIN an
|
|
276
|
+
* execution. Store-wide uniqueness is what `PRIMARY KEY (id)` gives a single-log
|
|
277
|
+
* backend, and those are free to be stricter, but it is explicitly **not required** —
|
|
278
|
+
* {@link ShardedEventStore} cannot provide it (separate executions live on separate
|
|
279
|
+
* backing stores, and no shard sees another's ids), the same carve-out `appendBatch`
|
|
280
|
+
* makes for cross-execution atomicity. A backend that indexes ids separately must free
|
|
281
|
+
* them when the events they name are deleted or compacted away, or an erased execution
|
|
282
|
+
* can never be re-created.
|
|
283
|
+
*
|
|
284
|
+
* The two are different failures and must not be reported as each other: a taken
|
|
285
|
+
* sequence means another writer reached that slot (a lost race, retryable by re-reading
|
|
286
|
+
* and re-allocating), while a taken id means the same envelope identity was minted twice
|
|
287
|
+
* (a bug in whatever produced it). The SQL backends get both from table constraints; a
|
|
288
|
+
* backend without them checks explicitly.
|
|
289
|
+
*/
|
|
290
|
+
append(envelope: EventEnvelope): Promise<void>;
|
|
291
|
+
/**
|
|
292
|
+
* OPTIONAL bulk append (ADR 0074 D1, SPI 1.3.0). Semantically **equivalent to calling
|
|
293
|
+
* `append` once per envelope, in array order**, but in one round-trip — which is the
|
|
294
|
+
* entire point, and the only part a caller cannot synthesize above the store boundary.
|
|
295
|
+
*
|
|
296
|
+
* Contract a backend MUST honour:
|
|
297
|
+
* - **Atomic PER EXECUTION.** All envelopes for a given executionId land, or none of
|
|
298
|
+
* them do. That is the property a fold depends on: a partial write within one log
|
|
299
|
+
* could leave a hole (sequence 6 durable, 5 missing), which no fold expects. A prefix
|
|
300
|
+
* is fine — the run simply stops there.
|
|
301
|
+
*
|
|
302
|
+
* Whole-batch atomicity across DIFFERENT executions is explicitly **not** required.
|
|
303
|
+
* {@link ShardedEventStore} cannot provide it — separate executions live on separate
|
|
304
|
+
* logs — and nothing needs it: a batch only ever groups INDEPENDENT executions, so
|
|
305
|
+
* nothing in it depends on anything else in it. A backend backed by a single
|
|
306
|
+
* transactional store will get whole-batch atomicity for free; do not rely on it.
|
|
307
|
+
* - **Fencing per envelope, not per batch.** Envelopes may belong to DIFFERENT
|
|
308
|
+
* executions (that is exactly what {@link CoalescingEventStore} produces), so each is
|
|
309
|
+
* checked against its own execution's fence. Rejecting when any envelope is fenced out
|
|
310
|
+
* is correct; silently dropping just the fenced rows is not.
|
|
311
|
+
* - **Reject, don't half-report.** If any envelope fails, the returned promise rejects —
|
|
312
|
+
* so a caller never reads a partial write as success. `CoalescingEventStore` propagates
|
|
313
|
+
* that rejection to every writer in the batch.
|
|
314
|
+
* - **Uniqueness within the batch, too.** Two envelopes claiming the same
|
|
315
|
+
* `(executionId, sequence)` — or the same `id` — are each appendable against the
|
|
316
|
+
* durable log and conflict only with each other, so a backend that validates solely
|
|
317
|
+
* against stored rows admits the pair. Checking the batch against itself is part of
|
|
318
|
+
* the contract.
|
|
319
|
+
* - **Empty input is a no-op**, not an error.
|
|
320
|
+
*
|
|
321
|
+
* A store that omits it is byte-identical to today — callers use {@link appendBatchOf},
|
|
322
|
+
* which falls back to a sequential `append` loop. Implementing it is how a
|
|
323
|
+
* bring-your-own backend opts into the batching win; `runEventStoreConformance` covers
|
|
324
|
+
* the contract above so that implementation is verifiable.
|
|
325
|
+
*/
|
|
326
|
+
appendBatch?(envelopes: readonly EventEnvelope[]): Promise<void>;
|
|
327
|
+
read(executionId: string): Promise<EventEnvelope[]>;
|
|
328
|
+
readFrom(executionId: string, fromSequence: number): Promise<EventEnvelope[]>;
|
|
329
|
+
/**
|
|
330
|
+
* OPTIONAL bounded read of `[fromSequence..toSequence]` (both inclusive) for one
|
|
331
|
+
* execution, ordered by sequence. Backends push the bound into the query (indexed
|
|
332
|
+
* range) instead of loading the whole log and filtering in JS. A store that omits
|
|
333
|
+
* it falls back to `readFrom` + filter, so callers must tolerate its absence — use
|
|
334
|
+
* {@link readRangeOf}. Empty when `toSequence < fromSequence`.
|
|
335
|
+
*/
|
|
336
|
+
readRange?(executionId: string, fromSequence: number, toSequence: number): Promise<EventEnvelope[]>;
|
|
337
|
+
/**
|
|
338
|
+
* OPTIONAL tip query: the highest sequence durably stored for an execution, or `null`
|
|
339
|
+
* when it has none. One indexed `MAX(sequence)` instead of materializing a log just to
|
|
340
|
+
* ask how long it is.
|
|
341
|
+
*
|
|
342
|
+
* `fork()` is the motivating caller — it needs the tip to validate a fork point, and was
|
|
343
|
+
* reading the ENTIRE parent log to get it even when the store could copy the prefix
|
|
344
|
+
* natively. A store that omits this falls back to reading the log, so callers must
|
|
345
|
+
* tolerate its absence — use {@link headOf}.
|
|
346
|
+
*/
|
|
347
|
+
head?(executionId: string): Promise<number | null>;
|
|
348
|
+
/**
|
|
349
|
+
* Live delivery of one execution's appends. Events committed by OTHER nodes arrive in commit
|
|
350
|
+
* order relative to each other (the Postgres store queues each execution's cross-node emits
|
|
351
|
+
* behind its predecessor's rather than emitting on lookup-completion order). A LOCAL append is
|
|
352
|
+
* emitted synchronously and may overtake a cross-node event still in flight, so a subscriber that
|
|
353
|
+
* needs total order should order by `sequence` (or read the log).
|
|
354
|
+
*
|
|
355
|
+
* Cross-node delivery can lose a wake-up, and a lost one is not sent later: a dropped listener or
|
|
356
|
+
* a full Postgres NOTIFY queue costs it. The log stays complete. A subscriber that must see a
|
|
357
|
+
* final event needs its own bounded re-read of the log.
|
|
358
|
+
*/
|
|
359
|
+
subscribe(executionId: string, handler: (event: EventEnvelope) => void): Promise<() => void>;
|
|
360
|
+
/**
|
|
361
|
+
* OPTIONAL fencing (K9.4). Atomically increment and return the execution's
|
|
362
|
+
* monotonic fencing token (first call → 1). A dispatcher/worker acquires a
|
|
363
|
+
* fence per dispatch; every envelope the run appends carries it in
|
|
364
|
+
* `metadata.fence`. Once an execution has a fence, a store that implements
|
|
365
|
+
* fencing MUST reject appends whose token is missing or lower than the
|
|
366
|
+
* current one (throw {@link StaleFenceError}) — a re-dispatched execution's
|
|
367
|
+
* zombie predecessor can no longer write. Executions that never acquire a
|
|
368
|
+
* fence are entirely unaffected (zero overhead, G2); a store that omits this
|
|
369
|
+
* method performs no fencing (e.g. single-node SQLite, where the process is
|
|
370
|
+
* the failure domain).
|
|
371
|
+
*/
|
|
372
|
+
acquireFence?(executionId: string): Promise<number>;
|
|
373
|
+
/**
|
|
374
|
+
* OPTIONAL conditional fence (ADR 0118 D1, SPI 2.1.0) — "acquire, but only if the park I am
|
|
375
|
+
* answering is still unanswered", as ONE atomic operation. Bumps and returns the next token iff
|
|
376
|
+
*
|
|
377
|
+
* (a) the execution's CURRENT token equals `expect.fence` (0 when it was never acquired), AND
|
|
378
|
+
* (b) no ANSWERING event ({@link isAnsweringKind}) exists with `sequence > expect.parkSeq`;
|
|
379
|
+
*
|
|
380
|
+
* otherwise returns `{ stale: true, fence: <current> }` and changes nothing. (b) is what makes a
|
|
381
|
+
* retry on a re-read token safe: a resume's append does not move the token, so only the log can
|
|
382
|
+
* say "a resume for this park is already recorded" (a dead acquirer, by contrast, moves the
|
|
383
|
+
* token and appends nothing). Audit appends after a park (`EXECUTION_DENIED`, `OUTCOME_RECORDED`,
|
|
384
|
+
* application events, ...) do not answer it.
|
|
385
|
+
*
|
|
386
|
+
* Atomic against appends: an answering append that lands implies the acquire is `stale`; an
|
|
387
|
+
* acquire that wins implies that append is a `StaleFenceError`, never both succeeding. A store
|
|
388
|
+
* that fences implements it (memory: one synchronous step; Postgres: a transaction that locks
|
|
389
|
+
* the fence row, with the answering appends taking it `FOR SHARE`); a store that does not fence
|
|
390
|
+
* (single-node SQLite) omits it, and a caller falls back to `acquireFence` and the documented
|
|
391
|
+
* residual.
|
|
392
|
+
*/
|
|
393
|
+
acquireFenceIf?(executionId: string, expect: {
|
|
394
|
+
fence: number;
|
|
395
|
+
parkSeq: number;
|
|
396
|
+
}): Promise<AcquireFenceIfResult>;
|
|
397
|
+
/**
|
|
398
|
+
* OPTIONAL conditional append (SPI 2.2.0, ADR 0116 amendment) — "append this ONE event iff the
|
|
399
|
+
* execution is exactly as I observed it", atomically. With a non-null `event`
|
|
400
|
+
* (`event.executionId === executionId`), appends it iff ALL hold at the instant of the write:
|
|
401
|
+
*
|
|
402
|
+
* (a) the execution EXISTS — its sequence-0 event is still stored (a retention sweep that
|
|
403
|
+
* deleted the log between the caller's read and now makes this `gone`, and NOTHING is
|
|
404
|
+
* written: no orphan log, whatever fence row a store keeps);
|
|
405
|
+
* (b) the stored head (`MAX(sequence)`) equals `expect.head`;
|
|
406
|
+
* (c) the fence token equals `expect.fence` (0 when it was never acquired).
|
|
407
|
+
*
|
|
408
|
+
* It does NOT check or present the envelope's own `metadata.fence` and never bumps or adopts a
|
|
409
|
+
* token: the caller observed the token and the store proves it has not moved, so a holder that
|
|
410
|
+
* acquires after the observation makes this `moved` (retryable) instead of being displaced, and
|
|
411
|
+
* a holder whose appends landed makes (b) fail. `event.sequence` must exceed `expect.head`
|
|
412
|
+
* (the caller may skip ahead of a compaction checkpoint; the slot must still be free).
|
|
413
|
+
* A duplicate sequence / envelope id / injected failure throws exactly as `append` does.
|
|
414
|
+
*
|
|
415
|
+
* With `event === null` it is a pure OBSERVATION: nothing is written and the result is
|
|
416
|
+
* `{ appended: false, reason: "observed" | "gone", head, fence, anchor }` (`expect` is ignored).
|
|
417
|
+
*
|
|
418
|
+
* Implementations hold the same lock/row the fence uses (ADR 0118): memory one synchronous
|
|
419
|
+
* step; Postgres a transaction that takes the execution's fence row `FOR UPDATE`; SQLite
|
|
420
|
+
* `BEGIN IMMEDIATE` (no fencing: the token is always 0). A decorator transforms the event
|
|
421
|
+
* exactly as it does for `append` (tenant scope, encryption, externalisation, chain stamp).
|
|
422
|
+
*/
|
|
423
|
+
appendIfUnchanged?(executionId: string, event: EventEnvelope | null, expect?: TipObservation): Promise<AppendIfUnchangedResult>;
|
|
424
|
+
/**
|
|
425
|
+
* OPTIONAL (SPI 2.4.0, ADR 0110 amendment D10a): the store's own clock in epoch milliseconds - the
|
|
426
|
+
* single clock every node of a fleet shares (Postgres: database time). A caller that must compare
|
|
427
|
+
* an instant stamped by one node with "now" on another (an inbox message's TTL) uses this on both
|
|
428
|
+
* sides instead of trusting the nodes' wall clocks. A store that is a single process (memory,
|
|
429
|
+
* SQLite) omits it and callers fall back to their injected clock.
|
|
430
|
+
*/
|
|
431
|
+
storeNow?(): Promise<number>;
|
|
432
|
+
/**
|
|
433
|
+
* OPTIONAL (SPI 2.5.0, ADR 0130 residuals D7; RESERVED - declared and forwarded, no caller yet):
|
|
434
|
+
* what this store seals AND therefore opens. Absent, or returning `undefined`: it seals nothing
|
|
435
|
+
* and opens nothing. Must be stable for an unchanged configuration (`cipher`, sorted deduped
|
|
436
|
+
* `covers`), and `opens(marker)` true iff the cipher is equal and every `marker.covers` entry is
|
|
437
|
+
* in `covers`. A decorator that does not seal forwards it; `ShardedEventStore` returns the
|
|
438
|
+
* intersection across shards (undefined unless every shard agrees on the cipher).
|
|
439
|
+
*/
|
|
440
|
+
sealingCapability?(): SealingCapability | undefined;
|
|
441
|
+
/**
|
|
442
|
+
* OPTIONAL (SPI 2.5.0, ADR 0130 D9): a READ-ONLY view of the envelopes exactly AS STORED - a
|
|
443
|
+
* sealing decorator never decrypts what this view returns (a store that seals nothing may return
|
|
444
|
+
* its ordinary reads; it need not implement the method). It exists so a caller that has decided a
|
|
445
|
+
* sealed value is not its business (the quarantine verbs stepping over a `MESSAGE_CONSUMED.payload`
|
|
446
|
+
* seal) reads WITHOUT asking the KeyStore. No write, no fence, no subscribe. Every envelope it
|
|
447
|
+
* returns is byte-identical to what was appended through the store. A decorator forwards it (the
|
|
448
|
+
* sealing one overrides it with its inner store's raw reads); `ShardedEventStore` routes each
|
|
449
|
+
* call to the stream's shard, like `read`. "As stored" includes UNRESOLVED content refs (a
|
|
450
|
+
* `ContentResolvingEventStore` above it never resolves them), so an admitted transient fold sees
|
|
451
|
+
* `ContentRef`s and erased content does not raise `ContentMissingError` on this path; harmless for
|
|
452
|
+
* routing fields unless an app externalizes one.
|
|
453
|
+
*/
|
|
454
|
+
readAtRest?(): AtRestEventReader;
|
|
455
|
+
/**
|
|
456
|
+
* OPTIONAL bulk copy of the prefix `[0..throughSequence]` of one execution's log
|
|
457
|
+
* into another `executionId`, re-stamping `id` + `executionId` and merging
|
|
458
|
+
* `metadata` into each copied event — WITHOUT round-tripping payloads through JS
|
|
459
|
+
* (de)serialization. Used by `fork()`; a store that omits it falls back to a
|
|
460
|
+
* per-event `append` loop, so this is purely a performance fast-path.
|
|
461
|
+
*/
|
|
462
|
+
copyPrefix?(fromExecutionId: string, toExecutionId: string, throughSequence: number, metadata: Record<string, unknown>): Promise<void>;
|
|
463
|
+
/**
|
|
464
|
+
* OPTIONAL (K10.1 retention). Delete ALL events for an execution. Used by the
|
|
465
|
+
* retention sweep after a terminal execution's retention window elapses
|
|
466
|
+
* (archive-before-delete is the sweep's responsibility, not the store's). A
|
|
467
|
+
* store that omits it cannot be swept — retention is opt-in per backend.
|
|
468
|
+
*/
|
|
469
|
+
deleteExecution?(executionId: string): Promise<void>;
|
|
470
|
+
/**
|
|
471
|
+
* OPTIONAL (SPI 2.6.0, ADR 0139 D8). Delete every event of an execution with `sequence <= through`,
|
|
472
|
+
* INCLUDING sequence 0 (unlike {@link truncatePrefix}, which preserves it), in ONE atomic operation
|
|
473
|
+
* (SQL: a single `DELETE ... WHERE sequence <= $through`; never a read followed by a delete). Events
|
|
474
|
+
* above `through` are untouched: a message appended AFTER the caller read the stream (the reason this
|
|
475
|
+
* exists) survives as the live remainder of the stream, instead of being swept away by a whole-stream
|
|
476
|
+
* {@link deleteExecution} that archived only what it had read. When nothing remains the execution is
|
|
477
|
+
* gone exactly as after `deleteExecution` (fence bookkeeping included). A store that omits it cannot
|
|
478
|
+
* be deleted safely by a caller that must not lose a concurrent append; such a caller REFUSES rather
|
|
479
|
+
* than falling back to `deleteExecution`.
|
|
480
|
+
*/
|
|
481
|
+
deleteThrough?(executionId: string, through: number): Promise<void>;
|
|
482
|
+
/**
|
|
483
|
+
* OPTIONAL (K10.4 compaction). Delete the prefix `(0..throughSequence]` of an
|
|
484
|
+
* execution's log — **sequence 0 (the EXECUTION_STARTED bootstrap) is always
|
|
485
|
+
* preserved** as the execution's metadata anchor (resume reads input/workflowId
|
|
486
|
+
* from it). The caller MUST ensure a snapshot at a sequence
|
|
487
|
+
* `>= throughSequence` exists first, so the invariant
|
|
488
|
+
* `fold(snapshot, suffix) === fold(events)` holds — the store only truncates.
|
|
489
|
+
*/
|
|
490
|
+
truncatePrefix?(executionId: string, throughSequence: number): Promise<void>;
|
|
491
|
+
/**
|
|
492
|
+
* OPTIONAL (SPI 1.5.0, ADR 0106). {@link truncatePrefix}, except that events whose
|
|
493
|
+
* `eventType` is in `keepEventTypes` survive in place: delete the prefix
|
|
494
|
+
* `(0..throughSequence]` of an execution's log, keeping sequence 0 AND every event of a kept
|
|
495
|
+
* type. ONE atomic operation (SQL: a single `DELETE … AND event_type <> ALL($3)`), never a
|
|
496
|
+
* read followed by per-row deletes, so a crash cannot leave a half-truncated prefix. With an
|
|
497
|
+
* empty `keepEventTypes` it is exactly `truncatePrefix`. The kept events sit BELOW the
|
|
498
|
+
* compaction checkpoint, where no reader folds them (every fold reads from
|
|
499
|
+
* `snapshot.sequence + 1`); what reads them is policy that scans the log for its pinned kinds
|
|
500
|
+
* (`pinByEventKinds`, the content sweep). Same precondition as `truncatePrefix`. A store that
|
|
501
|
+
* omits it cannot be compacted past a log's first pinned event, ever.
|
|
502
|
+
*/
|
|
503
|
+
truncatePrefixKeeping?(executionId: string, throughSequence: number, keepEventTypes: readonly string[]): Promise<void>;
|
|
504
|
+
/**
|
|
505
|
+
* OPTIONAL enumeration of every distinct executionId in the store (unordered). Powers
|
|
506
|
+
* operator sweeps that must visit all executions — `loom retention run`,
|
|
507
|
+
* `loom compliance report`. Includes reserved control streams (`__loom_*`); callers that
|
|
508
|
+
* want only real executions filter with {@link isReservedStream}. A store that omits this
|
|
509
|
+
* cannot be swept over cold storage (there is no cheap fallback — enumeration requires a
|
|
510
|
+
* scan the store alone can do efficiently, e.g. `SELECT DISTINCT execution_id`).
|
|
511
|
+
*/
|
|
512
|
+
listExecutions?(): Promise<string[]>;
|
|
513
|
+
/**
|
|
514
|
+
* OPTIONAL keyset-paged enumeration (SP-1, SPI 1.2.0): distinct executionIds in Unicode
|
|
515
|
+
* CODE POINT order (SPI 2.0.0, ADR 0108 — {@link compareExecutionIds}; SQL `COLLATE "C"`, never the
|
|
516
|
+
* database's collation), `limit` per page. `cursor` is an executionId — any string, not
|
|
517
|
+
* only one this store returned — and the page holds the ids strictly after it; `nextCursor`
|
|
518
|
+
* is the page's last id. `ShardedEventStore` depends on all three: it merges shard pages in
|
|
519
|
+
* this order and resumes EVERY shard from the merged page's last id. The guarantee covers
|
|
520
|
+
* well-formed Unicode ids; a lone surrogate cannot round-trip through UTF-8 (node-postgres
|
|
521
|
+
* sends U+FFFD), so no ordering or identity is promised for one. Bounded-memory alternative to {@link listExecutions} for maintenance passes
|
|
522
|
+
* (retention, the K10.6 sweep, read-model catch-up) over year-scale stores. Executions
|
|
523
|
+
* created DURING iteration whose ids sort before the cursor may be missed — acceptable
|
|
524
|
+
* for periodic maintenance jobs (they are visited on the next pass); do not use this for
|
|
525
|
+
* exactly-once semantics. Same reserved-stream note as `listExecutions`.
|
|
526
|
+
*/
|
|
527
|
+
listExecutionsPage?(opts?: {
|
|
528
|
+
cursor?: string;
|
|
529
|
+
limit?: number;
|
|
530
|
+
}): Promise<ExecutionPage>;
|
|
531
|
+
close(): Promise<void>;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* What a caller saw of an execution's tip: the stored head, the fence token (0 = never fenced) and
|
|
535
|
+
* the `anchor` — an OPAQUE incarnation marker. Since SPI 2.3.0 (ADR 0129) it is a STORE-ASSIGNED,
|
|
536
|
+
* monotonic incarnation that differs between two incarnations of an id even when their sequence-0
|
|
537
|
+
* envelopes are byte-identical (before it: a marker derived from that envelope's id and
|
|
538
|
+
* timestamp, which a pre-migration log keeps). The anchor is what tells "the log I observed" from
|
|
539
|
+
* "a log deleted and re-created under the same id that happens to have the same head and token"
|
|
540
|
+
* (the ABA case): envelope ids are deterministic (`<exec>-<seq>`), so the head and token alone
|
|
541
|
+
* cannot.
|
|
542
|
+
* Pass back exactly what an observation returned; a decorator forwards it untouched.
|
|
543
|
+
*/
|
|
544
|
+
export interface TipObservation {
|
|
545
|
+
head: number;
|
|
546
|
+
fence: number;
|
|
547
|
+
anchor: string;
|
|
548
|
+
}
|
|
549
|
+
/** What {@link EventStore.appendIfUnchanged} answers. */
|
|
550
|
+
export type AppendIfUnchangedResult = {
|
|
551
|
+
appended: true;
|
|
552
|
+
} | {
|
|
553
|
+
appended: false;
|
|
554
|
+
/** `moved`: the head or the fence changed; `gone`: no sequence-0 event; `observed`: a pure observation. */
|
|
555
|
+
reason: "moved" | "gone" | "observed";
|
|
556
|
+
/** The tip now (`null` when the execution is gone). */
|
|
557
|
+
head: number | null;
|
|
558
|
+
fence: number;
|
|
559
|
+
/** The creation marker now (`null` when the execution is gone). */
|
|
560
|
+
anchor: string | null;
|
|
561
|
+
};
|
|
562
|
+
/** What {@link EventStore.acquireFenceIf} answers: the new token, or the (unchanged) current one. */
|
|
563
|
+
export type AcquireFenceIfResult = {
|
|
564
|
+
fence: number;
|
|
565
|
+
} | {
|
|
566
|
+
stale: true;
|
|
567
|
+
fence: number;
|
|
568
|
+
};
|
|
569
|
+
/**
|
|
570
|
+
* The names of the OPTIONAL {@link EventStore} methods, derived from the interface itself —
|
|
571
|
+
* a key whose `Pick` admits `{}` is optional. A decorator that forgets one silently takes that
|
|
572
|
+
* capability away from everything above it (ADR 0074 Amendment), so decorators declare a
|
|
573
|
+
* `DecoratorPlan` over this whole union.
|
|
574
|
+
*/
|
|
575
|
+
export type OptionalEventStoreMethod = {
|
|
576
|
+
[K in keyof EventStore]-?: {} extends Pick<EventStore, K> ? K : never;
|
|
577
|
+
}[keyof EventStore];
|
|
578
|
+
/**
|
|
579
|
+
* The runtime list of {@link OptionalEventStoreMethod}, for the decorator conformance kit.
|
|
580
|
+
* The check below makes a new optional method on the interface a compile error here until it
|
|
581
|
+
* is listed — so the kit can never quietly stop checking one.
|
|
582
|
+
*/
|
|
583
|
+
export declare const OPTIONAL_EVENT_STORE_METHODS: readonly ["appendBatch", "readRange", "head", "acquireFence", "acquireFenceIf", "appendIfUnchanged", "storeNow", "sealingCapability", "readAtRest", "copyPrefix", "deleteExecution", "deleteThrough", "truncatePrefix", "truncatePrefixKeeping", "listExecutions", "listExecutionsPage"];
|
|
584
|
+
/**
|
|
585
|
+
* One page of {@link EventStore.listExecutionsPage}. `nextCursor` present iff more remain; a
|
|
586
|
+
* page that carries a `nextCursor` carries at least one id (consumers such as
|
|
587
|
+
* `ShardedEventStore`'s scatter-gather read an empty page as the end).
|
|
588
|
+
*/
|
|
589
|
+
export interface ExecutionPage {
|
|
590
|
+
executionIds: string[];
|
|
591
|
+
nextCursor?: string;
|
|
592
|
+
}
|
|
593
|
+
/** The enumeration surface of a store — what maintenance passes actually need. */
|
|
594
|
+
export interface ExecutionEnumerable {
|
|
595
|
+
listExecutions?(): Promise<string[]>;
|
|
596
|
+
listExecutionsPage?(opts?: {
|
|
597
|
+
cursor?: string;
|
|
598
|
+
limit?: number;
|
|
599
|
+
}): Promise<ExecutionPage>;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* SP-2 — the one enumeration loop every maintenance pass shares: prefers the
|
|
603
|
+
* bounded-memory paged surface, falls back to `listExecutions()`, and REFUSES a
|
|
604
|
+
* store with neither (silent partial passes are how retention deletes evidence
|
|
605
|
+
* and read models under-index).
|
|
606
|
+
*/
|
|
607
|
+
export declare function iterateExecutionIds(source: ExecutionEnumerable, pageSize?: number): AsyncGenerator<string, void, void>;
|
|
608
|
+
export interface EventStoreOptions {
|
|
609
|
+
dbPath: string;
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Append many envelopes through a store that may or may not implement the optional
|
|
613
|
+
* `appendBatch` fast-path (ADR 0074 D1). Uses the single round-trip when available, else
|
|
614
|
+
* falls back to a sequential `append` loop — so callers never branch on the capability.
|
|
615
|
+
*
|
|
616
|
+
* The fallback is deliberately **sequential**, not `Promise.all`: `append` is
|
|
617
|
+
* order-sensitive per execution, and a parallel loop would also lose the all-or-nothing
|
|
618
|
+
* property that the native path guarantees. The fallback is a correctness-preserving
|
|
619
|
+
* degradation, not a performance one — it wins nothing, and is not meant to.
|
|
620
|
+
*/
|
|
621
|
+
export declare function appendBatchOf(store: EventStore, envelopes: readonly EventEnvelope[]): Promise<void>;
|
|
622
|
+
/**
|
|
623
|
+
* Read `[fromSequence..toSequence]` from a store that may or may not implement the
|
|
624
|
+
* optional `readRange` fast-path. Uses the native indexed range when available,
|
|
625
|
+
* else falls back to `readFrom` + a bounded slice — so every caller gets the
|
|
626
|
+
* range without having to branch on the capability.
|
|
627
|
+
*/
|
|
628
|
+
/**
|
|
629
|
+
* The tip of an execution's log through the optional {@link EventStore.head} fast-path,
|
|
630
|
+
* falling back to reading it. `null` means the execution has no events at all.
|
|
631
|
+
*/
|
|
632
|
+
export declare function headOf(store: Pick<EventStore, "read" | "head">, executionId: string): Promise<number | null>;
|
|
633
|
+
export declare function readRangeOf(store: Pick<EventStore, "read" | "readFrom" | "readRange">, executionId: string, fromSequence: number, toSequence: number): Promise<EventEnvelope[]>;
|
|
634
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|