@wardic/core 1.0.0-rc.4 → 1.0.0-rc.5

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.
Files changed (45) hide show
  1. package/dist/Clock.d.ts.map +1 -1
  2. package/dist/Clock.js +20 -12
  3. package/dist/Clock.js.map +1 -1
  4. package/dist/FrameLoop.d.ts +12 -1
  5. package/dist/FrameLoop.d.ts.map +1 -1
  6. package/dist/FrameLoop.js +23 -1
  7. package/dist/FrameLoop.js.map +1 -1
  8. package/dist/LiveValue.d.ts +2 -2
  9. package/dist/LiveValue.d.ts.map +1 -1
  10. package/dist/LiveValue.js +5 -4
  11. package/dist/LiveValue.js.map +1 -1
  12. package/dist/Probe.d.ts +4 -46
  13. package/dist/Probe.d.ts.map +1 -1
  14. package/dist/Probe.js +5 -5
  15. package/dist/Probe.js.map +1 -1
  16. package/dist/ScrollSource.d.ts +62 -0
  17. package/dist/ScrollSource.d.ts.map +1 -0
  18. package/dist/ScrollSource.js +21 -0
  19. package/dist/ScrollSource.js.map +1 -0
  20. package/dist/SharedSource.d.ts +35 -15
  21. package/dist/SharedSource.d.ts.map +1 -1
  22. package/dist/SharedSource.js +84 -108
  23. package/dist/SharedSource.js.map +1 -1
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/internal/frameLoop.d.ts +17 -0
  29. package/dist/internal/frameLoop.d.ts.map +1 -1
  30. package/dist/internal/frameLoop.js +33 -20
  31. package/dist/internal/frameLoop.js.map +1 -1
  32. package/dist/internal/hearing.d.ts +13 -0
  33. package/dist/internal/hearing.d.ts.map +1 -0
  34. package/dist/internal/hearing.js +71 -0
  35. package/dist/internal/hearing.js.map +1 -0
  36. package/package.json +1 -1
  37. package/src/Clock.ts +29 -17
  38. package/src/FrameLoop.ts +24 -1
  39. package/src/LiveValue.ts +7 -6
  40. package/src/Probe.ts +7 -53
  41. package/src/ScrollSource.ts +68 -0
  42. package/src/SharedSource.ts +113 -146
  43. package/src/index.ts +2 -1
  44. package/src/internal/frameLoop.ts +41 -18
  45. package/src/internal/hearing.ts +76 -0
@@ -1,34 +1,54 @@
1
- import type * as Duration from "effect/Duration";
1
+ /**
2
+ * Shared sources, for the Streams an Environment hands out: each hot and counted, so however many
3
+ * subscribe, one underlying source runs, started by the first subscriber and stopped when the last one
4
+ * leaves. `byTarget` keeps one per target, one observer on each element, and `make` one for the whole
5
+ * Environment. An Environment builds its sources with these, as `@wardic/dom` does, and `counted` shares
6
+ * anything else it opens per target.
7
+ *
8
+ * @example
9
+ * import * as SharedSource from "@wardic/core/SharedSource"
10
+ *
11
+ * const resize = yield* SharedSource.byTarget((target) => Effect.succeed(resizesOf(target)))
12
+ * // Both share one observer on `card`:
13
+ * Stream.runForEach(resize(card), onLayout)
14
+ * Stream.runForEach(resize(card), onScroll)
15
+ */
2
16
  import * as Effect from "effect/Effect";
3
- import type * as Scope from "effect/Scope";
17
+ import * as Scope from "effect/Scope";
4
18
  import * as Stream from "effect/Stream";
5
- /** `byTarget`'s and `make`'s options. */
6
- export interface Options {
7
- /**
8
- * How long a source with no subscriber left keeps running before it stops, so a quick re-subscribe
9
- * reuses it. Default: none, stopped at once.
10
- */
11
- readonly idleTimeToLive?: Duration.Input | undefined;
12
- }
19
+ /**
20
+ * Values shared by key and counted: the first hold of a key opens its value with `open`, later holds
21
+ * share it, and the last one's release closes it with `close`. A key is held by identity and never
22
+ * hashed, so a DOM node is its own key. `open` runs inline, so it mustn't wait.
23
+ *
24
+ * @example
25
+ * // One listener set per container, however many readers hold it
26
+ * const containers = SharedSource.counted(
27
+ * (container: Element) => ({ remove: listenTo(container) }),
28
+ * (listening) => Effect.sync(listening.remove),
29
+ * )
30
+ * const listening = yield* containers(list) // held until the current Scope closes
31
+ */
32
+ export declare const counted: <K, V>(open: (key: K) => V, close: (value: V) => Effect.Effect<void>) => ((key: K) => Effect.Effect<V, never, Scope.Scope>);
13
33
  /**
14
34
  * A shared source per target: a function from a target to a Stream that's hot and counted for that
15
35
  * target. The first subscriber for a target starts `lookup(target)`'s source, later ones share it, and it
16
- * stops when the last one for that target leaves, after `idleTimeToLive` if it's given.
36
+ * stops when the last one for that target leaves.
17
37
  *
18
38
  * @example
19
39
  * // `resizesOf(target)`: an Environment's own Stream of a target's sizes
20
40
  * const resize = yield* SharedSource.byTarget((target) => Effect.succeed(resizesOf(target)))
21
41
  */
