@enbox/dwn-sdk-js 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.mjs +6 -6
- package/dist/browser.mjs.map +3 -3
- package/dist/esm/generated/precompiled-validators.js +704 -342
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +1 -0
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/event-stream/event-emitter-event-log.js +151 -20
- package/dist/esm/src/event-stream/event-emitter-event-log.js.map +1 -1
- package/dist/esm/src/handlers/messages-subscribe.js +7 -0
- package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/messages-sync.js +6 -3
- package/dist/esm/src/handlers/messages-sync.js.map +1 -1
- package/dist/esm/src/handlers/protocols-configure.js +1 -1
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/records-subscribe.js +7 -0
- package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +33 -5
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -1
- package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
- package/dist/esm/src/store/storage-controller.js +1 -1
- package/dist/esm/src/store/storage-controller.js.map +1 -1
- package/dist/esm/src/utils/messages.js +41 -1
- package/dist/esm/src/utils/messages.js.map +1 -1
- package/dist/esm/tests/event-emitter-event-log.spec.js +214 -81
- package/dist/esm/tests/event-emitter-event-log.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-subscribe.spec.js +288 -0
- package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/types/generated/precompiled-validators.d.ts +50 -34
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +1 -0
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts +34 -4
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-subscribe.d.ts +1 -1
- package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-sync.d.ts.map +1 -1
- package/dist/types/src/handlers/records-subscribe.d.ts +1 -1
- package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-subscribe.d.ts +4 -3
- package/dist/types/src/interfaces/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-subscribe.d.ts +4 -3
- package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/types/messages-types.d.ts +14 -4
- package/dist/types/src/types/messages-types.d.ts.map +1 -1
- package/dist/types/src/types/records-types.d.ts +8 -4
- package/dist/types/src/types/records-types.d.ts.map +1 -1
- package/dist/types/src/types/subscriptions.d.ts +73 -20
- package/dist/types/src/types/subscriptions.d.ts.map +1 -1
- package/dist/types/src/utils/messages.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/utils/test-data-generator.d.ts +5 -4
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/dwn-error.ts +1 -0
- package/src/event-stream/event-emitter-event-log.ts +169 -21
- package/src/handlers/messages-subscribe.ts +8 -1
- package/src/handlers/messages-sync.ts +6 -3
- package/src/handlers/protocols-configure.ts +1 -1
- package/src/handlers/records-subscribe.ts +8 -1
- package/src/handlers/records-write.ts +34 -5
- package/src/index.ts +1 -1
- package/src/interfaces/messages-subscribe.ts +4 -3
- package/src/interfaces/records-subscribe.ts +4 -3
- package/src/store/storage-controller.ts +1 -1
- package/src/types/messages-types.ts +12 -4
- package/src/types/records-types.ts +6 -4
- package/src/types/subscriptions.ts +78 -20
- package/src/utils/messages.ts +47 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"records-types.d.ts","sourceRoot":"","sources":["../../../../src/types/records-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"records-types.d.ts","sourceRoot":"","sources":["../../../../src/types/records-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
import type { RecordsWriteMessage } from './records-types.js';
|
|
2
2
|
import type { Filter, KeyValues } from './query-types.js';
|
|
3
3
|
import type { GenericMessage, GenericMessageReply, MessageSubscription } from './message-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Structured cursor for EventLog replay and resume. Replaces the previous
|
|
6
|
+
* opaque `string` cursor to provide explicit ordering semantics required
|
|
7
|
+
* by causal frontier progression in multi-master sync.
|
|
8
|
+
*
|
|
9
|
+
* Comparisons are valid only when `streamId` and `epoch` are equal.
|
|
10
|
+
* `position` is compared numerically (BigInt-safe), never lexicographically.
|
|
11
|
+
* Progress tokens are source-local: they MUST NOT be reused across different
|
|
12
|
+
* remote providers or EventLog instances.
|
|
13
|
+
*/
|
|
14
|
+
export type ProgressToken = {
|
|
15
|
+
/** Stable identity of the source event stream domain. */
|
|
16
|
+
streamId: string;
|
|
17
|
+
/** Stream generation/version; changes on non-compatible reset. */
|
|
18
|
+
epoch: string;
|
|
19
|
+
/** Monotonic decimal string within `(streamId, epoch)`. Compared numerically. */
|
|
20
|
+
position: string;
|
|
21
|
+
/** The CID of the message associated with this event. */
|
|
22
|
+
messageCid: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Reason code for a {@link ProgressGapInfo} — explains why the cursor
|
|
26
|
+
* cannot be resumed.
|
|
27
|
+
*/
|
|
28
|
+
export type ProgressGapReason = 'token_too_old' | 'epoch_mismatch' | 'stream_mismatch';
|
|
29
|
+
/**
|
|
30
|
+
* Metadata attached to a `DwnError(DwnErrorCode.EventLogProgressGap, ...)`
|
|
31
|
+
* when an EventLog implementation cannot resume from a given cursor.
|
|
32
|
+
*
|
|
33
|
+
* Subscribe handlers translate this into a 410 response.
|
|
34
|
+
*/
|
|
35
|
+
export type ProgressGapInfo = {
|
|
36
|
+
/** The cursor the consumer requested. */
|
|
37
|
+
requested: ProgressToken;
|
|
38
|
+
/** The oldest token still available for replay. */
|
|
39
|
+
oldestAvailable: ProgressToken;
|
|
40
|
+
/** The latest token available. */
|
|
41
|
+
latestAvailable: ProgressToken;
|
|
42
|
+
/** Why the cursor is no longer valid. */
|
|
43
|
+
reason: ProgressGapReason;
|
|
44
|
+
};
|
|
4
45
|
/**
|
|
5
46
|
* Internal listener type used by {@link EventLog.emit} to notify in-process
|
|
6
47
|
* subscribers. Not intended for direct consumer use — consumers should use
|
|
@@ -23,17 +64,16 @@ export type SubscriptionReply = GenericMessageReply & {
|
|
|
23
64
|
subscription?: MessageSubscription;
|
|
24
65
|
};
|
|
25
66
|
/**
|
|
26
|
-
* A regular subscription event carrying a message and its EventLog
|
|
67
|
+
* A regular subscription event carrying a message and its EventLog progress token.
|
|
27
68
|
*/
|
|
28
69
|
export type SubscriptionEvent = {
|
|
29
70
|
type: 'event';
|
|
30
71
|
/**
|
|
31
|
-
*
|
|
32
|
-
* persist this value and pass it back to `subscribe()` or `read()` to
|
|
33
|
-
* from this point.
|
|
34
|
-
* for in-memory, Redis stream ID, NATS stream sequence, etc.).
|
|
72
|
+
* Structured progress token assigned by the EventLog implementation. Clients
|
|
73
|
+
* should persist this value and pass it back to `subscribe()` or `read()` to
|
|
74
|
+
* resume from this point.
|
|
35
75
|
*/
|
|
36
|
-
cursor:
|
|
76
|
+
cursor: ProgressToken;
|
|
37
77
|
/** The event payload (message + optional initialWrite). */
|
|
38
78
|
event: MessageEvent;
|
|
39
79
|
};
|
|
@@ -47,10 +87,10 @@ export type SubscriptionEvent = {
|
|
|
47
87
|
export type SubscriptionEose = {
|
|
48
88
|
type: 'eose';
|
|
49
89
|
/**
|
|
50
|
-
*
|
|
90
|
+
* Progress token of the last stored event that was replayed.
|
|
51
91
|
* Echoes the input cursor when no stored events matched (i.e. already caught up).
|
|
52
92
|
*/
|
|
53
|
-
cursor:
|
|
93
|
+
cursor: ProgressToken;
|
|
54
94
|
};
|
|
55
95
|
/**
|
|
56
96
|
* Discriminated union of subscription event types delivered to
|
|
@@ -67,15 +107,15 @@ export type SubscriptionListener = (message: SubscriptionMessage) => void;
|
|
|
67
107
|
*/
|
|
68
108
|
export type EventLogSubscribeOptions = {
|
|
69
109
|
/**
|
|
70
|
-
*
|
|
110
|
+
* Progress token to resume from (exclusive — events after this position
|
|
71
111
|
* are replayed). When provided, stored events are replayed first, followed by
|
|
72
112
|
* an EOSE marker, then live events. When omitted, only live events are delivered.
|
|
73
113
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
114
|
+
* Tokens must be obtained from a prior interaction with the same EventLog
|
|
115
|
+
* instance (e.g. `SubscriptionEvent.cursor`, `EventLogReadResult.cursor`,
|
|
116
|
+
* or the return value of `emit()`).
|
|
77
117
|
*/
|
|
78
|
-
cursor?:
|
|
118
|
+
cursor?: ProgressToken;
|
|
79
119
|
/**
|
|
80
120
|
* Filters evaluated against event indexes. Events must match at least one
|
|
81
121
|
* filter (OR semantics). When omitted, all events are delivered.
|
|
@@ -97,8 +137,8 @@ export type EventLogEntry = {
|
|
|
97
137
|
* Options accepted by {@link EventLog.read}.
|
|
98
138
|
*/
|
|
99
139
|
export type EventLogReadOptions = {
|
|
100
|
-
/**
|
|
101
|
-
cursor?:
|
|
140
|
+
/** Progress token to resume from (exclusive — returns events after this position). */
|
|
141
|
+
cursor?: ProgressToken;
|
|
102
142
|
/** Maximum number of events to return. */
|
|
103
143
|
limit?: number;
|
|
104
144
|
/** Optional filters evaluated server-side. Events must match at least one filter (OR semantics). */
|
|
@@ -111,14 +151,14 @@ export type EventLogReadResult = {
|
|
|
111
151
|
/** Events matching the read request, ordered by ascending seq. */
|
|
112
152
|
events: EventLogEntry[];
|
|
113
153
|
/**
|
|
114
|
-
*
|
|
154
|
+
* Progress token for resuming subsequent reads or subscriptions.
|
|
115
155
|
*
|
|
116
|
-
* - When events are returned:
|
|
156
|
+
* - When events are returned: token of the last event.
|
|
117
157
|
* - When no events are returned but a cursor was provided: the input cursor
|
|
118
158
|
* (meaning "you are caught up, nothing new since this point").
|
|
119
159
|
* - When no events exist and no cursor was provided: `undefined`.
|
|
120
160
|
*/
|
|
121
|
-
cursor?:
|
|
161
|
+
cursor?: ProgressToken;
|
|
122
162
|
};
|
|
123
163
|
/**
|
|
124
164
|
* The EventLog interface provides persistent, ordered event storage with
|
|
@@ -135,9 +175,13 @@ export type EventLogReadResult = {
|
|
|
135
175
|
export interface EventLog {
|
|
136
176
|
/**
|
|
137
177
|
* Persist an event and notify in-process subscribers.
|
|
138
|
-
* @
|
|
178
|
+
* @param tenant The tenant DID.
|
|
179
|
+
* @param event The event payload.
|
|
180
|
+
* @param indexes Index values for the event.
|
|
181
|
+
* @param messageCid The CID of the message being emitted — embedded in the returned token.
|
|
182
|
+
* @returns A {@link ProgressToken} assigned to the event, or `undefined` on failure.
|
|
139
183
|
*/
|
|
140
|
-
emit(tenant: string, event: MessageEvent, indexes: KeyValues): Promise<
|
|
184
|
+
emit(tenant: string, event: MessageEvent, indexes: KeyValues, messageCid: string): Promise<ProgressToken | undefined>;
|
|
141
185
|
/**
|
|
142
186
|
* Read events from the log starting after `cursor`, optionally filtered.
|
|
143
187
|
*/
|
|
@@ -158,6 +202,15 @@ export interface EventLog {
|
|
|
158
202
|
* @param options Optional cursor and filters for catch-up replay.
|
|
159
203
|
*/
|
|
160
204
|
subscribe(tenant: string, id: string, listener: SubscriptionListener, options?: EventLogSubscribeOptions): Promise<EventSubscription>;
|
|
205
|
+
/**
|
|
206
|
+
* Returns the oldest and latest available progress tokens for a tenant,
|
|
207
|
+
* or `undefined` if the tenant has no events. Used to construct
|
|
208
|
+
* `ProgressGap` metadata when a consumer's cursor is no longer replayable.
|
|
209
|
+
*/
|
|
210
|
+
getReplayBounds(tenant: string): Promise<{
|
|
211
|
+
oldest: ProgressToken;
|
|
212
|
+
latest: ProgressToken;
|
|
213
|
+
} | undefined>;
|
|
161
214
|
/**
|
|
162
215
|
* Delete events older than the given sequence number or ISO-8601 timestamp.
|
|
163
216
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../../src/types/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../../src/types/subscriptions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../src/utils/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAOjE;;GAEG;AACH,qBAAa,QAAQ;IACnB;;OAEG;WACW,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE;IAwB3E;;;;;;;;;;OAUG;WACW,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,aAAa,CAAC,EAAE,oBAAoB,GAAG,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../src/utils/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAOjE;;GAEG;AACH,qBAAa,QAAQ;IACnB;;OAEG;WACW,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE;IAwB3E;;;;;;;;;;OAUG;WACW,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,aAAa,CAAC,EAAE,oBAAoB,GAAG,MAAM,EAAE;IA8CvG;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;CAkC7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages-subscribe.spec.d.ts","sourceRoot":"","sources":["../../../../tests/handlers/messages-subscribe.spec.ts"],"names":[],"mappings":"AAsBA,wBAAgB,4BAA4B,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"messages-subscribe.spec.d.ts","sourceRoot":"","sources":["../../../../tests/handlers/messages-subscribe.spec.ts"],"names":[],"mappings":"AAsBA,wBAAgB,4BAA4B,IAAI,IAAI,CAi8BnD"}
|
|
@@ -2,6 +2,7 @@ import type { DidResolutionResult } from '@enbox/dids';
|
|
|
2
2
|
import type { Dwn } from '../../src/dwn.js';
|
|
3
3
|
import type { GeneralJws } from '../../src/types/jws-types.js';
|
|
4
4
|
import type { MessageSigner } from '../../src/types/signer.js';
|
|
5
|
+
import type { ProgressToken } from '../../src/types/subscriptions.js';
|
|
5
6
|
import type { AuthorizationModel, Pagination } from '../../src/types/message-types.js';
|
|
6
7
|
import type { EncryptionInput } from '../../src/interfaces/records-write.js';
|
|
7
8
|
import type { DataEncodedRecordsWriteMessage, DateSort, RecordsCountMessage, RecordsDeleteMessage, RecordsFilter, RecordsQueryMessage, RecordsWriteTags } from '../../src/types/records-types.js';
|
|
@@ -159,8 +160,8 @@ export type GenerateRecordsSubscribeInput = {
|
|
|
159
160
|
dateSort?: DateSort;
|
|
160
161
|
pagination?: Pagination;
|
|
161
162
|
protocolRole?: string;
|
|
162
|
-
/**
|
|
163
|
-
cursor?:
|
|
163
|
+
/** Progress token for catch-up + EOSE subscribe. */
|
|
164
|
+
cursor?: ProgressToken;
|
|
164
165
|
};
|
|
165
166
|
export type GenerateRecordsSubscribeOutput = {
|
|
166
167
|
author: Persona | undefined;
|
|
@@ -195,8 +196,8 @@ export type GenerateMessagesSubscribeInput = {
|
|
|
195
196
|
filters?: MessagesFilter[];
|
|
196
197
|
messageTimestamp?: string;
|
|
197
198
|
permissionGrantId?: string;
|
|
198
|
-
/**
|
|
199
|
-
cursor?:
|
|
199
|
+
/** Progress token for catch-up + EOSE subscribe. */
|
|
200
|
+
cursor?: ProgressToken;
|
|
200
201
|
};
|
|
201
202
|
export type GenerateMessagesSubscribeOutput = {
|
|
202
203
|
author: Persona;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-data-generator.d.ts","sourceRoot":"","sources":["../../../../tests/utils/test-data-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"test-data-generator.d.ts","sourceRoot":"","sources":["../../../../tests/utils/test-data-generator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/core/dwn-error.ts
CHANGED
|
@@ -21,6 +21,7 @@ export enum DwnErrorCode {
|
|
|
21
21
|
ComputeCidMultihashNotSupported = 'ComputeCidMultihashNotSupported',
|
|
22
22
|
Ed25519InvalidJwk = 'Ed25519InvalidJwk',
|
|
23
23
|
EventLogNotOpenError = 'EventLogNotOpenError',
|
|
24
|
+
EventLogProgressGap = 'EventLogProgressGap',
|
|
24
25
|
MessagesGrantAuthorizationMismatchedProtocol = 'EventsGrantAuthorizationMismatchedProtocol',
|
|
25
26
|
MessagesSubscribeAuthorizationFailed = 'MessagesSubscribeAuthorizationFailed',
|
|
26
27
|
MessagesSubscribeEventLogUnimplemented = 'MessagesSubscribeEventLogUnimplemented',
|
|
@@ -7,6 +7,9 @@ import type {
|
|
|
7
7
|
EventLogSubscribeOptions,
|
|
8
8
|
EventSubscription,
|
|
9
9
|
MessageEvent,
|
|
10
|
+
ProgressGapInfo,
|
|
11
|
+
ProgressGapReason,
|
|
12
|
+
ProgressToken,
|
|
10
13
|
SubscriptionListener,
|
|
11
14
|
} from '../types/subscriptions.js';
|
|
12
15
|
|
|
@@ -30,11 +33,12 @@ type EmitterPayload = { tenant: string; event: MessageEvent; indexes: KeyValues;
|
|
|
30
33
|
type EmitterEvents = Record<string, EmitterPayload>;
|
|
31
34
|
|
|
32
35
|
/**
|
|
33
|
-
* Internal storage entry — the event plus its indexes.
|
|
36
|
+
* Internal storage entry — the event plus its indexes and message CID.
|
|
34
37
|
*/
|
|
35
38
|
type StoredEntry = {
|
|
36
39
|
event : MessageEvent;
|
|
37
40
|
indexes : KeyValues;
|
|
41
|
+
messageCid : string;
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
export interface EventEmitterEventLogConfig {
|
|
@@ -77,14 +81,92 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
77
81
|
*/
|
|
78
82
|
private tenantSeqs: Map<string, number> = new Map();
|
|
79
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Epoch for this EventLog instance. Generated once at construction as a
|
|
86
|
+
* UUID v4. Changes every restart (correct for in-memory — state is lost).
|
|
87
|
+
*/
|
|
88
|
+
private readonly epoch: string;
|
|
89
|
+
|
|
80
90
|
constructor(config: EventEmitterEventLogConfig = {}) {
|
|
81
91
|
this.maxEventsPerTenant = config.maxEventsPerTenant ?? 10_000;
|
|
92
|
+
this.epoch = crypto.randomUUID();
|
|
82
93
|
|
|
83
94
|
if (config.errorHandler) {
|
|
84
95
|
this.errorHandler = config.errorHandler;
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Derives a stable `streamId` for a given tenant. Deterministic — same
|
|
101
|
+
* tenant always produces the same streamId on any instance.
|
|
102
|
+
*/
|
|
103
|
+
private async getStreamId(tenant: string): Promise<string> {
|
|
104
|
+
const bytes = new TextEncoder().encode(tenant);
|
|
105
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);
|
|
106
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
107
|
+
// Take first 16 hex chars (64 bits) of the hash for a compact stable ID.
|
|
108
|
+
return Array.from(hashArray.slice(0, 8), (b: number) => b.toString(16).padStart(2, '0')).join('');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Constructs a {@link ProgressToken} from internal state.
|
|
113
|
+
*/
|
|
114
|
+
private async buildToken(tenant: string, seq: number, messageCid: string): Promise<ProgressToken> {
|
|
115
|
+
return {
|
|
116
|
+
streamId : await this.getStreamId(tenant),
|
|
117
|
+
epoch : this.epoch,
|
|
118
|
+
position : String(seq),
|
|
119
|
+
messageCid,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Validates a cursor against the current EventLog state. Throws
|
|
125
|
+
* `DwnError(EventLogProgressGap)` with {@link ProgressGapInfo} metadata
|
|
126
|
+
* if the cursor cannot be resumed.
|
|
127
|
+
*/
|
|
128
|
+
private async validateCursor(tenant: string, cursor: ProgressToken): Promise<void> {
|
|
129
|
+
const expectedStreamId = await this.getStreamId(tenant);
|
|
130
|
+
|
|
131
|
+
let reason: ProgressGapReason;
|
|
132
|
+
if (cursor.streamId !== expectedStreamId) {
|
|
133
|
+
reason = 'stream_mismatch';
|
|
134
|
+
} else if (cursor.epoch !== this.epoch) {
|
|
135
|
+
reason = 'epoch_mismatch';
|
|
136
|
+
} else {
|
|
137
|
+
// Check if position is still within replay bounds.
|
|
138
|
+
const log = this.tenantLogs.get(tenant);
|
|
139
|
+
if (log !== undefined && log.size > 0) {
|
|
140
|
+
const firstSeq = log.keys().next().value as number;
|
|
141
|
+
const cursorSeq = EventEmitterEventLog.parsePosition(cursor.position);
|
|
142
|
+
if (cursorSeq < firstSeq - 1) {
|
|
143
|
+
// Cursor position has been evicted — events between cursor and firstSeq are lost.
|
|
144
|
+
reason = 'token_too_old';
|
|
145
|
+
} else {
|
|
146
|
+
return; // Cursor is valid.
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
return; // No events for tenant — cursor is vacuously valid (will get empty catch-up + EOSE).
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Build gap metadata.
|
|
154
|
+
const bounds = await this.getReplayBounds(tenant);
|
|
155
|
+
const gapInfo: ProgressGapInfo = {
|
|
156
|
+
requested : cursor,
|
|
157
|
+
oldestAvailable : bounds?.oldest ?? cursor,
|
|
158
|
+
latestAvailable : bounds?.latest ?? cursor,
|
|
159
|
+
reason,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const error = new DwnError(
|
|
163
|
+
DwnErrorCode.EventLogProgressGap,
|
|
164
|
+
`progress token gap: ${reason}`
|
|
165
|
+
);
|
|
166
|
+
(error as any).gapInfo = gapInfo;
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
|
|
88
170
|
public async open(): Promise<void> {
|
|
89
171
|
this.isOpen = true;
|
|
90
172
|
}
|
|
@@ -96,13 +178,13 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
96
178
|
this.tenantSeqs.clear();
|
|
97
179
|
}
|
|
98
180
|
|
|
99
|
-
public async emit(tenant: string, event: MessageEvent, indexes: KeyValues): Promise<
|
|
181
|
+
public async emit(tenant: string, event: MessageEvent, indexes: KeyValues, messageCid: string): Promise<ProgressToken | undefined> {
|
|
100
182
|
if (!this.isOpen) {
|
|
101
183
|
this.errorHandler(new DwnError(
|
|
102
184
|
DwnErrorCode.EventLogNotOpenError,
|
|
103
185
|
'a message emitted when EventLog is closed'
|
|
104
186
|
));
|
|
105
|
-
return
|
|
187
|
+
return undefined;
|
|
106
188
|
}
|
|
107
189
|
|
|
108
190
|
// Assign a monotonic sequence number for this tenant.
|
|
@@ -116,7 +198,7 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
116
198
|
log = new Map();
|
|
117
199
|
this.tenantLogs.set(tenant, log);
|
|
118
200
|
}
|
|
119
|
-
log.set(seq, { event, indexes });
|
|
201
|
+
log.set(seq, { event, indexes, messageCid });
|
|
120
202
|
|
|
121
203
|
// Evict oldest entries if the log exceeds the retention limit.
|
|
122
204
|
if (log.size > this.maxEventsPerTenant) {
|
|
@@ -133,12 +215,18 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
133
215
|
const channel = `${tenant}_${EVENTS_LISTENER_CHANNEL}`;
|
|
134
216
|
this.emitter.emit(channel, { tenant, event, indexes, seq });
|
|
135
217
|
|
|
136
|
-
return
|
|
218
|
+
return this.buildToken(tenant, seq, messageCid);
|
|
137
219
|
}
|
|
138
220
|
|
|
139
221
|
public async read(tenant: string, options: EventLogReadOptions = {}): Promise<EventLogReadResult> {
|
|
140
222
|
const { cursor, limit, filters } = options;
|
|
141
|
-
|
|
223
|
+
|
|
224
|
+
// Validate cursor before attempting to read.
|
|
225
|
+
if (cursor !== undefined) {
|
|
226
|
+
await this.validateCursor(tenant, cursor);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const cursorSeq = cursor !== undefined ? EventEmitterEventLog.parsePosition(cursor.position) : undefined;
|
|
142
230
|
const log = this.tenantLogs.get(tenant);
|
|
143
231
|
|
|
144
232
|
if (log === undefined || log.size === 0) {
|
|
@@ -166,19 +254,36 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
166
254
|
if (results.length >= maxResults) { break; }
|
|
167
255
|
}
|
|
168
256
|
|
|
169
|
-
|
|
170
|
-
|
|
257
|
+
if (results.length > 0) {
|
|
258
|
+
const lastEntry = results[results.length - 1];
|
|
259
|
+
const lastStoredEntry = log.get(lastEntry.seq);
|
|
260
|
+
const lastToken = await this.buildToken(tenant, lastEntry.seq, lastStoredEntry!.messageCid);
|
|
261
|
+
return { events: results, cursor: lastToken };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return { events: results, cursor };
|
|
171
265
|
}
|
|
172
266
|
|
|
173
267
|
/**
|
|
174
|
-
* Parse
|
|
268
|
+
* Parse a position string into an internal sequence number using BigInt
|
|
269
|
+
* for safe handling of values beyond `Number.MAX_SAFE_INTEGER`.
|
|
270
|
+
*
|
|
271
|
+
* The returned `number` is safe for the in-memory EventLog which uses
|
|
272
|
+
* `Map<number, StoredEntry>` keys — in-memory sequences will never
|
|
273
|
+
* exceed safe integer range. The BigInt parse validates correctness
|
|
274
|
+
* before the narrowing conversion.
|
|
175
275
|
*/
|
|
176
|
-
private static
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
276
|
+
private static parsePosition(position: string): number {
|
|
277
|
+
try {
|
|
278
|
+
const big = BigInt(position);
|
|
279
|
+
if (big < 0n) {
|
|
280
|
+
throw new DwnError(DwnErrorCode.EventLogNotOpenError, `invalid cursor position: '${position}'`);
|
|
281
|
+
}
|
|
282
|
+
return Number(big);
|
|
283
|
+
} catch (e) {
|
|
284
|
+
if (e instanceof DwnError) { throw e; }
|
|
285
|
+
throw new DwnError(DwnErrorCode.EventLogNotOpenError, `invalid cursor position: '${position}'`);
|
|
180
286
|
}
|
|
181
|
-
return seq;
|
|
182
287
|
}
|
|
183
288
|
|
|
184
289
|
public async subscribe(
|
|
@@ -190,9 +295,20 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
190
295
|
const channel = `${tenant}_${EVENTS_LISTENER_CHANNEL}`;
|
|
191
296
|
const { cursor, filters } = options ?? {};
|
|
192
297
|
|
|
298
|
+
// Helper to build a token from a live emitter payload.
|
|
299
|
+
const tokenFromPayload = async (payload: EmitterPayload): Promise<ProgressToken> => {
|
|
300
|
+
const log = this.tenantLogs.get(tenant);
|
|
301
|
+
const stored = log?.get(payload.seq);
|
|
302
|
+
const cid = stored?.messageCid ?? '';
|
|
303
|
+
return this.buildToken(tenant, payload.seq, cid);
|
|
304
|
+
};
|
|
305
|
+
|
|
193
306
|
if (cursor !== undefined) {
|
|
194
307
|
// ---- Cursor mode: catch-up from stored events, then EOSE, then live ----
|
|
195
|
-
|
|
308
|
+
// Validate cursor before subscribing — throws DwnError(EventLogProgressGap) on gap.
|
|
309
|
+
await this.validateCursor(tenant, cursor);
|
|
310
|
+
|
|
311
|
+
const cursorSeq = EventEmitterEventLog.parsePosition(cursor.position);
|
|
196
312
|
|
|
197
313
|
// Buffer live events that arrive during catch-up to avoid losing them.
|
|
198
314
|
type BufferedEvent = { event: MessageEvent; seq: number };
|
|
@@ -207,7 +323,9 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
207
323
|
if (!catchUpComplete) {
|
|
208
324
|
pendingLiveEvents.push({ event: payload.event, seq: payload.seq });
|
|
209
325
|
} else {
|
|
210
|
-
|
|
326
|
+
void tokenFromPayload(payload).then((token) => {
|
|
327
|
+
listener({ type: 'event', cursor: token, event: payload.event });
|
|
328
|
+
});
|
|
211
329
|
}
|
|
212
330
|
};
|
|
213
331
|
|
|
@@ -215,19 +333,27 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
215
333
|
|
|
216
334
|
// Step 2: Read stored events from cursor and deliver them.
|
|
217
335
|
const readResult = await this.read(tenant, { cursor, filters });
|
|
218
|
-
// The read cursor is the last event
|
|
336
|
+
// The read cursor is the token of the last read event, or the input cursor if nothing new.
|
|
219
337
|
const eoseCursor = readResult.cursor ?? cursor;
|
|
220
|
-
const lastCatchUpSeq = readResult.cursor !== undefined
|
|
338
|
+
const lastCatchUpSeq = readResult.cursor !== undefined
|
|
339
|
+
? EventEmitterEventLog.parsePosition(readResult.cursor.position)
|
|
340
|
+
: cursorSeq;
|
|
221
341
|
|
|
222
342
|
for (const entry of readResult.events) {
|
|
223
|
-
|
|
343
|
+
const log = this.tenantLogs.get(tenant);
|
|
344
|
+
const stored = log?.get(entry.seq);
|
|
345
|
+
const token = await this.buildToken(tenant, entry.seq, stored?.messageCid ?? '');
|
|
346
|
+
listener({ type: 'event', cursor: token, event: entry.event });
|
|
224
347
|
}
|
|
225
348
|
|
|
226
349
|
// Step 3: Deliver any live events that arrived during catch-up (with seq > lastCatchUpSeq).
|
|
227
350
|
catchUpComplete = true;
|
|
228
351
|
for (const liveEvent of pendingLiveEvents) {
|
|
229
352
|
if (liveEvent.seq > lastCatchUpSeq) {
|
|
230
|
-
|
|
353
|
+
const log = this.tenantLogs.get(tenant);
|
|
354
|
+
const stored = log?.get(liveEvent.seq);
|
|
355
|
+
const token = await this.buildToken(tenant, liveEvent.seq, stored?.messageCid ?? '');
|
|
356
|
+
listener({ type: 'event', cursor: token, event: liveEvent.event });
|
|
231
357
|
}
|
|
232
358
|
}
|
|
233
359
|
|
|
@@ -246,7 +372,9 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
246
372
|
if (filters !== undefined && filters.length > 0) {
|
|
247
373
|
if (!FilterUtility.matchAnyFilter(payload.indexes, filters)) { return; }
|
|
248
374
|
}
|
|
249
|
-
|
|
375
|
+
void tokenFromPayload(payload).then((token) => {
|
|
376
|
+
listener({ type: 'event', cursor: token, event: payload.event });
|
|
377
|
+
});
|
|
250
378
|
};
|
|
251
379
|
|
|
252
380
|
this.emitter.on(channel, handler);
|
|
@@ -257,6 +385,26 @@ export class EventEmitterEventLog implements EventLog {
|
|
|
257
385
|
};
|
|
258
386
|
}
|
|
259
387
|
|
|
388
|
+
public async getReplayBounds(tenant: string): Promise<{ oldest: ProgressToken; latest: ProgressToken } | undefined> {
|
|
389
|
+
const log = this.tenantLogs.get(tenant);
|
|
390
|
+
if (log === undefined || log.size === 0) {
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Map is ordered by insertion (ascending seq). First and last keys are min/max.
|
|
395
|
+
const keys = [...log.keys()];
|
|
396
|
+
const oldestSeq = keys[0];
|
|
397
|
+
const latestSeq = keys[keys.length - 1];
|
|
398
|
+
|
|
399
|
+
const oldestEntry = log.get(oldestSeq)!;
|
|
400
|
+
const latestEntry = log.get(latestSeq)!;
|
|
401
|
+
|
|
402
|
+
const oldest = await this.buildToken(tenant, oldestSeq, oldestEntry.messageCid);
|
|
403
|
+
const latest = await this.buildToken(tenant, latestSeq, latestEntry.messageCid);
|
|
404
|
+
|
|
405
|
+
return { oldest, latest };
|
|
406
|
+
}
|
|
407
|
+
|
|
260
408
|
public async trim(tenant: string, olderThan: number | string): Promise<void> {
|
|
261
409
|
const log = this.tenantLogs.get(tenant);
|
|
262
410
|
if (log === undefined) { return; }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { MessageStore } from '../types/message-store.js';
|
|
2
|
-
import type { SubscriptionListener } from '../types/subscriptions.js';
|
|
3
2
|
import type { HandlerDependencies, MethodHandler } from '../types/method-handler.js';
|
|
4
3
|
import type { MessagesSubscribeMessage, MessagesSubscribeReply } from '../types/messages-types.js';
|
|
4
|
+
import type { ProgressGapInfo, SubscriptionListener } from '../types/subscriptions.js';
|
|
5
5
|
|
|
6
6
|
import { authenticate } from '../core/auth.js';
|
|
7
7
|
import { Message } from '../core/message.js';
|
|
@@ -61,6 +61,13 @@ export class MessagesSubscribeHandler implements MethodHandler {
|
|
|
61
61
|
subscription,
|
|
62
62
|
};
|
|
63
63
|
} catch (error) {
|
|
64
|
+
if (error instanceof DwnError && error.code === DwnErrorCode.EventLogProgressGap) {
|
|
65
|
+
const gapInfo = (error as any).gapInfo as ProgressGapInfo | undefined;
|
|
66
|
+
return {
|
|
67
|
+
status : { code: 410, detail: 'Progress token gap' },
|
|
68
|
+
error : gapInfo !== undefined ? { code: 'ProgressGap' as const, ...gapInfo } : undefined,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
64
71
|
return messageReplyFromError(error, 500);
|
|
65
72
|
}
|
|
66
73
|
}
|