@okikio/observables 1.0.2 → 1.3.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.
@@ -14,7 +14,7 @@
14
14
  */
15
15
  import "../../_dnt.polyfills.js";
16
16
  import type { ExcludeError, Operator } from "../_types.js";
17
- import type { ObservableError } from "../../error.js";
17
+ import { ObservableError } from "../../error.js";
18
18
  /**
19
19
  * Checks if every item in the stream passes a test.
20
20
  *
@@ -125,6 +125,45 @@ export declare function some<T>(predicate: (value: ExcludeError<T>, index: numbe
125
125
  * @returns A stream operator that finds the first matching value
126
126
  */
127
127
  export declare function find<T>(predicate: (value: ExcludeError<T>, index: number) => boolean): Operator<T | ObservableError, T | ObservableError>;
128
+ /**
129
+ * Finds the index of the first item in the stream that passes a test.
130
+ *
131
+ * This mirrors `Array.prototype.findIndex()`: it emits the zero-based index of
132
+ * the first matching value, or `-1` if the stream completes without a match.
133
+ *
134
+ * @typeParam T - Type of values from the source stream
135
+ * @param predicate - Function to test each value
136
+ * @returns An operator that emits the first matching index or `-1`
137
+ */
138
+ export declare function findIndex<T>(predicate: (value: ExcludeError<T>, index: number) => boolean): Operator<T | ObservableError, number | ObservableError>;
139
+ /**
140
+ * Emits the value at a specific zero-based source index.
141
+ *
142
+ * Unlike arrays, streams cannot jump to a position directly, so this operator
143
+ * reads and counts values until it reaches the requested slot. If the stream
144
+ * completes first, it emits nothing.
145
+ *
146
+ * @typeParam T - Type of values from the source stream
147
+ * @param targetIndex - Zero-based index to emit
148
+ * @returns An operator that emits at most one value from the requested index
149
+ */
150
+ export declare function elementAt<T>(targetIndex: number): Operator<T | ObservableError, T | ObservableError>;
151
+ /**
152
+ * Emits the first value in the stream, optionally constrained by a predicate.
153
+ *
154
+ * Without a predicate this is the Observable equivalent of reading index `0`.
155
+ * With a predicate it behaves like `find()`, but the name is useful when the
156
+ * caller wants to emphasize "take the first match" rather than "search".
157
+ *
158
+ * @typeParam T - Type of values from the source stream
159
+ * @param predicate - Optional test that the first emitted value must satisfy
160
+ * @returns An operator that emits at most one matching value
161
+ */
162
+ export declare function first<T>(): Operator<T | ObservableError, T | ObservableError>;
163
+ /**
164
+ * Emits the first value that satisfies the provided predicate.
165
+ */
166
+ export declare function first<T>(predicate: (value: ExcludeError<T>, index: number) => boolean): Operator<T | ObservableError, T | ObservableError>;
128
167
  /**
129
168
  * Removes duplicate values from the stream, keeping only the first occurrence.
130
169
  *
@@ -165,12 +204,48 @@ export declare function find<T>(predicate: (value: ExcludeError<T>, index: numbe
165
204
  * @returns An operator that filters out duplicate values.
166
205
  */
167
206
  export declare function unique<T, K = T>(keySelector?: (value: ExcludeError<T>) => K): Operator<T | ObservableError, ExcludeError<T> | ObservableError>;