22
- export declare const byTarget: <A>(lookup: (target: unknown) => Effect.Effect<Stream.Stream<A>, never, Scope.Scope>, options?: Options) => Effect.Effect<(target: unknown) => Stream.Stream<A>, never, Scope.Scope>;
42
+ export declare const byTarget: <A>(lookup: (target: unknown) => Effect.Effect<Stream.Stream<A>, never, Scope.Scope>) => Effect.Effect<(target: unknown) => Stream.Stream<A>, never, Scope.Scope>;
23
43
  /**
24
44
  * One shared source for the whole Environment: a Stream that's hot and counted. The first subscriber
25
- * starts `acquire`'s source, later ones share it, and it stops when the last one leaves, after
26
- * `idleTimeToLive` if it's given. `byTarget`'s form without a target.
45
+ * starts `acquire`'s source, later ones share it, and it stops when the last one leaves. `byTarget`'s
46
+ * form without a target.
27
47
  *
28
48
  * @example
29
49
  * // `viewportChanges`: an Environment's own Stream of its viewport's size
30
50
  * const viewport = yield* SharedSource.make(Effect.succeed(viewportChanges))
31
51
  * Stream.runForEach(viewport, onResize) // one listener, however many subscribe
32
52
  */
33
- export declare const make: <A>(acquire: Effect.Effect<Stream.Stream<A>, never, Scope.Scope>, options?: Options) => Effect.Effect<Stream.Stream<A>, never, Scope.Scope>;
53
+ export declare const make: <A>(acquire: Effect.Effect<Stream.Stream<A>, never, Scope.Scope>) => Effect.Effect<Stream.Stream<A>, never, Scope.Scope>;
34
54
  //# sourceMappingURL=SharedSource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SharedSource.d.ts","sourceRoot":"","sources":["../src/SharedSource.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAYvC,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAIvC,yCAAyC;AACzC,MAAM,WAAW,OAAO;IACtB;;;OAGG;IAEH,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAA;CACrD;AAoFD;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,EACvB,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAChF,OAAO,CAAC,EAAE,OAAO,KACd,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CA+BxE,CAAA;AAEJ;;;;;;;;;GASG;AAEH,eAAO,MAAM,IAAI,EAAE,CAAC,CAAC,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAC5D,OAAO,CAAC,EAAE,OAAO,KACd,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAgBnD,CAAA"}
