@durable-streams/server 0.2.0 → 0.2.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/index.cjs +490 -69
- package/dist/index.d.cts +76 -1
- package/dist/index.d.ts +76 -1
- package/dist/index.js +490 -69
- package/package.json +4 -4
- package/src/file-store.ts +259 -11
- package/src/server.ts +357 -54
- package/src/store.ts +201 -7
- package/src/types.ts +17 -0
package/dist/index.d.cts
CHANGED
|
@@ -61,6 +61,20 @@ interface Stream {
|
|
|
61
61
|
* Maps producer ID to their epoch and sequence state.
|
|
62
62
|
*/
|
|
63
63
|
producers?: Map<string, ProducerState>;
|
|
64
|
+
/**
|
|
65
|
+
* Whether the stream is closed (no further appends permitted).
|
|
66
|
+
* Once set to true, this is permanent and durable.
|
|
67
|
+
*/
|
|
68
|
+
closed?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The producer tuple that closed this stream (for idempotent close).
|
|
71
|
+
* If set, duplicate close requests with this tuple return 204.
|
|
72
|
+
*/
|
|
73
|
+
closedBy?: {
|
|
74
|
+
producerId: string;
|
|
75
|
+
epoch: number;
|
|
76
|
+
seq: number;
|
|
77
|
+
};
|
|
64
78
|
}
|
|
65
79
|
/**
|
|
66
80
|
* Event data for stream lifecycle hooks.
|
|
@@ -177,6 +191,8 @@ type ProducerValidationResult = {
|
|
|
177
191
|
status: `sequence_gap`;
|
|
178
192
|
expectedSeq: number;
|
|
179
193
|
receivedSeq: number;
|
|
194
|
+
} | {
|
|
195
|
+
status: `stream_closed`;
|
|
180
196
|
};
|
|
181
197
|
/**
|
|
182
198
|
* Pending long-poll request.
|
|
@@ -212,6 +228,7 @@ interface AppendOptions {
|
|
|
212
228
|
producerId?: string;
|
|
213
229
|
producerEpoch?: number;
|
|
214
230
|
producerSeq?: number;
|
|
231
|
+
close?: boolean;
|
|
215
232
|
}
|
|
216
233
|
/**
|
|
217
234
|
* Result of an append operation.
|
|
@@ -219,6 +236,7 @@ interface AppendOptions {
|
|
|
219
236
|
interface AppendResult {
|
|
220
237
|
message: StreamMessage | null;
|
|
221
238
|
producerResult?: ProducerValidationResult;
|
|
239
|
+
streamClosed?: boolean;
|
|
222
240
|
}
|
|
223
241
|
declare class StreamStore {
|
|
224
242
|
private streams;
|
|
@@ -247,6 +265,7 @@ declare class StreamStore {
|
|
|
247
265
|
ttlSeconds?: number;
|
|
248
266
|
expiresAt?: string;
|
|
249
267
|
initialData?: Uint8Array;
|
|
268
|
+
closed?: boolean;
|
|
250
269
|
}): Stream;
|
|
251
270
|
/**
|
|
252
271
|
* Get a stream by path.
|
|
@@ -299,6 +318,28 @@ declare class StreamStore {
|
|
|
299
318
|
*/
|
|
300
319
|
appendWithProducer(path: string, data: Uint8Array, options: AppendOptions): Promise<AppendResult>;
|
|
301
320
|
/**
|
|
321
|
+
* Close a stream without appending data.
|
|
322
|
+
* @returns The final offset, or null if stream doesn't exist
|
|
323
|
+
*/
|
|
324
|
+
closeStream(path: string): {
|
|
325
|
+
finalOffset: string;
|
|
326
|
+
alreadyClosed: boolean;
|
|
327
|
+
} | null;
|
|
328
|
+
/**
|
|
329
|
+
* Close a stream with producer headers for idempotent close-only operations.
|
|
330
|
+
* Participates in producer sequencing for deduplication.
|
|
331
|
+
* @returns The final offset and producer result, or null if stream doesn't exist
|
|
332
|
+
*/
|
|
333
|
+
closeStreamWithProducer(path: string, options: {
|
|
334
|
+
producerId: string;
|
|
335
|
+
producerEpoch: number;
|
|
336
|
+
producerSeq: number;
|
|
337
|
+
}): Promise<{
|
|
338
|
+
finalOffset: string;
|
|
339
|
+
alreadyClosed: boolean;
|
|
340
|
+
producerResult?: ProducerValidationResult;
|
|
341
|
+
} | null>;
|
|
342
|
+
/**
|
|
302
343
|
* Get the current epoch for a producer on a stream.
|
|
303
344
|
* Returns undefined if the producer doesn't exist or stream not found.
|
|
304
345
|
*/
|
|
@@ -324,6 +365,7 @@ declare class StreamStore {
|
|
|
324
365
|
waitForMessages(path: string, offset: string, timeoutMs: number): Promise<{
|
|
325
366
|
messages: Array<StreamMessage>;
|
|
326
367
|
timedOut: boolean;
|
|
368
|
+
streamClosed?: boolean;
|
|
327
369
|
}>;
|
|
328
370
|
/**
|
|
329
371
|
* Get the current offset for a stream.
|
|
@@ -345,6 +387,11 @@ declare class StreamStore {
|
|
|
345
387
|
private appendToStream;
|
|
346
388
|
private findOffsetIndex;
|
|
347
389
|
private notifyLongPolls;
|
|
390
|
+
/**
|
|
391
|
+
* Notify pending long-polls that a stream has been closed.
|
|
392
|
+
* They should wake up immediately and return Stream-Closed: true.
|
|
393
|
+
*/
|
|
394
|
+
private notifyLongPollsClosed;
|
|
348
395
|
private cancelLongPollsForStream;
|
|
349
396
|
private removePendingLongPoll;
|
|
350
397
|
} //#endregion
|
|
@@ -421,6 +468,7 @@ declare class FileBackedStreamStore {
|
|
|
421
468
|
ttlSeconds?: number;
|
|
422
469
|
expiresAt?: string;
|
|
423
470
|
initialData?: Uint8Array;
|
|
471
|
+
closed?: boolean;
|
|
424
472
|
}): Promise<Stream>;
|
|
425
473
|
get(streamPath: string): Stream | undefined;
|
|
426
474
|
has(streamPath: string): boolean;
|
|
@@ -433,6 +481,28 @@ declare class FileBackedStreamStore {
|
|
|
433
481
|
* This ensures that validation+append is atomic per producer.
|
|
434
482
|
*/
|
|
435
483
|
appendWithProducer(streamPath: string, data: Uint8Array, options: AppendOptions): Promise<AppendResult>;
|
|
484
|
+
/**
|
|
485
|
+
* Close a stream without appending data.
|
|
486
|
+
* @returns The final offset, or null if stream doesn't exist
|
|
487
|
+
*/
|
|
488
|
+
closeStream(streamPath: string): {
|
|
489
|
+
finalOffset: string;
|
|
490
|
+
alreadyClosed: boolean;
|
|
491
|
+
} | null;
|
|
492
|
+
/**
|
|
493
|
+
* Close a stream with producer headers for idempotent close-only operations.
|
|
494
|
+
* Participates in producer sequencing for deduplication.
|
|
495
|
+
* @returns The final offset and producer result, or null if stream doesn't exist
|
|
496
|
+
*/
|
|
497
|
+
closeStreamWithProducer(streamPath: string, options: {
|
|
498
|
+
producerId: string;
|
|
499
|
+
producerEpoch: number;
|
|
500
|
+
producerSeq: number;
|
|
501
|
+
}): Promise<{
|
|
502
|
+
finalOffset: string;
|
|
503
|
+
alreadyClosed: boolean;
|
|
504
|
+
producerResult?: ProducerValidationResult;
|
|
505
|
+
} | null>;
|
|
436
506
|
read(streamPath: string, offset?: string): {
|
|
437
507
|
messages: Array<StreamMessage>;
|
|
438
508
|
upToDate: boolean;
|
|
@@ -440,6 +510,7 @@ declare class FileBackedStreamStore {
|
|
|
440
510
|
waitForMessages(streamPath: string, offset: string, timeoutMs: number): Promise<{
|
|
441
511
|
messages: Array<StreamMessage>;
|
|
442
512
|
timedOut: boolean;
|
|
513
|
+
streamClosed?: boolean;
|
|
443
514
|
}>;
|
|
444
515
|
/**
|
|
445
516
|
* Format messages for response.
|
|
@@ -455,10 +526,14 @@ declare class FileBackedStreamStore {
|
|
|
455
526
|
cancelAllWaits(): void;
|
|
456
527
|
list(): Array<string>;
|
|
457
528
|
private notifyLongPolls;
|
|
529
|
+
/**
|
|
530
|
+
* Notify pending long-polls that a stream has been closed.
|
|
531
|
+
* They should wake up immediately and return Stream-Closed: true.
|
|
532
|
+
*/
|
|
533
|
+
private notifyLongPollsClosed;
|
|
458
534
|
private cancelLongPollsForStream;
|
|
459
535
|
private removePendingLongPoll;
|
|
460
536
|
}
|
|
461
|
-
|
|
462
537
|
//#endregion
|
|
463
538
|
//#region src/server.d.ts
|
|
464
539
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,20 @@ interface Stream {
|
|
|
61
61
|
* Maps producer ID to their epoch and sequence state.
|
|
62
62
|
*/
|
|
63
63
|
producers?: Map<string, ProducerState>;
|
|
64
|
+
/**
|
|
65
|
+
* Whether the stream is closed (no further appends permitted).
|
|
66
|
+
* Once set to true, this is permanent and durable.
|
|
67
|
+
*/
|
|
68
|
+
closed?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The producer tuple that closed this stream (for idempotent close).
|
|
71
|
+
* If set, duplicate close requests with this tuple return 204.
|
|
72
|
+
*/
|
|
73
|
+
closedBy?: {
|
|
74
|
+
producerId: string;
|
|
75
|
+
epoch: number;
|
|
76
|
+
seq: number;
|
|
77
|
+
};
|
|
64
78
|
}
|
|
65
79
|
/**
|
|
66
80
|
* Event data for stream lifecycle hooks.
|
|
@@ -177,6 +191,8 @@ type ProducerValidationResult = {
|
|
|
177
191
|
status: `sequence_gap`;
|
|
178
192
|
expectedSeq: number;
|
|
179
193
|
receivedSeq: number;
|
|
194
|
+
} | {
|
|
195
|
+
status: `stream_closed`;
|
|
180
196
|
};
|
|
181
197
|
/**
|
|
182
198
|
* Pending long-poll request.
|
|
@@ -212,6 +228,7 @@ interface AppendOptions {
|
|
|
212
228
|
producerId?: string;
|
|
213
229
|
producerEpoch?: number;
|
|
214
230
|
producerSeq?: number;
|
|
231
|
+
close?: boolean;
|
|
215
232
|
}
|
|
216
233
|
/**
|
|
217
234
|
* Result of an append operation.
|
|
@@ -219,6 +236,7 @@ interface AppendOptions {
|
|
|
219
236
|
interface AppendResult {
|
|
220
237
|
message: StreamMessage | null;
|
|
221
238
|
producerResult?: ProducerValidationResult;
|
|
239
|
+
streamClosed?: boolean;
|
|
222
240
|
}
|
|
223
241
|
declare class StreamStore {
|
|
224
242
|
private streams;
|
|
@@ -247,6 +265,7 @@ declare class StreamStore {
|
|
|
247
265
|
ttlSeconds?: number;
|
|
248
266
|
expiresAt?: string;
|
|
249
267
|
initialData?: Uint8Array;
|
|
268
|
+
closed?: boolean;
|
|
250
269
|
}): Stream;
|
|
251
270
|
/**
|
|
252
271
|
* Get a stream by path.
|
|
@@ -299,6 +318,28 @@ declare class StreamStore {
|
|
|
299
318
|
*/
|
|
300
319
|
appendWithProducer(path: string, data: Uint8Array, options: AppendOptions): Promise<AppendResult>;
|
|
301
320
|
/**
|
|
321
|
+
* Close a stream without appending data.
|
|
322
|
+
* @returns The final offset, or null if stream doesn't exist
|
|
323
|
+
*/
|
|
324
|
+
closeStream(path: string): {
|
|
325
|
+
finalOffset: string;
|
|
326
|
+
alreadyClosed: boolean;
|
|
327
|
+
} | null;
|
|
328
|
+
/**
|
|
329
|
+
* Close a stream with producer headers for idempotent close-only operations.
|
|
330
|
+
* Participates in producer sequencing for deduplication.
|
|
331
|
+
* @returns The final offset and producer result, or null if stream doesn't exist
|
|
332
|
+
*/
|
|
333
|
+
closeStreamWithProducer(path: string, options: {
|
|
334
|
+
producerId: string;
|
|
335
|
+
producerEpoch: number;
|
|
336
|
+
producerSeq: number;
|
|
337
|
+
}): Promise<{
|
|
338
|
+
finalOffset: string;
|
|
339
|
+
alreadyClosed: boolean;
|
|
340
|
+
producerResult?: ProducerValidationResult;
|
|
341
|
+
} | null>;
|
|
342
|
+
/**
|
|
302
343
|
* Get the current epoch for a producer on a stream.
|
|
303
344
|
* Returns undefined if the producer doesn't exist or stream not found.
|
|
304
345
|
*/
|
|
@@ -324,6 +365,7 @@ declare class StreamStore {
|
|
|
324
365
|
waitForMessages(path: string, offset: string, timeoutMs: number): Promise<{
|
|
325
366
|
messages: Array<StreamMessage>;
|
|
326
367
|
timedOut: boolean;
|
|
368
|
+
streamClosed?: boolean;
|
|
327
369
|
}>;
|
|
328
370
|
/**
|
|
329
371
|
* Get the current offset for a stream.
|
|
@@ -345,6 +387,11 @@ declare class StreamStore {
|
|
|
345
387
|
private appendToStream;
|
|
346
388
|
private findOffsetIndex;
|
|
347
389
|
private notifyLongPolls;
|
|
390
|
+
/**
|
|
391
|
+
* Notify pending long-polls that a stream has been closed.
|
|
392
|
+
* They should wake up immediately and return Stream-Closed: true.
|
|
393
|
+
*/
|
|
394
|
+
private notifyLongPollsClosed;
|
|
348
395
|
private cancelLongPollsForStream;
|
|
349
396
|
private removePendingLongPoll;
|
|
350
397
|
} //#endregion
|
|
@@ -421,6 +468,7 @@ declare class FileBackedStreamStore {
|
|
|
421
468
|
ttlSeconds?: number;
|
|
422
469
|
expiresAt?: string;
|
|
423
470
|
initialData?: Uint8Array;
|
|
471
|
+
closed?: boolean;
|
|
424
472
|
}): Promise<Stream>;
|
|
425
473
|
get(streamPath: string): Stream | undefined;
|
|
426
474
|
has(streamPath: string): boolean;
|
|
@@ -433,6 +481,28 @@ declare class FileBackedStreamStore {
|
|
|
433
481
|
* This ensures that validation+append is atomic per producer.
|
|
434
482
|
*/
|
|
435
483
|
appendWithProducer(streamPath: string, data: Uint8Array, options: AppendOptions): Promise<AppendResult>;
|
|
484
|
+
/**
|
|
485
|
+
* Close a stream without appending data.
|
|
486
|
+
* @returns The final offset, or null if stream doesn't exist
|
|
487
|
+
*/
|
|
488
|
+
closeStream(streamPath: string): {
|
|
489
|
+
finalOffset: string;
|
|
490
|
+
alreadyClosed: boolean;
|
|
491
|
+
} | null;
|
|
492
|
+
/**
|
|
493
|
+
* Close a stream with producer headers for idempotent close-only operations.
|
|
494
|
+
* Participates in producer sequencing for deduplication.
|
|
495
|
+
* @returns The final offset and producer result, or null if stream doesn't exist
|
|
496
|
+
*/
|
|
497
|
+
closeStreamWithProducer(streamPath: string, options: {
|
|
498
|
+
producerId: string;
|
|
499
|
+
producerEpoch: number;
|
|
500
|
+
producerSeq: number;
|
|
501
|
+
}): Promise<{
|
|
502
|
+
finalOffset: string;
|
|
503
|
+
alreadyClosed: boolean;
|
|
504
|
+
producerResult?: ProducerValidationResult;
|
|
505
|
+
} | null>;
|
|
436
506
|
read(streamPath: string, offset?: string): {
|
|
437
507
|
messages: Array<StreamMessage>;
|
|
438
508
|
upToDate: boolean;
|
|
@@ -440,6 +510,7 @@ declare class FileBackedStreamStore {
|
|
|
440
510
|
waitForMessages(streamPath: string, offset: string, timeoutMs: number): Promise<{
|
|
441
511
|
messages: Array<StreamMessage>;
|
|
442
512
|
timedOut: boolean;
|
|
513
|
+
streamClosed?: boolean;
|
|
443
514
|
}>;
|
|
444
515
|
/**
|
|
445
516
|
* Format messages for response.
|
|
@@ -455,10 +526,14 @@ declare class FileBackedStreamStore {
|
|
|
455
526
|
cancelAllWaits(): void;
|
|
456
527
|
list(): Array<string>;
|
|
457
528
|
private notifyLongPolls;
|
|
529
|
+
/**
|
|
530
|
+
* Notify pending long-polls that a stream has been closed.
|
|
531
|
+
* They should wake up immediately and return Stream-Closed: true.
|
|
532
|
+
*/
|
|
533
|
+
private notifyLongPollsClosed;
|
|
458
534
|
private cancelLongPollsForStream;
|
|
459
535
|
private removePendingLongPoll;
|
|
460
536
|
}
|
|
461
|
-
|
|
462
537
|
//#endregion
|
|
463
538
|
//#region src/server.d.ts
|
|
464
539
|
/**
|