207
+ /**
208
+ * Configuration for `changed()`.
209
+ *
210
+ * `by` lets you compare on a derived key instead of the full value.
211
+ * For example, you may want to emit only when `user.id` changes.
212
+ */
213
+ export interface ChangedOptions<T, K = ExcludeError<T>> {
214
+ /**
215
+ * Pick the value that should be compared.
216
+ *
217
+ * By default, the full value is compared.
218
+ */
219
+ by?: (value: ExcludeError<T>, index: number) => K;
220
+ /**
221
+ * Decide whether two comparison keys should be treated as the same.
222
+ *
223
+ * By default, `Object.is()` is used.
224
+ */
225
+ equals?: (previous: K, current: K) => boolean;
226
+ /**
227
+ * Whether the first non-error value should be emitted.
228
+ *
229
+ * This defaults to `true`, which is usually what people expect from a
230
+ * "changed" operator.
231
+ */
232
+ emitFirst?: boolean;
233
+ }
168
234
  /**
169
235
  * Emits an item only if it is different from the previous one.
170
236
  *
171
237
  * This is useful for streams where values can be emitted repeatedly, but you
172
238
  * only care about the changes.
173
239
  *
240
+ * Example 1:
241
+ * source: 1, 1, 2, 2, 3
242
+ * output: 1, 2, 3
243
+ *
244
+ * Example 2:
245
+ * source: { id: 1, name: "A" }, { id: 1, name: "B" }, { id: 2, name: "C" }
246
+ * changed({ by: value => value.id })
247
+ * output: first item, then the item with id 2
248
+ *
174
249
  * @example
175
250
  * ```ts
176
251
  * import { pipe, changed, from } from "./helpers/mod.ts";
@@ -208,4 +283,5 @@ export declare function unique<T, K = T>(keySelector?: (value: ExcludeError<T>)
208
283
  * @param compare An optional function to compare two keys for equality.
209
284
  * @returns An operator that filters out consecutive duplicate values.
210
285
  */
286
+ export declare function changed<T, K = ExcludeError<T>>(options?: ChangedOptions<T, K>): Operator<T | ObservableError, T | ObservableError>;
211
287
  //# sourceMappingURL=conditional.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conditional.d.ts","sourceRoot":"","sources":["../../../src/helpers/operations/conditional.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,KAAK,CAAC,CAAC,EACrB,SAAS,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GAC5D,QAAQ,CAAC,CAAC,GAAG,eAAe,EAAE,OAAO,GAAG,eAAe,CAAC,CA2B1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,IAAI,CAAC,CAAC,EACpB,SAAS,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GAC5D,QAAQ,CAAC,CAAC,GAAG,eAAe,EAAE,OAAO,GAAG,eAAe,CAAC,CA2B1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,IAAI,CAAC,CAAC,EACpB,SAAS,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GAC5D,QAAQ,CAAC,CAAC,GAAG,eAAe,EAAE,CAAC,GAAG,eAAe,CAAC,CAcpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAC7B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAC1C,QAAQ,CAAC,CAAC,GAAG,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAqBlE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG"}
