@thi.ng/rstream 7.2.46 → 8.0.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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-03-27T19:05:48Z
3
+ - **Last updated**: 2023-04-08T11:09:50Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,39 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ # [8.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/rstream@8.0.0) (2023-04-08)
13
+
14
+ #### 🛑 Breaking changes
15
+
16
+ - simplify/unify sidechain API ([5e90431](https://github.com/thi-ng/umbrella/commit/5e90431))
17
+ - BREAKING CHANGE: simplify/unify sidechain subscription API
18
+ - update sidechainPartition/Toggle/Trigger() to take src sub as 1st arg
19
+ - old: `src.subscribe(sidechainXXX(side))`...
20
+ - new: `sidechainXXX(src, side)`
21
+ - update docs
22
+ - update tests
23
+
24
+ #### 🚀 Features
25
+
26
+ - add syncRAF() ([3c17520](https://github.com/thi-ng/umbrella/commit/3c17520))
27
+ - add SyncRAF class and syncRAF() factory
28
+ - deprecate sidechainPartitionRAF()
29
+ - add tests
30
+ - add sidechainTrigger() ([3d2b56d](https://github.com/thi-ng/umbrella/commit/3d2b56d))
31
+ - add timestamp support for fromRAF() ([a2b8629](https://github.com/thi-ng/umbrella/commit/a2b8629))
32
+ - add FromRAFOpts
33
+ - update docs
34
+
35
+ #### 🩹 Bug fixes
36
+
37
+ - fix opts handling in syncRAF() & fromView() ([baa8878](https://github.com/thi-ng/umbrella/commit/baa8878))
38
+
39
+ #### ♻️ Refactoring
40
+
41
+ - update KeyStreams type ([1dd60e9](https://github.com/thi-ng/umbrella/commit/1dd60e9))
42
+ - switch value types Subscription => ISubscription
43
+ - minor update sidechainPartition/Toggle() ([c3ffd38](https://github.com/thi-ng/umbrella/commit/c3ffd38))
44
+
12
45
  ### [7.2.46](https://github.com/thi-ng/umbrella/tree/@thi.ng/rstream@7.2.46) (2023-03-27)
13
46
 
14
47
  #### ♻️ Refactoring
package/README.md CHANGED
@@ -35,6 +35,7 @@ This project is part of the
35
35
  - [Side-chaining](#side-chaining)
36
36
  - [Input chunking / buffering, controlled by sidechain](#input-chunking--buffering-controlled-by-sidechain)
37
37
  - [Input toggling, controlled by sidechain](#input-toggling-controlled-by-sidechain)
38
+ - [Input passthrough, controlled by sidechain](#input-passthrough-controlled-by-sidechain)
38
39
  - [Worker support](#worker-support)
39
40
  - [Parallel stream processing via workers](#parallel-stream-processing-via-workers)
40
41
  - [Stream processing via workers](#stream-processing-via-workers)
@@ -196,7 +197,7 @@ For Node.js REPL:
196
197
  const rstream = await import("@thi.ng/rstream");
197
198
  ```
198
199
 
199
- Package sizes (brotli'd, pre-treeshake): ESM: 5.63 KB
200
+ Package sizes (brotli'd, pre-treeshake): ESM: 5.80 KB
200
201
 
201
202
  ## Dependencies
202
203
 
@@ -237,6 +238,7 @@ A selection:
237
238
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/parse-playground.png" width="240"/> | Parser grammar livecoding editor/playground & codegen | [Demo](https://demo.thi.ng/umbrella/parse-playground/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/parse-playground) |
238
239
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-sorting.png" width="240"/> | Interactive pixel sorting tool using thi.ng/color & thi.ng/pixel | [Demo](https://demo.thi.ng/umbrella/pixel-sorting/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/pixel-sorting) |
239
240
  | | Demonstates various rdom usage patterns | [Demo](https://demo.thi.ng/umbrella/rdom-basics/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-basics) |
241
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-canvas-basics.png" width="240"/> | Minimal rdom-canvas animation | [Demo](https://demo.thi.ng/umbrella/rdom-canvas-basics/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-canvas-basics) |
240
242
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-delayed-update.jpg" width="240"/> | Dynamically loaded images w/ preloader state | [Demo](https://demo.thi.ng/umbrella/rdom-delayed-update/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-delayed-update) |
241
243
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-lissajous.png" width="240"/> | rdom & hiccup-canvas interop test | [Demo](https://demo.thi.ng/umbrella/rdom-lissajous/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-lissajous) |
242
244
  | | Full umbrella repo doc string search w/ paginated results | [Demo](https://demo.thi.ng/umbrella/rdom-search-docs/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-search-docs) |
@@ -246,9 +248,11 @@ A selection:
246
248
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rstream-grid.jpg" width="240"/> | Interactive grid generator, SVG generation & export, undo/redo support | [Demo](https://demo.thi.ng/umbrella/rstream-grid/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rstream-grid) |
247
249
  | | rstream based UI updates & state handling | [Demo](https://demo.thi.ng/umbrella/rstream-hdom/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rstream-hdom) |
248
250
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rstream-spreadsheet.png" width="240"/> | rstream based spreadsheet w/ S-expression formula DSL | [Demo](https://demo.thi.ng/umbrella/rstream-spreadsheet/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rstream-spreadsheet) |
251
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rstream-sync.png" width="240"/> | Minimal rstream sync() example using rdom | [Demo](https://demo.thi.ng/umbrella/rstream-sync/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rstream-sync) |
249
252
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-ast-workers.jpg" width="240"/> | Fork-join worker-based raymarch renderer (JS/CPU only) | [Demo](https://demo.thi.ng/umbrella/shader-ast-workers/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/shader-ast-workers) |
250
253
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/svg-resample.png" width="240"/> | SVG path parsing & dynamic resampling | [Demo](https://demo.thi.ng/umbrella/svg-resample/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/svg-resample) |
251
254
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/talk-slides.png" width="240"/> | hdom based slide deck viewer & slides from my ClojureX 2018 keynote | [Demo](http://media.thi.ng/2018/talks/clojurex/index.html) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/talk-slides) |
255
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/trace-bitmap.jpg" width="240"/> | Multi-layer vectorization & dithering of bitmap images | [Demo](https://demo.thi.ng/umbrella/trace-bitmap/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/trace-bitmap) |
252
256
  | | Transducer & rstream based hdom UI updates | [Demo](https://demo.thi.ng/umbrella/transducers-hdom/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/transducers-hdom) |
253
257
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-channel-mixer.jpg" width="240"/> | rdom & WebGL-based image channel editor | [Demo](https://demo.thi.ng/umbrella/webgl-channel-mixer/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/webgl-channel-mixer) |
254
258
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/webgl-cubemap.jpg" width="240"/> | WebGL cube maps with async texture loading | [Demo](https://demo.thi.ng/umbrella/webgl-cubemap/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/webgl-cubemap) |
@@ -304,7 +308,7 @@ interface CommonOpts {
304
308
 
305
309
  #### Stream
306
310
 
307
- Source: [stream()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/stream.ts)
311
+ Docs: [stream()](https://docs.thi.ng/umbrella/rstream/functions/stream-1.html)
308
312
 
309
313
  Creates a new `Stream` instance, optionally with given `StreamSource`
310
314
  function and / or ID. If a `src` function is provided, the function
@@ -361,7 +365,7 @@ will always return `undefined`.
361
365
 
362
366
  #### Subscription
363
367
 
364
- Source: [subscription()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/subscription.ts)
368
+ Docs: [subscription()](https://docs.thi.ng/umbrella/rstream/functions/subscription-1.html)
365
369
 
366
370
  Creates a new `Subscription` instance, the fundamental datatype &
367
371
  building block provided by this package (`Stream`s are `Subscription`s
@@ -393,25 +397,26 @@ s.next(42);
393
397
 
394
398
  #### Other stream creation helpers
395
399
 
396
- - [reactive()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/stream.ts) - syntax sugar for `stream()` with initial value
397
- - [fromAtom()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/atom.ts) - streams from value changes in atoms/cursors
400
+ - [reactive()](https://docs.thi.ng/umbrella/rstream/functions/reactive.html) - syntax sugar for `stream()` with initial value
401
+ - [fromAtom()](https://docs.thi.ng/umbrella/rstream/functions/fromAtom.html) - streams from value changes in atoms/cursors
398
402
  - [fromChannel()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream-csp) - CSP channel to stream conversion
399
- - [fromEvent()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/event.ts) - events
400
- - [fromDOMEvent()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/event.ts#L25) - DOM events
401
- - [fromInterval()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/interval.ts) - interval based counters
402
- - [fromIterable()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/iterable.ts) - arrays, iterators / generators (async & sync)
403
- - [fromNodeJS() / linesFromNodeJS()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/nodejs.ts) - NodeJS streams adapters
404
- - [fromObject()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/object.ts) - object property streams
405
- - [fromPromise()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/promise.ts) - single value stream from promise
406
- - [fromPromises()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/promises.ts) - results from multiple promise
407
- - [fromRAF()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/raf.ts) - requestAnimationFrame() counter (w/ node fallback)
408
- - [fromView()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/view.ts) - derived view changes (see [@thi.ng/atom](https://github.com/thi-ng/umbrella/tree/develop/packages/atom))
409
- - [fromWorker()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/worker.ts) - messages received from worker
410
- - [trigger()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/trigger.ts) - one-off events
403
+ - [fromEvent()](https://docs.thi.ng/umbrella/rstream/functions/fromEvent.html) - events
404
+ - [fromDOMEvent()](https://docs.thi.ng/umbrella/rstream/functions/fromDOMEvent.html) - DOM events
405
+ - [fromInterval()](https://docs.thi.ng/umbrella/rstream/functions/fromInterval.html) - interval based counters
406
+ - [fromIterable()](https://docs.thi.ng/umbrella/rstream/functions/fromIterable.html) - arrays, iterators / generators (async & sync)
407
+ - [fromNodeJS()](https://docs.thi.ng/umbrella/rstream/functions/fromNodeJS.html) - NodeJS stream adapter
408
+ - [linesFromNodeJS()](https://docs.thi.ng/umbrella/rstream/functions/linesFromNodeJS.html) - NodeJS stream adapter
409
+ - [fromObject()](https://docs.thi.ng/umbrella/rstream/functions/fromObject.html) - object property streams
410
+ - [fromPromise()](https://docs.thi.ng/umbrella/rstream/functions/fromPromise.html) - single value stream from promise
411
+ - [fromPromises()](https://docs.thi.ng/umbrella/rstream/functions/fromPromises.html) - results from multiple promise
412
+ - [fromRAF()](https://docs.thi.ng/umbrella/rstream/functions/fromRAF.html) - requestAnimationFrame() counter (w/ node fallback)
413
+ - [fromView()](https://docs.thi.ng/umbrella/rstream/functions/fromView.html) - derived view value changes (see [@thi.ng/atom](https://github.com/thi-ng/umbrella/tree/develop/packages/atom))
414
+ - [fromWorker()](https://docs.thi.ng/umbrella/rstream/functions/fromWorker.html) - messages received from worker
415
+ - [trigger()](https://docs.thi.ng/umbrella/rstream/functions/trigger.html) - one-off events
411
416
 
412
417
  ### Meta streams
413
418
 
414
- Source: [metaStream()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/metastream.ts)
419
+ Docs: [metaStream()](https://docs.thi.ng/umbrella/rstream/functions/metaStream-1.html)
415
420
 
416
421
  `MetaStream`s are streams of streams. A `MetaStream` is a subscription
417
422
  type which transforms each incoming value into a new stream, subscribes
@@ -496,7 +501,7 @@ m.next(true);
496
501
 
497
502
  #### Unordered merge from multiple inputs (dynamic add/remove)
498
503
 
499
- Source: [merge()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/stream-merge.ts)
504
+ Docs: [merge()](https://docs.thi.ng/umbrella/rstream/functions/merge.html)
500
505
 
501
506
  ![diagram](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/rstream/rstream-merge.png)
502
507
 
@@ -528,9 +533,8 @@ merge({
528
533
  ```
529
534
 
530
535
  Use the [`labeled()`
531
- transducer](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers/src/xform/labeled.ts)
532
- for each input to create a stream of labeled values and track their
533
- provenance:
536
+ transducer](https://docs.thi.ng/umbrella/transducers/functions/labeled.html) for
537
+ each input to create a stream of labeled values and track their provenance:
534
538
 
535
539
  ```ts
536
540
  merge({
@@ -548,7 +552,7 @@ merge({
548
552
  ```
549
553
 
550
554
  See
551
- [StreamMergeOpts](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/stream-merge.ts#L7)
555
+ [StreamMergeOpts](https://docs.thi.ng/umbrella/rstream/interfaces/StreamMergeOpts.html)
552
556
  for further reference of the various behavior options.
553
557
 
554
558
  ##### Adding inputs automatically
@@ -559,8 +563,10 @@ as new input to the merge and then automatically remove once that stream
559
563
  is exhausted.
560
564
 
561
565
  ```ts
566
+ import { repeat } from "@thi.ng/transducers";
567
+
562
568
  // stream source w/ transducer mapping values to new streams
563
- a = stream().transform(tx.map((x) => fromIterable(tx.repeat(x, 3))));
569
+ a = stream().map((x) => fromIterable(repeat(x, 3)));
564
570
  // simple 1Hz counter
565
571
  b = fromInterval(1000);
566
572
 
@@ -571,17 +577,17 @@ merge({ src: [a, b] }).subscribe(trace());
571
577
 
572
578
  // sent "a" will be transformed into stream via above transducer
573
579
  // and then auto-added as new input to the StreamMerge
574
- a.next("a");
575
- // a
576
- // a
577
- // a
580
+ a.next("abc");
581
+ // abc
582
+ // abc
583
+ // abc
578
584
  // 3
579
585
  // 4
580
586
  ```
581
587
 
582
588
  #### Synchronized merge and labeled tuple objects
583
589
 
584
- Source: [sync()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/stream-sync.ts)
590
+ Docs: [sync()](https://docs.thi.ng/umbrella/rstream/functions/sync.html)
585
591
 
586
592
  ![diagram](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/rstream/rstream-sync.png)
587
593
 
@@ -622,19 +628,20 @@ be incomplete, by default. To only allow complete tuples, also set the
622
628
  `all` option to `false`.
623
629
 
624
630
  The synchronization is done via the
625
- [`partitionSync()`](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers/src/xform/partition-sync.ts)
626
- transducer from the @thi.ng/transducers package. See this function's
627
- docs for further details.
631
+ [`partitionSync()`](https://docs.thi.ng/umbrella/transducers/functions/partitionSync-1.html)
632
+ transducer from the
633
+ [@thi.ng/transducers](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers)
634
+ package. See this function's docs for further details.
628
635
 
629
636
  See
630
- [StreamSyncOpts](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/stream-sync.ts#L12)
637
+ [StreamSyncOpts](https://docs.thi.ng/umbrella/rstream/interfaces/StreamSyncOpts.html)
631
638
  for further reference of the various behavior options.
632
639
 
633
640
  ### Stream splitting
634
641
 
635
642
  #### Topic based splitting
636
643
 
637
- Source: [pubsub()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/pubsub.ts)
644
+ Docs: [pubsub()](https://docs.thi.ng/umbrella/rstream/functions/pubsub-1.html)
638
645
 
639
646
  ![diagram](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/rstream/rstream-pubsub.png)
640
647
 
@@ -659,7 +666,7 @@ called WITHOUT argument to unsubscribe the entire `PubSub` instance
659
666
 
660
667
  #### Splitting via predicate
661
668
 
662
- Source: [bisect()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/bisect.ts)
669
+ Docs: [bisect()](https://docs.thi.ng/umbrella/rstream/functions/bisect.html)
663
670
 
664
671
  Returns a new `PubSub` instance using given predicate `pred` as boolean
665
672
  topic function and `a` & `b` as subscribers for truthy (`a`) and falsy
@@ -704,7 +711,7 @@ fromIterable([1, 2, 3, 4]).subscribe(bisect((x) => !!(x & 1), odd, even));
704
711
 
705
712
  #### Input chunking / buffering, controlled by sidechain
706
713
 
707
- Source: [sidechainPartition()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/sidechain-partition.ts)
714
+ Docs: [sidechainPartition()](https://docs.thi.ng/umbrella/rstream/functions/sidechainPartition-1.html)
708
715
 
709
716
  ![diagram](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/rstream/rstream-sidechain-partition.png)
710
717
 
@@ -715,21 +722,25 @@ optional predicate can be used to only trigger for specific values /
715
722
  conditions.
716
723
 
717
724
  ```ts
718
- // merge various event streams
719
- merge([
720
- fromEvent(document, "mousemove"),
721
- fromEvent(document, "mousedown"),
722
- fromEvent(document, "mouseup")
723
- ])
724
- // queue event processing to only execute during the
725
- // requestAnimationFrame cycle (RAF)
726
- .subscribe(sidechainPartition(fromRAF()))
727
- .subscribe(trace());
725
+ // queue event processing to only execute during the
726
+ // requestAnimationFrame cycle (RAF)
727
+ sidechainPartition(
728
+ // merge various event streams
729
+ merge([
730
+ fromEvent(document, "mousemove"),
731
+ fromEvent(document, "mousedown"),
732
+ fromEvent(document, "mouseup")
733
+ ]),
734
+ // sidechain control stream
735
+ fromRAF()
736
+ ).subscribe(trace());
728
737
  ```
729
738
 
739
+ Since v8.0.0 there's [`syncRAF()`](https://docs.thi.ng/umbrella/rstream/functions/syncRAF-1.html)
740
+
730
741
  #### Input toggling, controlled by sidechain
731
742
 
732
- Source: [sidechainToggle()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/sidechain-toggle.ts)
743
+ Docs: [sidechainToggle()](https://docs.thi.ng/umbrella/rstream/functions/sidechainToggle-1.html)
733
744
 
734
745
  ![diagram](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/rstream/rstream-sidechain-toggle.png)
735
746
 
@@ -741,10 +752,8 @@ will be toggled on/off. Whilst switched off, no input values will be
741
752
  forwarded.
742
753
 
743
754
  ```ts
744
- // use slower interval stream to toggle main stream on/off
745
- fromInterval(500)
746
- .subscribe(sidechainToggle(fromInterval(1000)))
747
- .subscribe(trace());
755
+ // use slower interval stream to toggle faster main stream on/off
756
+ sidechainToggle(fromInterval(500), fromInterval(1000)).subscribe(trace());
748
757
  // 0
749
758
  // 3
750
759
  // 4
@@ -753,11 +762,41 @@ fromInterval(500)
753
762
  ...
754
763
  ```
755
764
 
765
+ #### Input passthrough, controlled by sidechain
766
+
767
+ Docs: [sidechainTrigger()](https://docs.thi.ng/umbrella/rstream/functions/sidechainTrigger-1.html)
768
+
769
+ Buffers the most recent value received and only forwards it downstream whenever
770
+ a new control value is received from the sidechain.
771
+
772
+ ```ts
773
+ const src = reactive("payload");
774
+
775
+ const side = stream();
776
+
777
+ sidechainTrigger(src, side).subscribe(trace("data:"));
778
+
779
+ side.next(1);
780
+ // data: payload
781
+
782
+ // every time sidechain triggers
783
+ side.next(1);
784
+ // data: payload
785
+
786
+ // only newest value will be buffered
787
+ src.next("update #1");
788
+ src.next("update #2");
789
+
790
+ // ...until side chain triggers again
791
+ side.next(1);
792
+ // data: update #2
793
+ ```
794
+
756
795
  ### Worker support
757
796
 
758
797
  #### Parallel stream processing via workers
759
798
 
760
- Source: [forkJoin()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/forkjoin.ts)
799
+ Docs: [forkJoin()](https://docs.thi.ng/umbrella/rstream/functions/forkJoin.html)
761
800
 
762
801
  ![diagram](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/rstream/rstream-forkjoin.png)
763
802
 
@@ -806,27 +845,27 @@ src.next(new Array(16).fill(1));
806
845
 
807
846
  #### Stream processing via workers
808
847
 
809
- Source: [tunnel()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/tunnel.ts)
848
+ Docs: [tunnel()](https://docs.thi.ng/umbrella/rstream/functions/tunnel-1.html)
810
849
 
811
850
  Delegate stream value processing to workers and pass on their responses
812
851
  to downstream subscriptions. Supports multiple worker instances and
813
852
  worker termination / restart for each new stream value received.
814
853
 
815
- Source: [postWorker()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/post-worker.ts)
854
+ Docs: [postWorker()](https://docs.thi.ng/umbrella/rstream/functions/postWorker.html)
816
855
 
817
856
  Send values to workers (incl. optional (inline) worker instantiation)
818
857
 
819
- Source: [fromWorker()](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/worker.ts)
858
+ Docs: [fromWorker()](https://docs.thi.ng/umbrella/rstream/functions/fromWorker.html)
820
859
 
821
860
  Create value stream from worker messages.
822
861
 
823
862
  ### Other subscription ops
824
863
 
825
- - [debounce](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/debounce.ts) - ignore high frequency interim values
826
- - [resolve](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/resolve.ts) - resolve on-stream promises
827
- - [trace](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/trace.ts) - debug helper
828
- - [transduce](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/transduce.ts) - transduce or just reduce an entire stream into a promise
829
- - [tween](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream/src/tween.ts) - stream interpolation
864
+ - [debounce](https://docs.thi.ng/umbrella/rstream/functions/debounce.html): ignore high frequency interim values
865
+ - [resolve](https://docs.thi.ng/umbrella/rstream/functions/resolve.html): resolve on-stream promises
866
+ - [trace](https://docs.thi.ng/umbrella/rstream/functions/trace.html): debug helper
867
+ - [transduce](https://docs.thi.ng/umbrella/rstream/functions/transduce.html): transduce or just reduce an entire stream into a promise
868
+ - [tween](https://docs.thi.ng/umbrella/rstream/functions/tween.html): stream interpolation
830
869
 
831
870
  ### Error handling
832
871
 
package/index.d.ts CHANGED
@@ -23,9 +23,11 @@ export * from "./raf.js";
23
23
  export * from "./resolve.js";
24
24
  export * from "./sidechain-partition.js";
25
25
  export * from "./sidechain-toggle.js";
26
+ export * from "./sidechain-trigger.js";
26
27
  export * from "./stream.js";
27
28
  export * from "./subscription.js";
28
29
  export * from "./sync.js";
30
+ export * from "./sync-raf.js";
29
31
  export * from "./timeout.js";
30
32
  export * from "./trace.js";
31
33
  export * from "./transduce.js";
package/index.js CHANGED
@@ -23,9 +23,11 @@ export * from "./raf.js";
23
23
  export * from "./resolve.js";
24
24
  export * from "./sidechain-partition.js";
25
25
  export * from "./sidechain-toggle.js";
26
+ export * from "./sidechain-trigger.js";
26
27
  export * from "./stream.js";
27
28
  export * from "./subscription.js";
28
29
  export * from "./sync.js";
30
+ export * from "./sync-raf.js";
29
31
  export * from "./timeout.js";
30
32
  export * from "./trace.js";
31
33
  export * from "./transduce.js";
package/iterable.d.ts CHANGED
@@ -26,10 +26,10 @@ export interface FromIterableOpts extends CommonOpts {
26
26
  export declare const fromIterable: <T>(src: Iterable<T>, opts?: Partial<FromIterableOpts>) => import("./stream.js").Stream<T>;
27
27
  /**
28
28
  * Creates a new {@link Stream} of given iterable which synchronously calls
29
- * `.next()` for each item of the iterable when the first (and in this
30
- * case the only one) subscriber becomes available. Once the iterable is
31
- * exhausted (MUST be finite!), then calls `.done()` by default, but can
32
- * be avoided by passing `false` as last argument.
29
+ * {@link ISubscriber.next} for each item of the iterable when the first (and in
30
+ * this case the only one) subscriber becomes available. Once the iterable is
31
+ * exhausted (MUST be finite!), then calls {@link ISubscriber.done} by default,
32
+ * but can be avoided by passing `false` as last argument.
33
33
  *
34
34
  * @param src -
35
35
  * @param opts -
package/iterable.js CHANGED
@@ -32,10 +32,10 @@ export const fromIterable = (src, opts = {}) => stream((stream) => {
32
32
  }, __optsWithID("iterable", opts));
33
33
  /**
34
34
  * Creates a new {@link Stream} of given iterable which synchronously calls
35
- * `.next()` for each item of the iterable when the first (and in this
36
- * case the only one) subscriber becomes available. Once the iterable is
37
- * exhausted (MUST be finite!), then calls `.done()` by default, but can
38
- * be avoided by passing `false` as last argument.
35
+ * {@link ISubscriber.next} for each item of the iterable when the first (and in
36
+ * this case the only one) subscriber becomes available. Once the iterable is
37
+ * exhausted (MUST be finite!), then calls {@link ISubscriber.done} by default,
38
+ * but can be avoided by passing `false` as last argument.
39
39
  *
40
40
  * @param src -
41
41
  * @param opts -
package/object.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import type { Keys, Predicate2 } from "@thi.ng/api";
2
- import type { CommonOpts } from "./api.js";
3
- import { type Subscription } from "./subscription.js";
2
+ import type { CommonOpts, ISubscription } from "./api.js";
4
3
  export type KeyStreams<T, K extends Keys<T>> = {
5
- [id in K]-?: Subscription<T[id], T[id]>;
4
+ [id in K]-?: ISubscription<T[id], T[id]>;
6
5
  };
7
6
  /**
8
7
  * Result object type for {@link fromObject}.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/rstream",
3
- "version": "7.2.46",
3
+ "version": "8.0.1",
4
4
  "description": "Reactive streams & subscription primitives for constructing dataflow graphs / pipelines",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -38,22 +38,22 @@
38
38
  "test": "testament test"
39
39
  },
40
40
  "dependencies": {
41
- "@thi.ng/api": "^8.7.5",
42
- "@thi.ng/arrays": "^2.5.9",
43
- "@thi.ng/associative": "^6.2.33",
44
- "@thi.ng/atom": "^5.1.34",
45
- "@thi.ng/checks": "^3.3.11",
46
- "@thi.ng/errors": "^2.2.14",
47
- "@thi.ng/logger": "^1.4.12",
48
- "@thi.ng/transducers": "^8.4.1"
41
+ "@thi.ng/api": "^8.8.0",
42
+ "@thi.ng/arrays": "^2.5.11",
43
+ "@thi.ng/associative": "^6.2.35",
44
+ "@thi.ng/atom": "^5.2.1",
45
+ "@thi.ng/checks": "^3.3.12",
46
+ "@thi.ng/errors": "^2.2.15",
47
+ "@thi.ng/logger": "^1.4.13",
48
+ "@thi.ng/transducers": "^8.4.3"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@microsoft/api-extractor": "^7.34.4",
52
- "@thi.ng/testament": "^0.3.14",
52
+ "@thi.ng/testament": "^0.3.15",
53
53
  "rimraf": "^4.4.1",
54
54
  "tools": "^0.0.1",
55
55
  "typedoc": "^0.23.28",
56
- "typescript": "^5.0.2"
56
+ "typescript": "^5.0.4"
57
57
  },
58
58
  "keywords": [
59
59
  "async",
@@ -162,12 +162,18 @@
162
162
  "./sidechain-toggle": {
163
163
  "default": "./sidechain-toggle.js"
164
164
  },
165
+ "./sidechain-trigger": {
166
+ "default": "./sidechain-trigger.js"
167
+ },
165
168
  "./stream": {
166
169
  "default": "./stream.js"
167
170
  },
168
171
  "./subscription": {
169
172
  "default": "./subscription.js"
170
173
  },
174
+ "./sync-raf": {
175
+ "default": "./sync-raf.js"
176
+ },
171
177
  "./sync": {
172
178
  "default": "./sync.js"
173
179
  },
@@ -205,5 +211,5 @@
205
211
  ],
206
212
  "year": 2017
207
213
  },
208
- "gitHead": "83b15b34326d480cbca0472b20390d4d3bbb792a\n"
214
+ "gitHead": "3a56bc490f1e68754762a503d06327b5b34ff7eb\n"
209
215
  }
package/raf.d.ts CHANGED
@@ -1,15 +1,26 @@
1
1
  import type { CommonOpts } from "./api.js";
2
+ export interface FromRAFOpts extends CommonOpts {
3
+ /**
4
+ * Browser only. If true (default: false), passes the timestamps received
5
+ * via `requestAnimationFrame()` as stream values. If false, a simple
6
+ * counter [0..∞) will be emitted.
7
+ *
8
+ * @defaultValue false
9
+ */
10
+ timestamp: boolean;
11
+ }
2
12
  /**
3
- * Yields {@link Stream} of a monotonically increasing counter,
4
- * triggered by a `requestAnimationFrame()` loop (only available in
5
- * browser environments).
13
+ * Yields {@link Stream} of a monotonically increasing counter (or timestamps),
14
+ * triggered by a `requestAnimationFrame()` loop (only available in browser
15
+ * environments).
6
16
  *
7
17
  * @remarks
8
- * In NodeJS, this function falls back to {@link fromInterval}, yielding
9
- * a similar (approx. 60Hz) stream.
18
+ * In NodeJS, this function falls back to {@link fromInterval}, yielding a
19
+ * similar (approx. 60Hz) stream (the {@link FromRAFOpts.timestamp} option will
20
+ * be ignored).
10
21
  *
11
- * All subscribers to this stream will be processed during that same
12
- * loop iteration.
22
+ * All subscribers to this stream will be processed during that same RAF loop
23
+ * iteration.
13
24
  */
14
- export declare const fromRAF: (opts?: Partial<CommonOpts>) => import("./stream.js").Stream<number>;
25
+ export declare const fromRAF: (opts?: Partial<FromRAFOpts>) => import("./stream.js").Stream<number>;
15
26
  //# sourceMappingURL=raf.d.ts.map
package/raf.js CHANGED
@@ -3,24 +3,25 @@ import { __optsWithID } from "./idgen.js";
3
3
  import { fromInterval } from "./interval.js";
4
4
  import { stream } from "./stream.js";
5
5
  /**
6
- * Yields {@link Stream} of a monotonically increasing counter,
7
- * triggered by a `requestAnimationFrame()` loop (only available in
8
- * browser environments).
6
+ * Yields {@link Stream} of a monotonically increasing counter (or timestamps),
7
+ * triggered by a `requestAnimationFrame()` loop (only available in browser
8
+ * environments).
9
9
  *
10
10
  * @remarks
11
- * In NodeJS, this function falls back to {@link fromInterval}, yielding
12
- * a similar (approx. 60Hz) stream.
11
+ * In NodeJS, this function falls back to {@link fromInterval}, yielding a
12
+ * similar (approx. 60Hz) stream (the {@link FromRAFOpts.timestamp} option will
13
+ * be ignored).
13
14
  *
14
- * All subscribers to this stream will be processed during that same
15
- * loop iteration.
15
+ * All subscribers to this stream will be processed during that same RAF loop
16
+ * iteration.
16
17
  */
17
- export const fromRAF = (opts) => isNode()
18
+ export const fromRAF = (opts = {}) => isNode()
18
19
  ? fromInterval(16, opts)
19
20
  : stream((stream) => {
20
21
  let i = 0;
21
22
  let isActive = true;
22
- const loop = () => {
23
- isActive && stream.next(i++);
23
+ const loop = (time) => {
24
+ isActive && stream.next(opts.timestamp ? time : i++);
24
25
  isActive && (id = requestAnimationFrame(loop));
25
26
  };
26
27
  let id = requestAnimationFrame(loop);
@@ -1,19 +1,20 @@
1
1
  import type { Predicate } from "@thi.ng/api";
2
- import { type CommonOpts, type ISubscribable } from "./api.js";
2
+ import { type CommonOpts, type ISubscribable, type ISubscription } from "./api.js";
3
3
  import { ASidechain } from "./asidechain.js";
4
- import type { Subscription } from "./subscription.js";
5
4
  export interface SidechainPartitionOpts<T> extends CommonOpts {
6
5
  pred: Predicate<T>;
7
6
  }
8
7
  /**
9
- * Returns a {@link Subscription} which buffers values from `src` until
10
- * side chain fires, then emits buffer (unless empty) and repeats
11
- * process until either input is done.
8
+ * Returns a subscription which buffers values from `src` until side chain
9
+ * delivers its next value, then emits buffer (unless empty) and repeats process
10
+ * until either input is done.
12
11
  *
13
12
  * @remarks
14
- * By default, the values read from the side chain are ignored (i.e.
15
- * only their timing is used), however the `pred`icate option can be
16
- * used to only trigger for specific values / conditions.
13
+ * By default, the values read from the side chain are ignored (i.e. only their
14
+ * timing is used), however the `pred`icate option can be used to only trigger
15
+ * for specific values / conditions.
16
+ *
17
+ * Also see: {@link sidechainToggle}, {@link sidechainTrigger}, {@link syncRAF}.
17
18
  *
18
19
  * @example
19
20
  * ```t
@@ -26,23 +27,45 @@ export interface SidechainPartitionOpts<T> extends CommonOpts {
26
27
  *
27
28
  * // queue event processing to only execute during the
28
29
  * // requestAnimationFrame cycle (RAF)
29
- * events.subscribe(sidechainPartition(fromRAF())).subscribe(trace())
30
+ * sidechainPartition(events, fromRAF()).subscribe(trace())
30
31
  * ```
31
32
  *
33
+ * @param src -
32
34
  * @param side -
33
35
  * @param opts -
34
36
  */
35
- export declare const sidechainPartition: <A, B>(side: ISubscribable<B>, opts?: Partial<SidechainPartitionOpts<B>> | undefined) => Subscription<A, A[]>;
37
+ export declare const sidechainPartition: <T, S>(src: ISubscribable<T>, side: ISubscribable<S>, opts?: Partial<SidechainPartitionOpts<S>> | undefined) => ISubscription<T, T[]>;
36
38
  /**
37
- * Syntax sugar for one of most common {@link sidechainPartition} use cases, to
38
- * synchronize downstream processing w/ `requestAnimationFrame()`. The returned
39
- * subscription debounces any high frequency intra-frame input values and (if
40
- * any present), passes only most recent one downstream *during* next RAF event
41
- * processing.
39
+ * **Deprecated** syntax sugar for one of most common {@link sidechainPartition}
40
+ * use cases, to synchronize downstream processing w/ `requestAnimationFrame()`.
41
+ * Please use {@link syncRAF} instead.
42
+ *
43
+ * @remarks
44
+ * The returned subscription debounces any high frequency intra-frame input
45
+ * values and (if any present), passes only most recent one downstream during
46
+ * next RAF event processing.
47
+ *
48
+ * This example uses thi.ng/atom as state container. Also see {@link fromAtom}
49
+ * and {@link syncRAF}.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const atom = defAtom("alice");
54
+ *
55
+ * // any change to the atom will only be applied during next RAF update
56
+ * sideChainPartitionRAF(fromAtom(atom)).subscribe({
57
+ * next({ name }) { document.body.innerText = name; }
58
+ * });
59
+ *
60
+ * // trigger update
61
+ * atom.reset("bob");
62
+ * ```
42
63
  *
43
64
  * @param src -
65
+ *
66
+ * @deprecated
44
67
  */
45
- export declare const sidechainPartitionRAF: <T>(src: ISubscribable<T>) => import("./api.js").ISubscription<T[], T>;
68
+ export declare const sidechainPartitionRAF: <T>(src: ISubscribable<T>) => ISubscription<T[], T>;
46
69
  export declare class SidechainPartition<T, S> extends ASidechain<T, S, T[]> {
47
70
  buf: T[];
48
71
  constructor(side: ISubscribable<S>, opts?: Partial<SidechainPartitionOpts<S>>);
@@ -1,18 +1,20 @@
1
1
  import { peek } from "@thi.ng/arrays/peek";
2
2
  import { map } from "@thi.ng/transducers/map";
3
- import { State } from "./api.js";
3
+ import { State, } from "./api.js";
4
4
  import { ASidechain } from "./asidechain.js";
5
5
  import { __optsWithID } from "./idgen.js";
6
6
  import { fromRAF } from "./raf.js";
7
7
  /**
8
- * Returns a {@link Subscription} which buffers values from `src` until
9
- * side chain fires, then emits buffer (unless empty) and repeats
10
- * process until either input is done.
8
+ * Returns a subscription which buffers values from `src` until side chain
9
+ * delivers its next value, then emits buffer (unless empty) and repeats process
10
+ * until either input is done.
11
11
  *
12
12
  * @remarks
13
- * By default, the values read from the side chain are ignored (i.e.
14
- * only their timing is used), however the `pred`icate option can be
15
- * used to only trigger for specific values / conditions.
13
+ * By default, the values read from the side chain are ignored (i.e. only their
14
+ * timing is used), however the `pred`icate option can be used to only trigger
15
+ * for specific values / conditions.
16
+ *
17
+ * Also see: {@link sidechainToggle}, {@link sidechainTrigger}, {@link syncRAF}.
16
18
  *
17
19
  * @example
18
20
  * ```t
@@ -25,45 +27,64 @@ import { fromRAF } from "./raf.js";
25
27
  *
26
28
  * // queue event processing to only execute during the
27
29
  * // requestAnimationFrame cycle (RAF)
28
- * events.subscribe(sidechainPartition(fromRAF())).subscribe(trace())
30
+ * sidechainPartition(events, fromRAF()).subscribe(trace())
29
31
  * ```
30
32
  *
33
+ * @param src -
31
34
  * @param side -
32
35
  * @param opts -
33
36
  */
34
- export const sidechainPartition = (side, opts) => new SidechainPartition(side, opts);
37
+ export const sidechainPartition = (src, side, opts) => src.subscribe(new SidechainPartition(side, opts));
35
38
  /**
36
- * Syntax sugar for one of most common {@link sidechainPartition} use cases, to
37
- * synchronize downstream processing w/ `requestAnimationFrame()`. The returned
38
- * subscription debounces any high frequency intra-frame input values and (if
39
- * any present), passes only most recent one downstream *during* next RAF event
40
- * processing.
39
+ * **Deprecated** syntax sugar for one of most common {@link sidechainPartition}
40
+ * use cases, to synchronize downstream processing w/ `requestAnimationFrame()`.
41
+ * Please use {@link syncRAF} instead.
42
+ *
43
+ * @remarks
44
+ * The returned subscription debounces any high frequency intra-frame input
45
+ * values and (if any present), passes only most recent one downstream during
46
+ * next RAF event processing.
47
+ *
48
+ * This example uses thi.ng/atom as state container. Also see {@link fromAtom}
49
+ * and {@link syncRAF}.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const atom = defAtom("alice");
54
+ *
55
+ * // any change to the atom will only be applied during next RAF update
56
+ * sideChainPartitionRAF(fromAtom(atom)).subscribe({
57
+ * next({ name }) { document.body.innerText = name; }
58
+ * });
59
+ *
60
+ * // trigger update
61
+ * atom.reset("bob");
62
+ * ```
41
63
  *
42
64
  * @param src -
65
+ *
66
+ * @deprecated
43
67
  */
44
- export const sidechainPartitionRAF = (src) => src
45
- .subscribe(sidechainPartition(fromRAF()))
46
- .transform(map(peek));
68
+ export const sidechainPartitionRAF = (src) => sidechainPartition(src, fromRAF()).transform(map(peek));
47
69
  export class SidechainPartition extends ASidechain {
48
70
  constructor(side, opts) {
49
71
  opts = __optsWithID("sidepart", opts);
50
72
  super(opts);
51
- this.buf = [];
52
73
  const pred = opts.pred || (() => true);
53
- const $this = this;
74
+ this.buf = [];
54
75
  this.sideSub = side.subscribe({
55
- next(x) {
56
- if ($this.buf.length && pred(x)) {
57
- $this.dispatch($this.buf);
58
- $this.buf = [];
76
+ next: (x) => {
77
+ if (this.buf.length && pred(x)) {
78
+ this.dispatch(this.buf);
79
+ this.buf = [];
59
80
  }
60
81
  },
61
- done() {
62
- if ($this.buf.length) {
63
- $this.dispatch($this.buf);
82
+ done: () => {
83
+ if (this.buf.length) {
84
+ this.dispatch(this.buf);
64
85
  }
65
- $this.done();
66
- delete $this.buf;
86
+ this.done();
87
+ delete this.buf;
67
88
  },
68
89
  });
69
90
  }
@@ -1,28 +1,25 @@
1
1
  import type { Predicate } from "@thi.ng/api";
2
- import { type CommonOpts, type ISubscribable } from "./api.js";
2
+ import { type CommonOpts, type ISubscribable, type ISubscription } from "./api.js";
3
3
  import { ASidechain } from "./asidechain.js";
4
- import type { Subscription } from "./subscription.js";
5
4
  export interface SidechainToggleOpts<T> extends CommonOpts {
6
5
  pred: Predicate<T>;
7
6
  initial: boolean;
8
7
  }
9
8
  /**
10
- * Returns {@link Subscription} which filters values from input based on
11
- * values received from side chain.
9
+ * Returns a subscription which filters values from `src` based on control
10
+ * values received from `side` chain.
12
11
  *
13
12
  * @remarks
14
- * By default, the value read from the side chain is ignored (i.e. only
15
- * their timing is used), however the `pred`icate option can be used to
16
- * only trigger for specific values/conditions. Every time the predicate
17
- * fn returns true, the filter will be toggled on/off. Whilst switched
18
- * off, no input values will be forwarded.
13
+ * By default, the values read from the side chain are ignored (i.e. only their
14
+ * timing is used), however the `pred`icate option can be used to only trigger
15
+ * for specific values/conditions. Every time the predicate fn returns true, the
16
+ * filter will be toggled on/off. Whilst switched off, no input values will be
17
+ * forwarded downstream.
19
18
  *
20
19
  * @example
21
20
  * ```ts
22
- * // use slower interval stream to toggle main stream on/off
23
- * fromInterval(500)
24
- * .subscribe(sidechainToggle(fromInterval(1000)))
25
- * .subscribe(trace());
21
+ * // use slower interval stream to toggle faster main stream on/off
22
+ * sidechainToggle(fromInterval(500), fromInterval(1000)).subscribe(trace());
26
23
  * // 0
27
24
  * // 3
28
25
  * // 4
@@ -31,10 +28,11 @@ export interface SidechainToggleOpts<T> extends CommonOpts {
31
28
  * ...
32
29
  * ```
33
30
  *
31
+ * @param src -
34
32
  * @param side -
35
33
  * @param opts -
36
34
  */
37
- export declare const sidechainToggle: <A, B>(side: ISubscribable<B>, opts?: Partial<SidechainToggleOpts<B>> | undefined) => Subscription<A, A>;
35
+ export declare const sidechainToggle: <T, S>(src: ISubscribable<T>, side: ISubscribable<S>, opts?: Partial<SidechainToggleOpts<S>> | undefined) => ISubscription<T, T>;
38
36
  export declare class SidechainToggle<T, S> extends ASidechain<T, S, T> {
39
37
  isActive: boolean;
40
38
  constructor(side: ISubscribable<S>, opts?: Partial<SidechainToggleOpts<S>>);
@@ -1,23 +1,21 @@
1
- import { State } from "./api.js";
1
+ import { State, } from "./api.js";
2
2
  import { ASidechain } from "./asidechain.js";
3
3
  import { __optsWithID } from "./idgen.js";
4
4
  /**
5
- * Returns {@link Subscription} which filters values from input based on
6
- * values received from side chain.
5
+ * Returns a subscription which filters values from `src` based on control
6
+ * values received from `side` chain.
7
7
  *
8
8
  * @remarks
9
- * By default, the value read from the side chain is ignored (i.e. only
10
- * their timing is used), however the `pred`icate option can be used to
11
- * only trigger for specific values/conditions. Every time the predicate
12
- * fn returns true, the filter will be toggled on/off. Whilst switched
13
- * off, no input values will be forwarded.
9
+ * By default, the values read from the side chain are ignored (i.e. only their
10
+ * timing is used), however the `pred`icate option can be used to only trigger
11
+ * for specific values/conditions. Every time the predicate fn returns true, the
12
+ * filter will be toggled on/off. Whilst switched off, no input values will be
13
+ * forwarded downstream.
14
14
  *
15
15
  * @example
16
16
  * ```ts
17
- * // use slower interval stream to toggle main stream on/off
18
- * fromInterval(500)
19
- * .subscribe(sidechainToggle(fromInterval(1000)))
20
- * .subscribe(trace());
17
+ * // use slower interval stream to toggle faster main stream on/off
18
+ * sidechainToggle(fromInterval(500), fromInterval(1000)).subscribe(trace());
21
19
  * // 0
22
20
  * // 3
23
21
  * // 4
@@ -26,26 +24,24 @@ import { __optsWithID } from "./idgen.js";
26
24
  * ...
27
25
  * ```
28
26
  *
27
+ * @param src -
29
28
  * @param side -
30
29
  * @param opts -
31
30
  */
32
- export const sidechainToggle = (side, opts) => new SidechainToggle(side, opts);
31
+ export const sidechainToggle = (src, side, opts) => src.subscribe(new SidechainToggle(side, opts));
33
32
  export class SidechainToggle extends ASidechain {
34
33
  constructor(side, opts) {
35
34
  opts = __optsWithID("sidetoggle", opts);
36
35
  super(opts);
37
36
  this.isActive = !!opts.initial;
38
37
  const pred = opts.pred || (() => true);
39
- const $this = this;
40
38
  this.sideSub = side.subscribe({
41
- next(x) {
39
+ next: (x) => {
42
40
  if (pred(x)) {
43
- $this.isActive = !$this.isActive;
41
+ this.isActive = !this.isActive;
44
42
  }
45
43
  },
46
- done() {
47
- $this.done();
48
- },
44
+ done: () => this.done(),
49
45
  });
50
46
  }
51
47
  next(x) {
@@ -0,0 +1,54 @@
1
+ import type { Predicate } from "@thi.ng/api";
2
+ import { SEMAPHORE } from "@thi.ng/api/api";
3
+ import { type CommonOpts, type ISubscribable, type ISubscription } from "./api.js";
4
+ import { ASidechain } from "./asidechain.js";
5
+ export interface SidechainTriggerOpts<T> extends CommonOpts {
6
+ pred: Predicate<T>;
7
+ }
8
+ /**
9
+ * Returns a subscription which buffers the most recent value received from
10
+ * `src` and only forwards it downstream whenever a new control value is
11
+ * received from the `side` chain.
12
+ *
13
+ * @remarks
14
+ * By default, the values read from the side chain are ignored (i.e. only their
15
+ * timing is used), however the `pred`icate option can be used to only trigger
16
+ * for specific values/conditions. Every time the predicate fn returns true AND
17
+ * if `src` already has delivered at least one value, it will be forwarded
18
+ * downstream.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const src = reactive("payload");
23
+ *
24
+ * const side = stream();
25
+ *
26
+ * sidechainTrigger(src, side).subscribe(trace("data:"));
27
+ *
28
+ * side.next(1);
29
+ * // data: payload
30
+ *
31
+ * side.next(1);
32
+ * // data: payload
33
+ *
34
+ * // only newest value will be buffered
35
+ * src.next("update #1");
36
+ * src.next("update #2");
37
+ *
38
+ * // ...until side chain triggers again
39
+ * side.next(1);
40
+ * // data: update #2
41
+ * ...
42
+ * ```
43
+ *
44
+ * @param src
45
+ * @param side
46
+ * @param opts
47
+ */
48
+ export declare const sidechainTrigger: <T, S>(src: ISubscribable<T>, side: ISubscribable<S>, opts?: Partial<SidechainTriggerOpts<S>> | undefined) => ISubscription<T, T>;
49
+ export declare class SidechainTrigger<T, S> extends ASidechain<T, S, T> {
50
+ buf: T | typeof SEMAPHORE;
51
+ constructor(side: ISubscribable<S>, opts?: Partial<SidechainTriggerOpts<S>>);
52
+ next(x: T): void;
53
+ }
54
+ //# sourceMappingURL=sidechain-trigger.d.ts.map
@@ -0,0 +1,66 @@
1
+ import { SEMAPHORE } from "@thi.ng/api/api";
2
+ import { State, } from "./api.js";
3
+ import { ASidechain } from "./asidechain.js";
4
+ import { __optsWithID } from "./idgen.js";
5
+ /**
6
+ * Returns a subscription which buffers the most recent value received from
7
+ * `src` and only forwards it downstream whenever a new control value is
8
+ * received from the `side` chain.
9
+ *
10
+ * @remarks
11
+ * By default, the values read from the side chain are ignored (i.e. only their
12
+ * timing is used), however the `pred`icate option can be used to only trigger
13
+ * for specific values/conditions. Every time the predicate fn returns true AND
14
+ * if `src` already has delivered at least one value, it will be forwarded
15
+ * downstream.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const src = reactive("payload");
20
+ *
21
+ * const side = stream();
22
+ *
23
+ * sidechainTrigger(src, side).subscribe(trace("data:"));
24
+ *
25
+ * side.next(1);
26
+ * // data: payload
27
+ *
28
+ * side.next(1);
29
+ * // data: payload
30
+ *
31
+ * // only newest value will be buffered
32
+ * src.next("update #1");
33
+ * src.next("update #2");
34
+ *
35
+ * // ...until side chain triggers again
36
+ * side.next(1);
37
+ * // data: update #2
38
+ * ...
39
+ * ```
40
+ *
41
+ * @param src
42
+ * @param side
43
+ * @param opts
44
+ */
45
+ export const sidechainTrigger = (src, side, opts) => src.subscribe(new SidechainTrigger(side, opts));
46
+ export class SidechainTrigger extends ASidechain {
47
+ constructor(side, opts) {
48
+ opts = __optsWithID("sidetrigger", opts);
49
+ super(opts);
50
+ this.buf = SEMAPHORE;
51
+ const pred = opts.pred || (() => true);
52
+ this.sideSub = side.subscribe({
53
+ next: (x) => {
54
+ if (this.buf !== SEMAPHORE && pred(x)) {
55
+ this.dispatch(this.buf);
56
+ }
57
+ },
58
+ done: () => this.done(),
59
+ });
60
+ }
61
+ next(x) {
62
+ if (this.state < State.DONE) {
63
+ this.buf = x;
64
+ }
65
+ }
66
+ }
package/sync-raf.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ /// <reference types="node" />
2
+ import { type CommonOpts, type ISubscribable } from "./api.js";
3
+ import { Subscription } from "./subscription.js";
4
+ /**
5
+ * Similar to (in in effect the same as the **now deprecated**)
6
+ * {@link sidechainPartitionRAF}, however more performant & lightweight.
7
+ * Synchronizes downstream processing w/ `requestAnimationFrame()`. The returned
8
+ * subscription delays & debounces any high frequency intra-frame input values
9
+ * and passes only most recent one downstream during next RAF event processing.
10
+ *
11
+ * This example uses thi.ng/atom as state container. Also see {@link fromAtom}.
12
+ *
13
+ * See {@link sidechainTrigger} from a similar & more general construct.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const atom = defAtom("alice");
18
+ *
19
+ * // any changes to the atom will only be received by this subscription
20
+ * // during next RAF update cycle
21
+ * syncRAF(fromAtom(atom)).subscribe({
22
+ * next({ name }) { document.body.innerText = name; }
23
+ * });
24
+ *
25
+ * // trigger update
26
+ * atom.reset("bob");
27
+ * ```
28
+ *
29
+ * @param src -
30
+ * @param opts -
31
+ */
32
+ export declare const syncRAF: <T>(src: ISubscribable<T>, opts?: Partial<CommonOpts>) => import("./api.js").ISubscription<T, T>;
33
+ /**
34
+ * See {@link syncRAF} for details.
35
+ */
36
+ export declare class SyncRAF<T> extends Subscription<T, T> {
37
+ queued?: T;
38
+ raf?: number | NodeJS.Timeout;
39
+ constructor(opts?: Partial<CommonOpts>);
40
+ next(x: T): void;
41
+ done(): void;
42
+ error(e: any): boolean;
43
+ protected _clean(): void;
44
+ }
45
+ //# sourceMappingURL=sync-raf.d.ts.map
package/sync-raf.js ADDED
@@ -0,0 +1,72 @@
1
+ import { isNode } from "@thi.ng/checks/is-node";
2
+ import { State } from "./api.js";
3
+ import { __optsWithID } from "./idgen.js";
4
+ import { Subscription } from "./subscription.js";
5
+ /**
6
+ * Similar to (in in effect the same as the **now deprecated**)
7
+ * {@link sidechainPartitionRAF}, however more performant & lightweight.
8
+ * Synchronizes downstream processing w/ `requestAnimationFrame()`. The returned
9
+ * subscription delays & debounces any high frequency intra-frame input values
10
+ * and passes only most recent one downstream during next RAF event processing.
11
+ *
12
+ * This example uses thi.ng/atom as state container. Also see {@link fromAtom}.
13
+ *
14
+ * See {@link sidechainTrigger} from a similar & more general construct.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const atom = defAtom("alice");
19
+ *
20
+ * // any changes to the atom will only be received by this subscription
21
+ * // during next RAF update cycle
22
+ * syncRAF(fromAtom(atom)).subscribe({
23
+ * next({ name }) { document.body.innerText = name; }
24
+ * });
25
+ *
26
+ * // trigger update
27
+ * atom.reset("bob");
28
+ * ```
29
+ *
30
+ * @param src -
31
+ * @param opts -
32
+ */
33
+ export const syncRAF = (src, opts) => src.subscribe(new SyncRAF(__optsWithID(`syncraf-${src.id}`, opts)));
34
+ /**
35
+ * See {@link syncRAF} for details.
36
+ */
37
+ export class SyncRAF extends Subscription {
38
+ constructor(opts) {
39
+ super(undefined, opts);
40
+ }
41
+ next(x) {
42
+ if (this.state >= State.DONE)
43
+ return;
44
+ this.queued = x;
45
+ if (!this.raf) {
46
+ const update = () => {
47
+ if (this.state < State.DONE)
48
+ super.next(this.queued);
49
+ this._clean();
50
+ };
51
+ this.raf = isNode()
52
+ ? setTimeout(update, 16)
53
+ : requestAnimationFrame(update);
54
+ }
55
+ }
56
+ done() {
57
+ this._clean();
58
+ super.done();
59
+ }
60
+ error(e) {
61
+ this._clean();
62
+ return super.error(e);
63
+ }
64
+ _clean() {
65
+ if (this.raf) {
66
+ isNode()
67
+ ? clearTimeout(this.raf)
68
+ : cancelAnimationFrame(this.raf);
69
+ }
70
+ this.raf = this.queued = undefined;
71
+ }
72
+ }
package/view.d.ts CHANGED
@@ -41,7 +41,7 @@ export declare const fromViewUnsafe: <T>(atom: ReadonlyAtom<any>, opts: FromView
41
41
  /**
42
42
  * Similar to {@link fromAtom}, but creates a type checked, eager derived view
43
43
  * for a nested value in an Atom-like state container and yields stream of its
44
- * value changes.
44
+ * value changes. See {@link fromViewUnsafe} for unchecked version.
45
45
  *
46
46
  * @remarks
47
47
  * Stream value type is inferred from target path or (if given), the result type
package/view.js CHANGED
@@ -43,5 +43,5 @@ export function fromView(atom, opts) {
43
43
  isActive = false;
44
44
  view.release();
45
45
  };
46
- });
46
+ }, opts);
47
47
  }