@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.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
  /**