1
+ {"version":3,"file":"conditional.d.ts","sourceRoot":"","sources":["../../../src/helpers/operations/conditional.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.every = every;
4
4
  exports.some = some;
5
5
  exports.find = find;
6
+ exports.findIndex = findIndex;
7
+ exports.elementAt = elementAt;
8
+ exports.first = first;
6
9
  exports.unique = unique;
10
+ exports.changed = changed;
7
11
  /**
8
12
  * Predicate and decision-oriented operators for Observable streams.
9
13
  *
@@ -19,6 +23,7 @@ exports.unique = unique;
19
23
  * @module
20
24
  */
21
25
  require("../../_dnt.polyfills.js");
26
+ const error_js_1 = require("../../error.js");
22
27
  const operators_js_1 = require("../operators.js");
23
28
  /**
24
29
  * Checks if every item in the stream passes a test.
@@ -187,6 +192,74 @@ function find(predicate) {
187
192
  },
188
193
  });
189
194
  }
195
+ /**
196
+ * Finds the index of the first item in the stream that passes a test.
197
+ *
198
+ * This mirrors `Array.prototype.findIndex()`: it emits the zero-based index of
199
+ * the first matching value, or `-1` if the stream completes without a match.
200
+ *
201
+ * @typeParam T - Type of values from the source stream
202
+ * @param predicate - Function to test each value
203
+ * @returns An operator that emits the first matching index or `-1`
204
+ */
205
+ function findIndex(predicate) {
206
+ return (0, operators_js_1.createStatefulOperator)({
207
+ name: "findIndex",
208
+ createState: () => ({ index: 0, finished: false }),
209
+ transform(chunk, state, controller) {
210
+ if (state.finished) {
211
+ return;
212
+ }
213
+ const currentIndex = state.index;
214
+ const result = predicate(chunk, currentIndex);
215
+ state.index++;
216
+ if (result) {
217
+ state.finished = true;
218
+ controller.enqueue(currentIndex);
219
+ controller.terminate();
220
+ }
221
+ },
222
+ flush(state, controller) {
223
+ if (!state.finished) {
224
+ controller.enqueue(-1);
225
+ }
226
+ },
227
+ });
228
+ }
229
+ /**
230
+ * Emits the value at a specific zero-based source index.
231
+ *
232
+ * Unlike arrays, streams cannot jump to a position directly, so this operator
233
+ * reads and counts values until it reaches the requested slot. If the stream
234
+ * completes first, it emits nothing.
235
+ *
236
+ * @typeParam T - Type of values from the source stream
237
+ * @param targetIndex - Zero-based index to emit
238
+ * @returns An operator that emits at most one value from the requested index
239
+ */
240
+ function elementAt(targetIndex) {
241
+ if (!Number.isInteger(targetIndex) || targetIndex < 0) {
242
+ throw new RangeError("elementAt: targetIndex must be a non-negative integer");
243
+ }
244
+ return (0, operators_js_1.createStatefulOperator)({
245
+ name: "elementAt",
246
+ createState: () => ({ index: 0 }),
247
+ transform(chunk, state, controller) {
248
+ if (state.index === targetIndex) {
249
+ controller.enqueue(chunk);
250
+ controller.terminate();
251
+ return;
252
+ }
253
+ state.index++;
254
+ },
255
+ });
256
+ }
257
+ function first(predicate) {
258
+ if (!predicate) {
259
+ return elementAt(0);
260
+ }
261
+ return find(predicate);
262
+ }
190
263
  /**
191
264
  * Removes duplicate values from the stream, keeping only the first occurrence.
192
265
  *
@@ -241,12 +314,27 @@ function unique(keySelector) {
241
314
  },
242
315
  });
243
316
  }
317
+ function defaultBy(value) {
318
+ return value;
319
+ }
320
+ function defaultEquals(previous, current) {
321
+ return Object.is(previous, current);
322
+ }
244
323
  /**
245
324
  * Emits an item only if it is different from the previous one.
246
325
  *
247
326
  * This is useful for streams where values can be emitted repeatedly, but you
248
327
  * only care about the changes.
249
328
  *
329
+ * Example 1:
330
+ * source: 1, 1, 2, 2, 3
331
+ * output: 1, 2, 3
332
+ *
333
+ * Example 2:
334
+ * source: { id: 1, name: "A" }, { id: 1, name: "B" }, { id: 2, name: "C" }
335
+ * changed({ by: value => value.id })
336
+ * output: first item, then the item with id 2
337
+ *
250
338
  * @example
251
339
  * ```ts
252
340
  * import { pipe, changed, from } from "./helpers/mod.ts";
@@ -284,3 +372,58 @@ function unique(keySelector) {
284
372
  * @param compare An optional function to compare two keys for equality.
285
373
  * @returns An operator that filters out consecutive duplicate values.
286
374
  */
375
+ function changed(options = {}) {
376
+ const by = (options.by ??
377
+ defaultBy);
378
+ const equals = (options.equals ??
379
+ defaultEquals);
380
+ const emitFirst = options.emitFirst ?? true;
381
+ return (0, operators_js_1.createStatefulOperator)({
382
+ name: "changed",
383
+ createState: () => ({
384
+ hasPrevious: false,
385
+ previousKey: undefined,
386
+ index: 0,
387
+ }),
388
+ transform(chunk, state, controller) {
389
+ if ((0, error_js_1.isObservableError)(chunk)) {
390
+ controller.enqueue(chunk);
391
+ return;
392
+ }
393
+ const value = chunk;
394
+ let currentKey;
395
+ try {
396
+ currentKey = by(value, state.index++);
397
+ }
398
+ catch (err) {
399
+ controller.enqueue(error_js_1.ObservableError.from(err, "operator:stateful:changed:by", value));
400
+ return;
401
+ }
402
+ if (!state.hasPrevious) {
403
+ state.hasPrevious = true;
404
+ state.previousKey = currentKey;
405
+ if (emitFirst) {
406
+ controller.enqueue(value);
407
+ }
408
+ return;
409
+ }
410
+ let isSame;
411
+ try {
412
+ isSame = equals(state.previousKey, currentKey);
413
+ }
414
+ catch (err) {
415
+ controller.enqueue(error_js_1.ObservableError.from(err, "operator:stateful:changed:equals", value));
416
+ return;
417
+ }
418
+ state.previousKey = currentKey;
419
+ if (!isSame) {
420
+ controller.enqueue(value);
421
+ }
422
+ },
423
+ cancel(state) {
424
+ state.hasPrevious = false;
425
+ state.previousKey = undefined;
426
+ state.index = 0;
427
+ },
428
+ });
429
+ }
@@ -436,6 +436,63 @@ export declare function handleStart<T, O, S extends unknown = undefined>(errorMo
436
436
  * @returns A function suitable for TransformStream's `flush` property, or undefined
437
437
  */
438
438
  export declare function handleFlush<T, O, S extends unknown = undefined>(errorMode: OperatorErrorMode, flush?: TransformFunctionOptions<T, O>["flush"] | StatefulTransformFunctionOptions<T, O, S>["flush"], context?: TransformHandlerContext<S>): Transformer<T, O>["flush"];
439
+ /**
440
+ * Lifecycle handling for downstream cancellation cleanup.
441
+ *
442
+ * `flush()` runs when the source ends normally. `cancel()` runs when a consumer
443
+ * stops early, for example by unsubscribing, breaking out of `for await`, or
444
+ * otherwise cancelling the pipeline before the source completes.
445
+ *
446
+ * ```text
447
+ * source completes normally -> flush()
448
+ * consumer stops early -> cancel(reason)
449
+ * ```
450
+ *
451
+ * That distinction matters for operators that hold timers, inner
452
+ * subscriptions, or abort controllers. Those resources should be released when
453
+ * the consumer goes away, even if the source never reached completion.
454
+ *
455
+ * Cleanup here is intentionally not treated like transform output. If the
456
+ * cleanup callback fails, the cancellation promise rejects, but no
457
+ * `ObservableError` is emitted into the stream because the consumer has already
458
+ * said it is no longer interested in more values.
459
+ *
460
+ * @typeParam T - Input chunk type
461
+ * @typeParam O - Output chunk type
462
+ * @typeParam S - State type (for stateful operators)
463
+ * @param _errorMode - Unused here. Cancellation cleanup does not route through
464
+ * the operator error modes because it is teardown, not part of the data path.
465
+ * @param cancel - Your cancellation handler (stateless or stateful, optional)
466
+ * @param context - Info about the operator, including name and state
467
+ * @returns A function suitable for a ReadableStream `cancel` hook, or undefined
468
+ */
469
+ export declare function handleCancel<T, O, S extends unknown = undefined>(_errorMode: OperatorErrorMode, cancel?: TransformFunctionOptions<T, O>["cancel"] | StatefulTransformFunctionOptions<T, O, S>["cancel"], context?: TransformHandlerContext<S>): ((reason?: unknown) => Promise<void>) | undefined;
470
+ /**
471
+ * Wraps a transformed stream so operator-level cleanup runs when a downstream
472
+ * consumer stops early.
473
+ *
474
+ * This wrapper has a deliberately narrow job: it forwards readable-side
475
+ * cancellation to an operator cleanup callback while preserving the chunks
476
+ * coming from the wrapped stream. It does not try to redefine TransformStream
477
+ * semantics or reinterpret cancellation as a normal data-path error.
478
+ *
479
+ * ```text
480
+ * source -> TransformStream -> wrapped readable -> consumer
481
+ * |
482
+ * +-> cancel(reason)
483
+ * ```
484
+ *
485
+ * @typeParam T - Output chunk type of the wrapped stream
486
+ * @param stream - The transformed stream to expose downstream
487
+ * @param options - Cancellation behavior for the wrapped stream
488
+ * @returns A readable stream that preserves output values and forwards cancel
489
+ */
490
+ export declare function wrapStreamWithCancel<T>(stream: ReadableStream<T>, options?: {
491
+ /**
492
+ * Cleanup to run if the consumer cancels the stream before it completes.
493
+ */
494
+ cancel?: (reason?: unknown) => void | Promise<void>;
495
+ }): ReadableStream<T>;
439
496
  /**
440
497
  * Creates operators that maintain state across stream chunks
441
498
  *
@@ -1 +1 @@
1
- {"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../src/helpers/operators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../src/helpers/operators.ts"],"names":[],"mappings":"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"}
@@ -224,6 +224,8 @@ exports.createOperator = createOperator;
224
224
  exports.handleTransform = handleTransform;
225
225
  exports.handleStart = handleStart;
226
226
  exports.handleFlush = handleFlush;
227
+ exports.handleCancel = handleCancel;
228
+ exports.wrapStreamWithCancel = wrapStreamWithCancel;
227
229
  exports.createStatefulOperator = createStatefulOperator;
228
230
  const utils_js_1 = require("./utils.js");
229
231
  const error_js_1 = require("../error.js");
@@ -237,6 +239,7 @@ function createOperator(options) {
237
239
  const transform = options?.transform;
238
240
  const start = options?.start;
239
241
  const flush = options?.flush;
242
+ const cancel = options?.cancel;
240
243
  return (source) => {
241
244
  try {
242
245
  // Create a transform stream with the provided options
@@ -250,8 +253,10 @@ function createOperator(options) {
250
253
  // Flush function called when the input is done
251
254
  flush: handleFlush(errorMode, flush, { operatorName }),
252
255
  }, { highWaterMark: 1 }, { highWaterMark: 0 });
253
- // Pipe the source through the transform
254
- return source.pipeThrough(transformStream);
256
+ // Pipe the source through the transform and bind downstream cancellation
257
+ return wrapStreamWithCancel(source.pipeThrough(transformStream), {
258
+ cancel: handleCancel(errorMode, cancel, { operatorName }),
259
+ });
255
260
  }
256
261
  catch (err) {
257
262
  // If setup fails, return a stream that errors immediately
@@ -508,6 +513,131 @@ function handleFlush(errorMode, flush, context = {}) {
508
513
  }
509
514
  };
510
515
  }
516
+ /**
517
+ * Lifecycle handling for downstream cancellation cleanup.
518
+ *
519
+ * `flush()` runs when the source ends normally. `cancel()` runs when a consumer
520
+ * stops early, for example by unsubscribing, breaking out of `for await`, or
521
+ * otherwise cancelling the pipeline before the source completes.
522
+ *
523
+ * ```text
524
+ * source completes normally -> flush()
525
+ * consumer stops early -> cancel(reason)
526
+ * ```
527
+ *
528
+ * That distinction matters for operators that hold timers, inner
529
+ * subscriptions, or abort controllers. Those resources should be released when
530
+ * the consumer goes away, even if the source never reached completion.
531
+ *
532
+ * Cleanup here is intentionally not treated like transform output. If the
533
+ * cleanup callback fails, the cancellation promise rejects, but no
534
+ * `ObservableError` is emitted into the stream because the consumer has already
535
+ * said it is no longer interested in more values.
536
+ *
537
+ * @typeParam T - Input chunk type
538
+ * @typeParam O - Output chunk type
539
+ * @typeParam S - State type (for stateful operators)
540
+ * @param _errorMode - Unused here. Cancellation cleanup does not route through
541
+ * the operator error modes because it is teardown, not part of the data path.
542
+ * @param cancel - Your cancellation handler (stateless or stateful, optional)
543
+ * @param context - Info about the operator, including name and state
544
+ * @returns A function suitable for a ReadableStream `cancel` hook, or undefined
545
+ */
546
+ function handleCancel(_errorMode, cancel, context = {}) {
547
+ if (!cancel)
548
+ return;
549
+ const operatorName = context.operatorName || `operator:unknown`;
550
+ const isStateful = context.isStateful || false;
551
+ const state = context.state;
552
+ return async function (reason) {
553
+ try {
554
+ if (isStateful) {
555
+ await cancel(state, reason);
556
+ return;
557
+ }
558
+ await cancel(reason);
559
+ }
560
+ catch (err) {
561
+ throw error_js_1.ObservableError.from(err, `${operatorName}:cancel`, reason);
562
+ }
563
+ };
564
+ }
565
+ /**
566
+ * Wraps a transformed stream so operator-level cleanup runs when a downstream
567
+ * consumer stops early.
568
+ *
569
+ * This wrapper has a deliberately narrow job: it forwards readable-side
570
+ * cancellation to an operator cleanup callback while preserving the chunks
571
+ * coming from the wrapped stream. It does not try to redefine TransformStream
572
+ * semantics or reinterpret cancellation as a normal data-path error.
573
+ *
574
+ * ```text
575
+ * source -> TransformStream -> wrapped readable -> consumer
576
+ * |
577
+ * +-> cancel(reason)
578
+ * ```
579
+ *
580
+ * @typeParam T - Output chunk type of the wrapped stream
581
+ * @param stream - The transformed stream to expose downstream
582
+ * @param options - Cancellation behavior for the wrapped stream
583
+ * @returns A readable stream that preserves output values and forwards cancel
584
+ */
585
+ function wrapStreamWithCancel(stream, options = {}) {
586
+ if (!options.cancel)
587
+ return stream;
588
+ const reader = stream.getReader();
589
+ let settled = false;
590
+ // The wrapper acquires an exclusive reader, so releasing it exactly once
591
+ // keeps teardown predictable even when both cancel and read completion race.
592
+ const release = () => {
593
+ if (settled)
594
+ return;
595
+ settled = true;
596
+ try {
597
+ reader.releaseLock();
598
+ }
599
+ catch {
600
+ // Releasing the reader is best-effort during teardown.
601
+ }
602
+ };
603
+ return new ReadableStream({
604
+ async pull(controller) {
605
+ try {
606
+ // Forward chunks one-by-one so downstream backpressure still controls
607
+ // how quickly we read from the wrapped stream.
608
+ const { done, value } = await reader.read();
609
+ if (done) {
610
+ release();
611
+ controller.close();
612
+ return;
613
+ }
614
+ controller.enqueue(value);
615
+ }
616
+ catch (err) {
617
+ release();
618
+ controller.error(err);
619
+ }
620
+ },
621
+ async cancel(reason) {
622
+ try {
623
+ // Run operator cleanup first so resources such as timers or inner
624
+ // subscriptions are released before we cancel the wrapped reader.
625
+ await options.cancel?.(reason);
626
+ }
627
+ finally {
628
+ try {
629
+ // Cancelling the reader tells the wrapped stream that nobody wants
630
+ // more output. Any rejection here is surfaced through the returned
631
+ // cancellation promise instead of being emitted as a chunk.
632
+ await reader.cancel(reason);
633
+ }
634
+ finally {
635
+ release();
636
+ }
637
+ }
638
+ },
639
+ });
640
+ }
511
641
  // Default case
512
642
  function createStatefulOperator(options) {
513
643
  // Extract operator name from options or the function name for better error reporting
@@ -519,6 +649,7 @@ function createStatefulOperator(options) {
519
649
  ?.transform;
520
650
  const start = options?.start;
521
651
  const flush = options?.flush;
652
+ const cancel = options?.cancel;
522
653
  return (source) => {
523
654
  try {
524
655
  // Create state only when the stream is used
@@ -559,8 +690,14 @@ function createStatefulOperator(options) {
559
690
  state,
560
691
  }),
561
692
  }, { highWaterMark: 1 }, { highWaterMark: 0 });
562
- // Pipe the source through the transform
563
- return source.pipeThrough(transformStream);
693
+ // Pipe the source through the transform and bind downstream cancellation
694
+ return wrapStreamWithCancel(source.pipeThrough(transformStream), {
695
+ cancel: handleCancel(errorMode, cancel, {
696
+ operatorName,
697
+ isStateful: true,
698
+ state,
699
+ }),
700
+ });
564
701
  }
565
702
  catch (err) {
566
703
  // If setup fails, return a stream that errors immediately
@@ -1,6 +1,7 @@
1
- import type { TransformFunctionOptions, TransformStreamOptions } from "./_types.js";
1
+ import type { ObservableInteropInputLike, ObservableOperatorInterop, ObservableOperatorInteropOptions, TransformFunctionOptions, StreamPair, TransformStreamOptions } from "./_types.js";
2
2
  import type { CreateOperatorOptions, Operator } from "./_types.js";
3
3
  import { ObservableError } from "../error.js";
4
+ import { Observable } from "../observable.js";
4
5
  /**
5
6
  * Type guard to check if options is a TransformStreamOptions
6
7
  *
@@ -73,6 +74,77 @@ export declare function applyOperator(input: ReadableStream<unknown>, operator:
73
74
  * ```
74
75
  */
75
76
  export declare function toStream<T>(iterable: Iterable<T> | AsyncIterable<T>): ReadableStream<T | ObservableError>;
77
+ /**
78
+ * Adapts a readable/writable stream pair into an Observable operator.
79
+ *
80
+ * Some platform transforms, such as `CompressionStream`, expose a writable side
81
+ * and a readable side without being created through this library's operator
82
+ * builders. This helper turns that pair into a normal `Operator` so it can be
83
+ * used inside `pipe()` like any built-in operator.
84
+ *
85
+ * A fresh pair is created for each operator application. That preserves the
86
+ * cold semantics of the surrounding Observable pipeline and avoids reusing a
87
+ * consumed stream pair across subscriptions.
88
+ *
89
+ * @typeParam TIn - Chunk type written into the pair
90
+ * @typeParam TOut - Chunk type read from the pair
91
+ * @param createPair - Factory that returns a fresh readable/writable pair
92
+ * @returns An operator that pipes input through the created pair
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * const gzip = fromStreamPair<Uint8Array, Uint8Array>(
97
+ * () => new CompressionStream('gzip')
98
+ * );
99
+ * ```
100
+ */
101
+ export declare function fromStreamPair<TIn, TOut>(createPair: () => StreamPair<TIn, TOut>): Operator<TIn, TOut>;
102
+ /**
103
+ * Wraps a `ReadableStream` as an Observable so foreign Observable-style
104
+ * operators can subscribe to it directly.
105
+ *
106
+ * This avoids first converting the stream into an async-iterable Observable via
107
+ * `Observable.from()`, which would add an extra adaptation layer before the
108
+ * foreign operator even starts running.
109
+ */
110
+ export declare function streamAsObservable<T>(stream: ReadableStream<T>): Observable<T>;
111
+ /**
112
+ * Subscribes to an Observable-like output and exposes it as a ReadableStream.
113
+ *
114
+ * Foreign operators are allowed to return either a normal `Observable.from()`
115
+ * input or a direct subscribable from another Observable implementation.
116
+ * Converting the result with a direct subscription avoids the extra
117
+ * async-generator and stream layers that `pull(...)+toStream()` would add.
118
+ */
119
+ export declare function observableInputToStream<T>(input: ObservableInteropInputLike<T>, errorContext: string): ReadableStream<T | ObservableError>;
120
+ /**
121
+ * Adapts a foreign Observable-style operator into a stream operator.
122
+ *
123
+ * Libraries such as RxJS model operators as functions from one Observable-like
124
+ * source to another Observable-like result. This helper bridges that shape into
125
+ * this library's `Operator` contract by:
126
+ *
127
+ * 1. wrapping the input stream as an Observable-like source
128
+ * 2. calling the foreign operator
129
+ * 3. converting the resulting Observable-like output back into a stream
130
+ *
131
+ * The result keeps this library's buffered error behavior by converting the
132
+ * foreign output into a `ReadableStream` that enqueues wrapped
133
+ * `ObservableError` values instead of failing the readable side outright.
134
+ *
135
+ * @typeParam TIn - Value type accepted by the foreign operator
136
+ * @typeParam TOut - Value type produced by the foreign operator
137
+ * @param operator - Foreign operator function to adapt
138
+ * @returns An operator compatible with this library's `pipe()`
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * const foreignTakeOne = fromObservableOperator<number, number>((source) =>
143
+ * rxTake(1)(source)
144
+ * , { sourceAdapter: (source) => rxFrom(source) });
145
+ * ```
146
+ */
147
+ export declare function fromObservableOperator<TIn, TOut, TSource = Observable<TIn>>(operator: ObservableOperatorInterop<TIn, TOut, TSource>, options?: ObservableOperatorInteropOptions<TIn, TSource>): Operator<TIn, TOut | ObservableError>;
76
148
  /**
77
149
  * Creates a TransformStream that injects an error at the start and passes through all original data.
78
150
  *
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/helpers/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,CAAC,EAC3C,OAAO,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,GACnC,OAAO,IAAI,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,CAEzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,CAAC,EAC7C,OAAO,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,GACnC,OAAO,IAAI,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAE3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAE9B,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,EAC5B,EAAE,OAAyB,EAAE;;CAAK,GACjC,cAAc,CAAC,OAAO,CAAC,CAOzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GACvC,cAAc,CAAC,CAAC,GAAG,eAAe,CAAC,CAkCrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,GAAG,OAAO,EAAE,EAC7C,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,GACd,eAAe,CAAC,CAAC,EAAE,eAAe,CAAC,CAOrC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/helpers/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,wBAAwB,EACxB,UAAU,EACV,sBAAsB,EACvB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,CAAC,EAC3C,OAAO,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,GACnC,OAAO,IAAI,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,CAEzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,CAAC,EAC7C,OAAO,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,GACnC,OAAO,IAAI,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAE3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAE9B,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,EAC5B,EAAE,OAAyB,EAAE;;CAAK,GACjC,cAAc,CAAC,OAAO,CAAC,CAOzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GACvC,cAAc,CAAC,CAAC,GAAG,eAAe,CAAC,CAkCrC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,EACtC,UAAU,EAAE,MAAM,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GACtC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAErB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAsC9E;AAsBD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,KAAK,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACpC,YAAY,EAAE,MAAM,GACnB,cAAc,CAAC,CAAC,GAAG,eAAe,CAAC,CAqCrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,EACzE,QAAQ,EAAE,yBAAyB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,EACvD,OAAO,CAAC,EAAE,gCAAgC,CAAC,GAAG,EAAE,OAAO,CAAC,GACvD,QAAQ,CAAC,GAAG,EAAE,IAAI,GAAG,eAAe,CAAC,CAcvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,GAAG,OAAO,EAAE,EAC7C,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,GACd,eAAe,CAAC,CAAC,EAAE,eAAe,CAAC,CAOrC"}