1
+ {"version":3,"file":"SharedSource.d.ts","sourceRoot":"","sources":["../src/SharedSource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAKvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAUvC;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,CAAC,QACpB,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,SACZ,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KACvC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAoBnD,CAAA;AAwDD;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,EACvB,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAC7E,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAUxE,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,EAAE,CAAC,CAAC,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KACzD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CASnD,CAAA"}
@@ -2,7 +2,8 @@
2
2
  * Shared sources, for the Streams an Environment hands out: each hot and counted, so however many
3
3
  * subscribe, one underlying source runs, started by the first subscriber and stopped when the last one
4
4
  * leaves. `byTarget` keeps one per target, one observer on each element, and `make` one for the whole
5
- * Environment. An Environment builds its sources with these, as `@wardic/dom` does.
5
+ * Environment. An Environment builds its sources with these, as `@wardic/dom` does, and `counted` shares
6
+ * anything else it opens per target.
6
7
  *
7
8
  * @example
8
9
  * import * as SharedSource from "@wardic/core/SharedSource"
@@ -13,146 +14,121 @@
13
14
  * Stream.runForEach(resize(card), onScroll)
14
15
  */
15
16
  // CONTEXT.md's **Shared source** contract (#37, ADR-0041 *Amendment (#37)*). An Environment's **Input
16
- // feeds** are shared by `InputFeed.byTarget` instead, with no `PubSub` or fiber (#318).
17
+ // feeds** are shared by `InputFeed.byTarget` instead, with no fiber (#318).
17
18
  //
18
- // Two constructors, both built on the same primitive (a `PubSub` fed by a `forkScoped` pump that drains
19
- // the cold source), wrapped in Effect's reference-counted resource caches: `byTarget` keys on the target
20
- // (`RcMap`), the cold `lookup` running once per target while a subscriber holds it (an Environment's
21
- // `Probe.observeResize`); `make` is the keyless case (`RcRef`). The cold source is acquired by the first
22
- // subscriber and released when the last subscriber's scope closes: `Stream.unwrap` holds the Rc reference
23
- // for the subscriber stream's lifetime, so when the last one ends the cache releases the entry, the pump
24
- // is interrupted, and the cold source's finalizers run (a listener is removed). The source's end ends
25
- // every subscriber, and its failure fails them (#618, decision 6). Effect's own `Stream.share` and
26
- // `Stream.broadcast` do this too, but put 2.2 KB gzip on every app (`bun run size`), so the pump stays.
19
+ // One shape under both constructors (#518, ADR-0067 *Amendment (#518)*, decision 3): a target's entry in
20
+ // a `counted` map holds its subscribers' hearings and, while any subscriber holds it, a pump that runs the
21
+ // cold source and hands each element to every hearing, which resumes a waiting subscriber inside the
22
+ // call, as the `PubSub` did. The first subscriber opens the entry and starts the pump; the
23
+ // last one's release interrupts it, and the cold source's finalizers run (a listener is removed). The
24
+ // source's end ends every subscriber, and its failure fails them (#618, decision 6). It replaced a
25
+ // `PubSub` per source in Effect's `RcMap` and `RcRef`, whose code every app shipped (4.1 KB gzipped with
26
+ // `Clock.ticks`' and the DOM's scroll containers'), and whose `idleTimeToLive` nothing passed.
27
27
  //
28
28
  // Tier 2 (ADR-0008), for Environment authors, as `InputSource.heldPointer` is (#31's rule: Wardic ships
29
29
  // what makes a new Environment little work). Observability: each constructor emits a
30
- // `wardic.sharedSource.*` span and a debug log on subscribe; the per-event publish path stays quiet.
31
- import * as Cause from "effect/Cause";
30
+ // `wardic.sharedSource.*` span and a debug log on subscribe; the per-event path stays quiet.
32
31
  import * as Effect from "effect/Effect";
33
- import * as Equal from "effect/Equal";
34
32
  import * as Exit from "effect/Exit";
35
- import { identity } from "effect/Function";
36
- import * as Hash from "effect/Hash";
37
- import * as Match from "effect/Match";
38
- import * as MutableRef from "effect/MutableRef";
33
+ import * as Fiber from "effect/Fiber";
34
+ import * as Iter from "effect/Iterable";
39
35
  import * as Option from "effect/Option";
40
- import * as Predicate from "effect/Predicate";
41
- import * as PubSub from "effect/PubSub";
42
- import * as RcMap from "effect/RcMap";
43
- import * as RcRef from "effect/RcRef";
36
+ import * as Scope from "effect/Scope";
44
37
  import * as Stream from "effect/Stream";
45
- import * as UndefinedOr from "effect/UndefinedOr";
38
+ import * as Hearing from "./internal/hearing.js";
46
39
  import { tracedStream } from "./internal/tracing.js";
47
40
  /**
48
- * The hot `PubSub` that fronts a cold source: acquire the source via `acquire`, fork a scoped pump
49
- * that republishes every element into the PubSub, and hand back the PubSub. The pump is bound to
50
- * the Rc cache entry's scope, so when the cache releases the entry the pump is interrupted and the
51
- * cold source's finalizers run. When the source ends, how it ended is kept and the PubSub shut down,
52
- * which ends every subscription. Per-element publishing is un-logged: it's the hot path.
41
+ * Values shared by key and counted: the first hold of a key opens its value with `open`, later holds
42
+ * share it, and the last one's release closes it with `close`. A key is held by identity and never
43
+ * hashed, so a DOM node is its own key. `open` runs inline, so it mustn't wait.
44
+ *
45
+ * @example
46
+ * // One listener set per container, however many readers hold it
47
+ * const containers = SharedSource.counted(
48
+ * (container: Element) => ({ remove: listenTo(container) }),
49
+ * (listening) => Effect.sync(listening.remove),
50
+ * )
51
+ * const listening = yield* containers(list) // held until the current Scope closes
53
52
  */
54
- const fanIn = /*#__PURE__*/ Effect.fnUntraced(function* (acquire) {
55
- const pubsub = yield* PubSub.unbounded();
56
- const source = yield* acquire;
57
- const ended = MutableRef.make(Option.none());
58
- yield* Effect.forkScoped(Stream.runForEach(source, (a) => PubSub.publish(pubsub, a)).pipe(Effect.onExit((exit) => Effect.andThen(Effect.sync(() => MutableRef.set(ended, Option.some(exit))), PubSub.shutdown(pubsub)))));
59
- return { pubsub, ended };
60
- });
61
- /** A source's failure, if it failed: an interruption is how its cache ends it, not a failure. */
62
- const failureOf = (exit) => {
63
- if (Exit.isSuccess(exit))
64
- return Option.none();
65
- if (Cause.hasInterruptsOnly(exit.cause))
66
- return Option.none();
67
- return Option.some(exit.cause);
53
+ // #518: what `RcMap` gave the DOM's scroll containers (#618, M7), with no Scope per entry and no `Hash`.
54
+ export const counted = (open, close) => {
55
+ const held = new Map();
56
+ const acquire = (key) => Effect.sync(() => {
57
+ const entry = Option.getOrElse(Option.fromUndefinedOr(held.get(key)), () => {
58
+ const opened = { value: open(key), count: 0 };
59
+ held.set(key, opened);
60
+ return opened;
61
+ });
62
+ entry.count++;
63
+ return entry;
64
+ });
65
+ const release = (key, entry) => Effect.suspend(() => {
66
+ entry.count--;
67
+ if (entry.count > 0)
68
+ return Effect.void;
69
+ if (held.get(key) === entry)
70
+ held.delete(key);
71
+ return close(entry.value);
72
+ });
73
+ return (key) => Effect.map(Effect.acquireRelease(acquire(key), (entry) => release(key, entry)), (entry) => entry.value);
68
74
  };
69
- /** How a subscriber ends after its source has: failed with the source's failure, else at once. */
70
- const endOf = (ended) => Option.match(Option.flatMap(ended, failureOf), { onNone: () => Effect.void, onSome: (cause) => Effect.failCause(cause) });
71
- /**
72
- * A subscriber to a fanned-out source, made as it subscribes: its events, then the source's end. One that
73
- * subscribes after the end gets the end alone.
74
- */
75
- const subscriberOf = ({ pubsub, ended }) => Stream.onEnd(Option.match(MutableRef.get(ended), { onNone: () => Stream.fromPubSub(pubsub), onSome: () => Stream.empty }), Effect.suspend(() => endOf(MutableRef.get(ended))));
75
+ /** A fresh source's entry, with no subscriber, no pump and no end. */
76
+ const fanned = () => ({ hearings: new Set(), pump: Option.none(), ended: Option.none() });
77
+ /** The pump: `acquire`'s source, each element to every subscriber; its end, kept and handed to each. */
78
+ const pumpOf = (entry, acquire) => Effect.scoped(Effect.flatMap(acquire, (source) => Stream.runForEach(source, (a) => Effect.sync(() => Iter.forEach(entry.hearings, (hearing) => hearing.hear(a)))))).pipe(Effect.onExit((exit) => Effect.sync(() => {
79
+ entry.ended = Option.some(exit);
80
+ Iter.forEach(entry.hearings, (hearing) => hearing.end(exit));
81
+ })));
82
+ /** An entry's pump stopped, its last subscriber gone. */
83
+ const stop = (entry) => Option.match(entry.pump, { onNone: () => Effect.void, onSome: (pump) => Effect.asVoid(Fiber.interrupt(pump)) });
76
84
  /**
77
- * An identity key for `RcMap`. `RcMap` hashes its keys with Effect's structural `Hash`, which
78
- * walks a target's properties: on a platform object that can throw (a DOM node's function
79
- * properties touch `.caller` in strict mode), and it would conflate two structurally equal but
80
- * distinct targets. This wrapper is equal by reference, with a stable per-instance hash, so `RcMap`
81
- * never inspects the target and each distinct target is its own entry. One wrapper is cached per
82
- * target (the `WeakMap` in {@link byTarget}).
85
+ * A subscriber to `key`'s shared source: its hearing on the entry while its Stream runs, the pump started
86
+ * for the first, in `scope`, the shared source's. One that subscribes after the source ended gets the end
87
+ * alone.
83
88
  */
84
- // Module state (#460, Q7): an id counter, only ever compared for distinctness, so every runtime may share it.
85
- let nextTargetHash = 1;
86
- class TargetKey {
87
- target;
88
- hash;
89
- constructor(target) {
90
- this.target = target;
91
- this.hash = nextTargetHash++;
92
- }
93
- [Hash.symbol]() {
94
- return this.hash;
95
- }
96
- [Equal.symbol](that) {
97
- return this === that;
89
+ const subscriberOf = (hold, key, acquire, scope) => Stream.unwrap(Effect.gen(function* () {
90
+ const entry = yield* hold(key);
91
+ const hearing = Hearing.make();
92
+ if (Option.isSome(entry.ended)) {
93
+ hearing.end(entry.ended.value);
94
+ return hearing.stream;
98
95
  }
99
- }
100
- /** The target a key addresses: a {@link TargetKey}'s own, else the key itself (a non-object target). */
101
- const targetOf = /*#__PURE__*/ Match.type().pipe(Match.when(Match.instanceOf(TargetKey), (key) => key.target), Match.orElse(identity));
102
- /** The cache's `idleTimeToLive`, when the options give one. */
103
- const idleOf = (options = {}) => UndefinedOr.match(options.idleTimeToLive, { onUndefined: () => ({}), onDefined: (idleTimeToLive) => ({ idleTimeToLive }) });
96
+ // Its hearing first, so what the pump hands on as it starts reaches it.
97
+ entry.hearings.add(hearing);
98
+ yield* Effect.addFinalizer(() => Effect.sync(() => entry.hearings.delete(hearing)));
99
+ if (Option.isNone(entry.pump))
100
+ entry.pump = Option.some(yield* Effect.forkIn(pumpOf(entry, acquire()), scope, { startImmediately: true }));
101
+ return hearing.stream;
102
+ }));
104
103
  /**
105
104
  * A shared source per target: a function from a target to a Stream that's hot and counted for that
106
105
  * target. The first subscriber for a target starts `lookup(target)`'s source, later ones share it, and it
107
- * stops when the last one for that target leaves, after `idleTimeToLive` if it's given.
106
+ * stops when the last one for that target leaves.
108
107
  *
109
108
  * @example
110
109
  * // `resizesOf(target)`: an Environment's own Stream of a target's sizes
111
110
  * const resize = yield* SharedSource.byTarget((target) => Effect.succeed(resizesOf(target)))
112
111
  */
113
- export const byTarget = /*#__PURE__*/ Effect.fnUntraced(function* (lookup, options) {
112
+ export const byTarget = /*#__PURE__*/ Effect.fnUntraced(function* (lookup) {
114
113
  yield* Effect.logDebug("wardic.sharedSource.byTarget: create");
115
- // One stable identity key per target (see TargetKey). Object targets are cached weakly, so the
116
- // key, and the RcMap entry it addresses, share the target's lifetime; a non-object target hashes
117
- // safely on its own.
118
- const keys = new WeakMap();
119
- const keyFor = (target) => Option.match(Option.liftPredicate(target, Predicate.isObjectOrArray), {
120
- onNone: () => target,
121
- onSome: (object) => Option.getOrElse(Option.fromUndefinedOr(keys.get(object)), () => {
122
- const key = new TargetKey(object);
123
- keys.set(object, key);
124
- return key;
125
- }),
126
- });
127
- const map = yield* RcMap.make({
128
- lookup: (key) => fanIn(lookup(targetOf(key))),
129
- ...idleOf(options),
130
- });
131
- return (target) => tracedStream(Stream.unwrap(Effect.gen(function* () {
132
- yield* Effect.logDebug("wardic.sharedSource.byTarget: subscribe");
133
- return subscriberOf(yield* RcMap.get(map, keyFor(target)));
134
- })), "wardic.sharedSource.byTarget");
114
+ const scope = yield* Scope.Scope;
115
+ const hold = counted(fanned, stop);
116
+ return (target) => tracedStream(Stream.unwrap(Effect.as(Effect.logDebug("wardic.sharedSource.byTarget: subscribe"), subscriberOf(hold, target, () => lookup(target), scope))), "wardic.sharedSource.byTarget");
135
117
  });
136
118
  /**
137
119
  * One shared source for the whole Environment: a Stream that's hot and counted. The first subscriber
138
- * starts `acquire`'s source, later ones share it, and it stops when the last one leaves, after
139
- * `idleTimeToLive` if it's given. `byTarget`'s form without a target.
120
+ * starts `acquire`'s source, later ones share it, and it stops when the last one leaves. `byTarget`'s
121
+ * form without a target.
140
122
  *
141
123
  * @example
142
124
  * // `viewportChanges`: an Environment's own Stream of its viewport's size
143
125
  * const viewport = yield* SharedSource.make(Effect.succeed(viewportChanges))
144
126
  * Stream.runForEach(viewport, onResize) // one listener, however many subscribe
145
127
  */
146
- // As `RcRef.make` is `RcMap.make`'s.
147
- export const make = /*#__PURE__*/ Effect.fnUntraced(function* (acquire, options) {
128
+ export const make = /*#__PURE__*/ Effect.fnUntraced(function* (acquire) {
148
129
  yield* Effect.logDebug("wardic.sharedSource.make: create");
149
- const ref = yield* RcRef.make({
150
- acquire: fanIn(acquire),
151
- ...idleOf(options),
152
- });
153
- return tracedStream(Stream.unwrap(Effect.gen(function* () {
154
- yield* Effect.logDebug("wardic.sharedSource.make: subscribe");
155
- return subscriberOf(yield* RcRef.get(ref));
156
- })), "wardic.sharedSource.make");
130
+ const scope = yield* Scope.Scope;
131
+ const hold = counted(fanned, stop);
132
+ return tracedStream(Stream.unwrap(Effect.as(Effect.logDebug("wardic.sharedSource.make: subscribe"), subscriberOf(hold, undefined, () => acquire, scope))), "wardic.sharedSource.make");
157
133
  });
158
134
  //# sourceMappingURL=SharedSource.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SharedSource.js","sourceRoot":"","sources":["../src/SharedSource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SharedSource.js","sourceRoot":"","sources":["../src/SharedSource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,sGAAsG;AACtG,4EAA4E;AAC5E,EAAE;AACF,yGAAyG;AACzG,2GAA2G;AAC3G,qGAAqG;AACrG,2FAA2F;AAC3F,sGAAsG;AACtG,mGAAmG;AACnG,yGAAyG;AACzG,+FAA+F;AAC/F,EAAE;AACF,wGAAwG;AACxG,qFAAqF;AACrF,6FAA6F;AAC7F,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAQpD;;;;;;;;;;;;GAYG;AACH,yGAAyG;AACzG,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,IAAmB,EACnB,KAAwC,EACY,EAAE;IACtD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAc,CAAA;IAClC,MAAM,OAAO,GAAG,CAAC,GAAM,EAA0B,EAAE,CACjD,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;QACf,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE;YACzE,MAAM,MAAM,GAAY,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;YACtD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACrB,OAAO,MAAM,CAAA;QACf,CAAC,CAAC,CAAA;QACF,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;IACJ,MAAM,OAAO,GAAG,CAAC,GAAM,EAAE,KAAc,EAAuB,EAAE,CAC9D,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;QAClB,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC,IAAI,CAAA;QACvC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC7C,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IACJ,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AACzH,CAAC,CAAA;AASD,sEAAsE;AACtE,MAAM,MAAM,GAAG,GAAiB,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;AAEvG,wGAAwG;AACxG,MAAM,MAAM,GAAG,CAAI,KAAgB,EAAE,OAA4D,EAAuB,EAAE,CACxH,MAAM,CAAC,MAAM,CACX,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACrJ,CAAC,IAAI,CACJ,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CACrB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;IACf,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;AAC9D,CAAC,CAAC,CACH,CACF,CAAA;AAEH,yDAAyD;AACzD,MAAM,IAAI,GAAG,CAAI,KAAgB,EAAuB,EAAE,CACxD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAA;AAEjH;;;;GAIG;AACH,MAAM,YAAY,GAAG,CACnB,IAAoE,EACpE,GAAY,EACZ,OAAkE,EAClE,KAAkB,EACA,EAAE,CACpB,MAAM,CAAC,MAAM,CACX,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAK,CAAA;IACjC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC9B,OAAO,OAAO,CAAC,MAAM,CAAA;IACvB,CAAC;IACD,wEAAwE;IACxE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC3B,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACnF,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC1I,OAAO,OAAO,CAAC,MAAM,CAAA;AACvB,CAAC,CAAC,CACH,CAAA;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,QAAQ,GAE2D,aAAa,CAAC,MAAM,CAAC,UAAU,CAC7G,QAAQ,CAAC,EAAK,MAAgF;IAC5F,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,sCAAsC,CAAC,CAAA;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;IAChC,MAAM,IAAI,GAAG,OAAO,CAAqB,MAAM,EAAE,IAAI,CAAC,CAAA;IACtD,OAAO,CAAC,MAAe,EAAoB,EAAE,CAC3C,YAAY,CACV,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,yCAAyC,CAAC,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAC7I,8BAA8B,CAC/B,CAAA;AACL,CAAC,CAAC,CAAA;AAEJ;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,IAAI,GAE0C,aAAa,CAAC,MAAM,CAAC,UAAU,CACxF,QAAQ,CAAC,EAAK,OAA4D;IACxE,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,kCAAkC,CAAC,CAAA;IAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;IAChC,MAAM,IAAI,GAAG,OAAO,CAAqB,MAAM,EAAE,IAAI,CAAC,CAAA;IACtD,OAAO,YAAY,CACjB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,qCAAqC,CAAC,EAAE,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EACrI,0BAA0B,CAC3B,CAAA;AACH,CAAC,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * Each Primitive is a machine (`Machine`), run as a `Stream` over the Clock's ticks
8
8
  * (`Machine.toStream`) or on the Frame loop (`Machine.run`). The services (`Clock`,
9
- * `RefreshFrameSource`, `Renderer`, `InputSource`, `Probe`, `InterpolatorRegistry`, `FrameLoop`,
9
+ * `RefreshFrameSource`, `Renderer`, `InputSource`, `Probe`, `ScrollSource`, `InterpolatorRegistry`, `FrameLoop`,
10
10
  * `DefaultTransition`) are each `X.X`, with the shared constructors the Environments build on
11
11
  * (`Clock.layer`, `Clock.fromRefreshFrames`, `InputSource.heldPointer`, `InputFeed.byTarget`,
12
12
  * `InterpolatorRegistry.layer`, `FrameLoop.layer`, `DefaultTransition.layerOneSpring`). Each module's
@@ -45,6 +45,7 @@ export * as RefreshFrameSource from "./RefreshFrameSource.ts";
45
45
  export * as Renderer from "./Renderer.ts";
46
46
  export * as Reorder from "./Reorder.ts";
47
47
  export * as Scalar from "./Scalar.ts";
48
+ export * as ScrollSource from "./ScrollSource.ts";
48
49
  export * as Sequence from "./Sequence.ts";
49
50
  export * as SharedSource from "./SharedSource.ts";
50
51
  export * as Spring from "./Spring.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAA;AACjE,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAA;AACjE,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA"}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * Each Primitive is a machine (`Machine`), run as a `Stream` over the Clock's ticks
8
8
  * (`Machine.toStream`) or on the Frame loop (`Machine.run`). The services (`Clock`,
9
- * `RefreshFrameSource`, `Renderer`, `InputSource`, `Probe`, `InterpolatorRegistry`, `FrameLoop`,
9
+ * `RefreshFrameSource`, `Renderer`, `InputSource`, `Probe`, `ScrollSource`, `InterpolatorRegistry`, `FrameLoop`,
10
10
  * `DefaultTransition`) are each `X.X`, with the shared constructors the Environments build on
11
11
  * (`Clock.layer`, `Clock.fromRefreshFrames`, `InputSource.heldPointer`, `InputFeed.byTarget`,
12
12
  * `InterpolatorRegistry.layer`, `FrameLoop.layer`, `DefaultTransition.layerOneSpring`). Each module's
@@ -47,6 +47,7 @@ export * as RefreshFrameSource from "./RefreshFrameSource.js";
47
47
  export * as Renderer from "./Renderer.js";
48
48
  export * as Reorder from "./Reorder.js";
49
49
  export * as Scalar from "./Scalar.js";
50
+ export * as ScrollSource from "./ScrollSource.js";
50
51
  export * as Sequence from "./Sequence.js";
51
52
  export * as SharedSource from "./SharedSource.js";
52
53
  export * as Spring from "./Spring.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,oGAAoG;AACpG,uGAAuG;AACvG,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAA;AACjE,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,oGAAoG;AACpG,uGAAuG;AACvG,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAA;AAC3D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAA;AACjE,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import * as Cause from "effect/Cause";
2
2
  import * as Context from "effect/Context";
3
3
  import * as Effect from "effect/Effect";
4
+ import type * as Metric from "effect/Metric";
4
5
  import * as Option from "effect/Option";
5
6
  import type * as Scope from "effect/Scope";
6
7
  import * as Clock from "../Clock.ts";
@@ -43,6 +44,22 @@ export interface Shape {
43
44
  */
44
45
  readonly afterTick: (hook: () => undefined) => Effect.Effect<void, never, Scope.Scope>;
45
46
  }
47
+ /**
48
+ * The Frame loop's metrics: the running animations, the runs that settled and failed, and each tick's
49
+ * ms. None unless an app gives them (`FrameLoop.layerMetrics`, #518), so an app that reads none ships and
50
+ * updates none.
51
+ */
52
+ export interface Metrics {
53
+ readonly animations: Metric.Gauge<number>;
54
+ readonly settled: Metric.Counter<number>;
55
+ readonly failed: Metric.Counter<number>;
56
+ readonly tickMs: Metric.Histogram<number>;
57
+ }
58
+ /**
59
+ * Where a run's fiber finds the metrics. The loop takes them from the first run that has them: an app
60
+ * gives them beside its Environment, which the loop's own build doesn't see, as `CheckFrames` is read.
61
+ */
62
+ export declare const MetricsGiven: Context.Reference<Metrics | undefined>;
46
63
  /**
47
64
  * A check for development, off by default: on, every run started where it's on checks each Frame before
48
65
  * its sink gets it, and fails with `NonFiniteFrame` on a NaN or an Infinity. Read once a run, from the
@@ -1 +1 @@
1
- {"version":3,"file":"frameLoop.d.ts","sourceRoot":"","sources":["../../src/internal/frameLoop.ts"],"names":[],"mappings":"AAkDA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AAGzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAMvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAA;AAG1C,OAAO,KAAK,KAAK,MAAM,aAAa,CAAA;AACpC,OAAO,KAAK,KAAK,KAAK,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,KAAK,SAAS,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,KAAK,OAAO,MAAM,eAAe,CAAA;AAO7C,iFAAiF;AAEjF,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAA;CACxC;AAED,oFAAoF;AACpF,MAAM,WAAW,GAAG;IAClB,CAAC,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACxG,CAAC,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAA;CACrJ;AAED,wDAAwD;AACxD,MAAM,WAAW,KAAK;IACpB;;;;;;;;OAQG;IAGH,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IACjB;;;OAGG;IAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAA;IACrB;;;;;OAKG;IAEH,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,SAAS,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;CACvF;AA2BD;;;;;GAKG;AAEH,eAAO,MAAM,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,OAAO,CAEjD,CAAA;;;;AAEF;;;GAGG;AAEH,qBAAa,cAAe,SAAQ,oBAAmC;IACrE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,CAAC;CAAG;AAqEL;;;;;GAKG;AACH,eAAO,MAAM,IAAI;;;sBAqHY,MAAM,SAAS,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;oCA6HrF,CAAA"}
1
+ {"version":3,"file":"frameLoop.d.ts","sourceRoot":"","sources":["../../src/internal/frameLoop.ts"],"names":[],"mappings":"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"}
@@ -29,11 +29,11 @@
29
29
  *
30
30
  * Observability: a span per run, named after its Primitive (`machine.span`), and one per burst
31
31
  * (`wardic.frameloop`). A run's `<name>: start` debug log, annotated with its span's attributes,
32
- * built only when a Debug log would be kept (#542). Per tick, no span or log: a gauge of running
33
- * animations and a histogram of ms per tick, each one `updateUnsafe` (ADR-0027, decision 6), and the
34
- * runs that settled or failed in it, counted as they end and added at its end by the loop's own
35
- * `afterTick` hook, its first (#542). The histogram ends before the hooks, so it measures the steps
36
- * alone, not the gate's flush (ADR-0033).
32
+ * built only when a Debug log would be kept (#542). Per tick, no span or log. With the metrics an app
33
+ * gives (`FrameLoop.layerMetrics`, #518): a gauge of running animations and a histogram of ms per tick,
34
+ * each one `updateUnsafe` (ADR-0027, decision 6), and the runs that settled or failed in it, counted as
35
+ * they end and added at its end by the loop's own `afterTick` hook, its first (#542). The histogram ends
36
+ * before the hooks, so it measures the steps alone, not the gate's flush (ADR-0033).
37
37
  *
38
38
  * A run's span is opened without a stack frame (ADR-0040, decision 3): `useSpan` with the span as
39
39
  * the `ParentSpan`, not `withSpan`, whose frame Effect stamps on an interrupted run's cause and
@@ -57,7 +57,6 @@ import * as Exit from "effect/Exit";
57
57
  import * as FiberHandle from "effect/FiberHandle";
58
58
  import { constUndefined, identity } from "effect/Function";
59
59
  import * as LogLevel from "effect/LogLevel";
60
- import * as Metric from "effect/Metric";
61
60
  import * as Option from "effect/Option";
62
61
  import * as Predicate from "effect/Predicate";
63
62
  import * as References from "effect/References";
@@ -66,12 +65,13 @@ import * as Tracer from "effect/Tracer";
66
65
  import * as Clock from "../Clock.js";
67
66
  import * as Supersede from "../Supersede.js";
68
67
  import { isTraced, traced } from "./tracing.js";
69
- const animations = Metric.gauge("wardic_frameloop_animations", { description: "Primitives running on the Frame loop" });
70
- const settledRuns = Metric.counter("wardic_frameloop_settled", { description: "Runs on the Frame loop that settled" });
71
- const failedRuns = Metric.counter("wardic_frameloop_failed", { description: "Runs on the Frame loop that failed" });
72
- const tickMs = Metric.histogram("wardic_frameloop_tick_ms", {
73
- description: "Milliseconds the Frame loop spends on one tick",
74
- boundaries: Metric.linearBoundaries({ start: 0, width: 0.5, count: 32 }),
68
+ /**
69
+ * Where a run's fiber finds the metrics. The loop takes them from the first run that has them: an app
70
+ * gives them beside its Environment, which the loop's own build doesn't see, as `CheckFrames` is read.
71
+ */
72
+ // #518, ADR-0067 *Amendment (#518)*, decision 2.
73
+ export const MetricsGiven = Context.Reference("@wardic/core/FrameLoop/Metrics", {
74
+ defaultValue: constUndefined,
75
75
  });
76
76
  /**
77
77
  * A check for development, off by default: on, every run started where it's on checks each Frame before
@@ -174,6 +174,8 @@ export const make = Effect.fnUntraced(function* () {
174
174
  // once per tick. An interruption is neither, nor a superseded run, which the loop doesn't end.
175
175
  let settledCount = 0;
176
176
  let failedCount = 0;
177
+ // The metrics, once a run brings them (#518).
178
+ let metrics;
177
179
  /** End `entry`'s run: removed, counted, and its fiber resumed with `exit` (inline, within the tick). */
178
180
  const end = (entry, exit) => {
179
181
  entry.removed = true;
@@ -185,10 +187,12 @@ export const make = Effect.fnUntraced(function* () {
185
187
  };
186
188
  /** The runs ended since the last count, into the counters: once per tick, and as a burst ends. */
187
189
  const countEnds = () => {
188
- if (settledCount > 0)
189
- settledRuns.updateUnsafe(settledCount, buildContext);
190
- if (failedCount > 0)
191
- failedRuns.updateUnsafe(failedCount, buildContext);
190
+ if (Predicate.isNotUndefined(metrics)) {
191
+ if (settledCount > 0)
192
+ metrics.settled.updateUnsafe(settledCount, buildContext);
193
+ if (failedCount > 0)
194
+ metrics.failed.updateUnsafe(failedCount, buildContext);
195
+ }
192
196
  settledCount = 0;
193
197
  failedCount = 0;
194
198
  return undefined;
@@ -234,7 +238,10 @@ export const make = Effect.fnUntraced(function* () {
234
238
  // The first lane's loops stay inline in `tick`: moved into a function shared with the last lane,
235
239
  // Node's `chase/loop` ran 55% slower (`bench:core`, ADR-0027 *Amendment (#137)*).
236
240
  const tick = (dt) => {
237
- const t0 = performance.now();
241
+ // The tick's start, read only for the metrics' histogram (#518).
242
+ let t0 = 0;
243
+ if (Predicate.isNotUndefined(metrics))
244
+ t0 = performance.now();
238
245
  // Both counts before any step: a run added during the tick, to either lane, waits for the next.
239
246
  const count = entries.length;
240
247
  const lastCount = lastEntries.length;
@@ -267,8 +274,10 @@ export const make = Effect.fnUntraced(function* () {
267
274
  entries.length = kept;
268
275
  if (lastEntries.length > 0)
269
276
  kept += compactLast();
270
- animations.updateUnsafe(kept, buildContext);
271
- tickMs.updateUnsafe(performance.now() - t0, buildContext);
277
+ if (Predicate.isNotUndefined(metrics)) {
278
+ metrics.animations.updateUnsafe(kept, buildContext);
279
+ metrics.tickMs.updateUnsafe(performance.now() - t0, buildContext);
280
+ }
272
281
  // The end of the tick: everything for this Refresh frame is written (ADR-0033). After
273
282
  // `tickMs`, which stays the cost of the steps alone.
274
283
  const ended = hooks;
@@ -299,7 +308,8 @@ export const make = Effect.fnUntraced(function* () {
299
308
  if (!entry.removed)
300
309
  end(entry, ending);
301
310
  });
302
- animations.updateUnsafe(0, buildContext);
311
+ if (Predicate.isNotUndefined(metrics))
312
+ metrics.animations.updateUnsafe(0, buildContext);
303
313
  countEnds();
304
314
  };
305
315
  const ticking = clock.ticks.pipe(Stream.map(tick), Stream.takeUntil(identity), Stream.runDrain, Effect.onExit((exit) => Effect.sync(() => endAll(exit))), (self) => traced(self, "wardic.frameloop", { root: true }), Effect.provideContext(buildContext));
@@ -323,6 +333,9 @@ export const make = Effect.fnUntraced(function* () {
323
333
  const runIn = (lane) => ((machine, sink, options) => Effect.withFiber((fiber) => {
324
334
  // Its start log only when a Debug log would be kept (#542): Effect's own rule, read once.
325
335
  const logged = !LogLevel.isGreaterThan(fiber.getRef(References.MinimumLogLevel), "Debug");
336
+ // The metrics from the first run whose fiber has them (#518); none is read once they're in.
337
+ if (Predicate.isUndefined(metrics))
338
+ metrics = fiber.getRef(MetricsGiven);
326
339
  if (!isTraced(fiber))
327
340
  return added(lane, machine, sink, options, undefined, logged);
328
341
  return Effect.useSpan(machine.span.name, { attributes: machine.span.attributes }, (span) => Effect.provideService(added(lane, machine, sink, options, span, logged), Tracer.ParentSpan, span));