uneventful 0.0.13 → 0.0.16

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.
@@ -1,5 +1,5 @@
1
- import { s as start, j as connect, p as isValue, h as isError, f as markHandled } from './jobutils-O9tOTNKC.mjs';
2
- import { i as isFunction } from './utils-BgqyDPjA.mjs';
1
+ import { s as start, j as connect, p as isValue, h as isError, f as markHandled } from './jobutils-WMcB-H_8.mjs';
2
+ import { i as isFunction } from './utils-XKvfJLkI.mjs';
3
3
 
4
4
  function callOrWait(source, method, handler, noArgs) {
5
5
  if (source && isFunction(source[method]))
package/dist/ext.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as PlainFunction } from './types-pElgImr7.js';
1
+ import { P as PlainFunction } from './types-C3WWddF2.js';
2
2
 
3
3
  /**
4
4
  * This module provides helpers for creating *extensions*: a way of extending
package/dist/ext.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { s as setMap } from './utils-BgqyDPjA.mjs';
1
+ import { s as setMap } from './utils-XKvfJLkI.mjs';
2
2
 
3
3
  function ext(factory, map = /* @__PURE__ */ new WeakMap()) {
4
4
  return (tgt) => map.has(tgt) ? map.get(tgt) : setMap(map, tgt, factory(tgt, map));
@@ -1,5 +1,5 @@
1
- import { M as pushCtx, N as popCtx, c as backpressure, I as IsStream, _ as _Job, d as root, h as isError, f as markHandled, g as getJob, o as currentCell } from './jobutils-O9tOTNKC.mjs';
2
- import { h as batch, d as defer, c as apply, s as setMap } from './utils-BgqyDPjA.mjs';
1
+ import { M as pushCtx, N as popCtx, c as backpressure, I as IsStream, l as currentCell, _ as _Job, d as root, h as isError, f as markHandled, g as getJob } from './jobutils-WMcB-H_8.mjs';
2
+ import { d as defer, b as apply, s as setMap, h as batch } from './utils-XKvfJLkI.mjs';
3
3
 
4
4
  const ruleQueues = /* @__PURE__ */ new WeakMap();
5
5
  function ruleQueue(scheduleFn = defer) {
@@ -209,6 +209,8 @@ class Cell {
209
209
  this.catchUp();
210
210
  if (this.adding === s)
211
211
  s.ts = this.lastChanged;
212
+ } else if (dep === false) {
213
+ throw new Error("Reactive values can't be used while creating services or lazy constants");
212
214
  } else
213
215
  this.catchUp();
214
216
  if (this.flags & 16 /* Error */)
@@ -241,7 +243,7 @@ class Cell {
241
243
  if (this.shouldWrite(val !== this.value || isErr !== !!(this.flags & 16 /* Error */))) {
242
244
  this.value = val;
243
245
  this.lastChanged = timestamp;
244
- this.flags = isErr ? this.flags | 16 /* Error */ : this.flags & ~16 /* Error */;
246
+ this.flags = isErr ? this.flags | 16 /* Error */ : this.flags & -17 /* Error */;
245
247
  }
246
248
  this.compute = isErr ? throwValue : returnValue;
247
249
  }
@@ -318,11 +320,11 @@ class Cell {
318
320
  throw e;
319
321
  }
320
322
  } finally {
321
- this.flags &= ~32 /* Running */;
323
+ this.flags &= -33 /* Running */;
322
324
  if (this.flags & 64 /* Stateful */) {
323
325
  demandChanges.delete(this);
324
326
  if (this.flags & (16 /* Error */ | 2 /* Stopped */)) {
325
- this.flags &= ~2 /* Stopped */;
327
+ this.flags &= -3 /* Stopped */;
326
328
  this.job?.restart();
327
329
  } else if (this.flags & 1 /* Observed */) ; else {
328
330
  this.job?.restart();
@@ -350,7 +352,7 @@ class Cell {
350
352
  mksub(dummySource ||= Cell.mkValue(null), this);
351
353
  return;
352
354
  }
353
- this.flags &= ~4 /* Compute */;
355
+ this.flags &= -5 /* Compute */;
354
356
  if (this.flags & 132 /* Variable */)
355
357
  return;
356
358
  while (this.adding)
@@ -480,7 +482,7 @@ class Cell {
480
482
  try {
481
483
  return apply(fn, thisArg, args);
482
484
  } finally {
483
- this.flags &= ~8 /* Peeking */;
485
+ this.flags &= -9 /* Peeking */;
484
486
  }
485
487
  }
486
488
  unchangedIf(newVal, equals) {
@@ -572,7 +574,13 @@ function perSignal(func, site, name) {
572
574
  if (findOrCreateMemos(hooks2, site, 1)) {
573
575
  return getMemo(hooks2, 1)();
574
576
  } else {
575
- const result = func(...args);
577
+ let result;
578
+ pushCtx(void 0, false);
579
+ try {
580
+ result = func(...args);
581
+ } finally {
582
+ popCtx();
583
+ }
576
584
  setMemo(hooks2, 1, () => result);
577
585
  return result;
578
586
  }
@@ -1,4 +1,4 @@
1
- import { h as batch, d as defer, i as isFunction, G as GeneratorBase, c as apply } from './utils-BgqyDPjA.mjs';
1
+ import { h as batch, d as defer, i as isFunction, G as GeneratorBase, b as apply } from './utils-XKvfJLkI.mjs';
2
2
 
3
3
  function resolve(request, val) {
4
4
  request("next", val);
@@ -80,7 +80,7 @@ function popCtx() {
80
80
  currentCell = cells.pop();
81
81
  }
82
82
  function cellJob() {
83
- return currentJob ||= currentCell?.getJob();
83
+ return currentJob ||= currentCell ? currentCell.getJob() : void 0;
84
84
  }
85
85
 
86
86
  const catchers = /* @__PURE__ */ new WeakMap(), defaultCatch = (e) => {
@@ -93,6 +93,12 @@ const pulls = /* @__PURE__ */ batch((pulls2) => {
93
93
  conn.doPull();
94
94
  }
95
95
  }, defer);
96
+ let lazyConstants;
97
+ let rootId = 0;
98
+ function resetConstants() {
99
+ ++rootId;
100
+ lazyConstants = /* @__PURE__ */ new WeakMap();
101
+ }
96
102
 
97
103
  function chain() {
98
104
  return link(0, void 0, void 0);
@@ -259,7 +265,7 @@ class _Job {
259
265
  });
260
266
  }
261
267
  result() {
262
- return this._done || currentCell?.recalcWhen(this, recalcJob) || void 0;
268
+ return this._done || currentCell && currentCell.recalcWhen(this, recalcJob) || void 0;
263
269
  }
264
270
  get [Symbol.toStringTag]() {
265
271
  return "Job";
@@ -451,6 +457,7 @@ let root;
451
457
  newRoot();
452
458
  function newRoot() {
453
459
  root?.end();
460
+ resetConstants();
454
461
  const job = root = new _Job().asyncCatch(defaultCatch);
455
462
  job.release(() => root === job && (root = null));
456
463
  return root;
@@ -614,7 +621,7 @@ function start(init, fn) {
614
621
  return getJob().start(init, fn);
615
622
  }
616
623
  function isJobActive() {
617
- return !!(currentJob || currentCell?.isObserved());
624
+ return !!(currentJob || currentCell && currentCell.isObserved());
618
625
  }
619
626
  const timers = /* @__PURE__ */ new WeakMap();
620
627
  function timeout(ms = 0, job = getJob()) {
@@ -679,4 +686,4 @@ function task(fn, _ctx, desc) {
679
686
  };
680
687
  }
681
688
 
682
- export { CancelError as A, pipe as B, CancelResult as C, compose as D, ErrorResult as E, into as F, isJobActive as G, timeout as H, IsStream as I, abortSignal as J, task as K, currentJob as L, pushCtx as M, popCtx as N, ValueResult as V, _Job as _, rejecter as a, resolve as b, backpressure as c, root as d, isUnhandled as e, markHandled as f, getJob as g, isError as h, isCancel as i, connect as j, fulfillPromise as k, restarting as l, must as m, noop as n, currentCell as o, isValue as p, nativePromise as q, resolver as r, start as s, throttle as t, makeJob as u, newRoot as v, reject as w, isHandled as x, getResult as y, propagateResult as z };
689
+ export { makeJob as A, nativePromise as B, CancelError as C, newRoot as D, ErrorResult as E, pipe as F, propagateResult as G, reject as H, IsStream as I, task as J, timeout as K, lazyConstants as L, pushCtx as M, popCtx as N, rootId as O, currentJob as P, ValueResult as V, _Job as _, resolver as a, rejecter as b, backpressure as c, root as d, isUnhandled as e, markHandled as f, getJob as g, isError as h, isCancel as i, connect as j, fulfillPromise as k, currentCell as l, must as m, noop as n, restarting as o, isValue as p, CancelResult as q, resolve as r, start as s, throttle as t, abortSignal as u, compose as v, getResult as w, into as x, isHandled as y, isJobActive as z };
package/dist/mod.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { J as Job, C as CleanupFn, Y as Yielding, S as Source, D as DisposeFn, a as Stream, B as Backpressure, T as Transformer, b as Sink, O as OptionalCleanup, c as StartFn, d as StartObj, A as AnyFunction } from './types-pElgImr7.js';
2
- export { e as AsyncStart, z as CancelError, m as CancelResult, K as Connection, E as ErrorResult, H as HandledError, I as Inlet, M as IsStream, g as JobIterator, o as JobResult, N as Nothing, P as PlainFunction, i as RecalcSource, R as Request, L as SignalSource, h as Suspend, f as SyncStart, G as Throttle, U as UnhandledError, V as ValueResult, F as backpressure, Z as compose, Q as connect, x as fulfillPromise, w as getResult, _ as into, p as isCancel, s as isError, u as isHandled, t as isUnhandled, q as isValue, v as markHandled, n as noop, X as pipe, y as propagateResult, j as reject, l as rejecter, r as resolve, k as resolver, W as throttle } from './types-pElgImr7.js';
3
- export { a as Each, E as EachResult, N as NextMethod, U as UntilMethod, e as each, f as forEach, i as isObserved, n as next, r as recalcWhen } from './sinks-B_LfTZgF.js';
1
+ import { J as Job, C as CleanupFn, Y as Yielding, S as Source, B as Backpressure, D as DisposeFn, a as Stream, T as Transformer, b as Sink, O as OptionalCleanup, A as AnyFunction, c as StartFn, d as StartObj } from './types-C3WWddF2.js';
2
+ export { e as AsyncStart, f as CancelError, g as CancelResult, h as Connection, E as ErrorResult, H as HandledError, I as Inlet, i as IsStream, j as JobIterator, k as JobResult, N as Nothing, P as PlainFunction, R as RecalcSource, l as Request, m as SignalSource, n as Suspend, o as SyncStart, p as Throttle, U as UnhandledError, V as ValueResult, q as backpressure, r as compose, s as connect, t as fulfillPromise, u as getResult, v as into, w as isCancel, x as isError, y as isHandled, z as isUnhandled, F as isValue, G as markHandled, K as noop, L as pipe, M as propagateResult, Q as reject, W as rejecter, X as resolve, Z as resolver, _ as throttle } from './types-C3WWddF2.js';
3
+ export { E as Each, a as EachResult, N as NextMethod, U as UntilMethod, e as each, f as forEach, i as isObserved, n as next, r as recalcWhen } from './sinks-CoXxbJrs.js';
4
4
 
5
5
  /**
6
6
  * Invoke a no-argument function as a microtask, using queueMicrotask or Promise.resolve().then()
package/dist/mod.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { d as defer, i as isFunction } from './utils-BgqyDPjA.mjs';
2
- import { r as resolver, a as rejecter, b as resolve, I as IsStream, c as backpressure, m as must, s as start, g as getJob, n as noop, d as root, i as isCancel, e as isUnhandled, f as markHandled, h as isError, t as throttle, j as connect, k as fulfillPromise, l as restarting, o as currentCell, p as isValue } from './jobutils-O9tOTNKC.mjs';
3
- export { A as CancelError, C as CancelResult, E as ErrorResult, V as ValueResult, J as abortSignal, D as compose, y as getResult, F as into, x as isHandled, G as isJobActive, u as makeJob, q as nativePromise, v as newRoot, B as pipe, z as propagateResult, w as reject, K as task, H as timeout } from './jobutils-O9tOTNKC.mjs';
4
- import { c as callOrWait, m as mustBeSourceOrSignal } from './call-or-wait-CvOF0pao.mjs';
1
+ import { d as defer, i as isFunction } from './utils-XKvfJLkI.mjs';
2
+ import { r as resolve, a as resolver, b as rejecter, I as IsStream, c as backpressure, m as must, s as start, g as getJob, n as noop, d as root, i as isCancel, e as isUnhandled, f as markHandled, h as isError, t as throttle, j as connect, k as fulfillPromise, l as currentCell, o as restarting, p as isValue } from './jobutils-WMcB-H_8.mjs';
3
+ export { C as CancelError, q as CancelResult, E as ErrorResult, V as ValueResult, u as abortSignal, v as compose, w as getResult, x as into, y as isHandled, z as isJobActive, A as makeJob, B as nativePromise, D as newRoot, F as pipe, G as propagateResult, H as reject, J as task, K as timeout } from './jobutils-WMcB-H_8.mjs';
4
+ import { c as callOrWait, m as mustBeSourceOrSignal } from './call-or-wait-DgI1Y5BE.mjs';
5
5
 
6
6
  function* to(p) {
7
7
  return yield (res) => Promise.resolve(p).then(resolver(res), rejecter(res));
@@ -276,10 +276,10 @@ function forEach(src, sink, inlet) {
276
276
  return (src2) => forEach(src2, sink, inlet);
277
277
  }
278
278
  function recalcWhen(fnOrKey, fn) {
279
- currentCell?.recalcWhen(fnOrKey, fn);
279
+ currentCell && currentCell.recalcWhen(fnOrKey, fn);
280
280
  }
281
281
  function isObserved() {
282
- return currentCell?.isObserved();
282
+ return currentCell ? currentCell.isObserved() : void 0;
283
283
  }
284
284
 
285
285
  function concat(sources) {
package/dist/shared.d.ts CHANGED
@@ -1,33 +1,32 @@
1
- import { Y as Yielding } from './types-pElgImr7.js';
1
+ import { Y as Yielding } from './types-C3WWddF2.js';
2
2
 
3
3
  /** @inline */
4
4
  type CallSite = TemplateStringsArray;
5
5
 
6
6
  /**
7
7
  * Tools for sharing tasks, values, services, etc., especially across job
8
- * boundaries.
8
+ * boundaries, but also across reactive expression lifetimes (similar to React
9
+ * hooks).
9
10
  *
10
11
  * @module uneventful/shared
11
12
  * @disableGroups
12
13
  */
13
14
 
14
15
  /**
15
- * Wrap a factory function to create a singleton service accessor
16
+ * Define a configurable service accessor
16
17
  *
17
- * The returned function, when called, will run the factory in a new job and
18
- * cache the result. The job the factory ran in will end when the {@link root}
19
- * job does, after which the cached result will be cleared.
18
+ * The returned accessor function, when called, will run the factory in the
19
+ * {@link root} job and cache the result until/unless a new root is started.
20
20
  *
21
- * @param factory A function returning whatever result you want to share: a
22
- * value, a function, an object, etc. It will be called at most once per root
23
- * job lifetime, in a job that is an immediate child of the root job.
21
+ * The factory and result can be overridden at runtime using the accessor's
22
+ * methods: i.e. `myService.set(obj)` sets the instance that `myService()` will
23
+ * return, `myService.replace(otherFactory)` changes the factory used to create
24
+ * it, and so on.
24
25
  *
25
- * (Note: if your factory is a native generator function, it is automatically
26
- * wrapped with {@link fork}() so that its job will not end when the generator
27
- * ends, and the result can be waited on by multiple callers. If your factory
28
- * is *not* a native generator function but still returns a generator to produce
29
- * an async result, you should wrap that generator with {@link fork} before
30
- * returning it.)
26
+ * @param defaultFactory The {@link ServiceFactory} function or class whose
27
+ * shared/cached result the accessor returns by default. See
28
+ * {@link ServiceFactory} for important details on how the factory is run and
29
+ * the restrictions on what it can do.
31
30
  *
32
31
  * @remarks Note that if you want your code to be testable with {@link newRoot},
33
32
  * you should avoid storing the *result* of calling the service accessor
@@ -43,7 +42,43 @@ type CallSite = TemplateStringsArray;
43
42
  *
44
43
  * @category Resources
45
44
  */
46
- declare function service<T>(factory: () => T): () => T;
45
+ declare function service<T>(defaultFactory: ServiceFactory<T>): ServiceAccessor<T>;
46
+ /**
47
+ * A configurable access point for a lazily-created {@link service}.
48
+ *
49
+ * @category Types and Interfaces
50
+ */
51
+ interface ServiceAccessor<T> {
52
+ /** Return the service's current instance, creating it if necessary */
53
+ (): T;
54
+ set(instance: T): void;
55
+ unset(): void;
56
+ replace(factory?: ServiceFactory<T>): void;
57
+ }
58
+ /**
59
+ * A function, or class constructor producing a value that will be cached by a
60
+ * `service()` accessor for the life of the root job. (Or until overridden via
61
+ * a service accessor's set/unset methods.)
62
+ *
63
+ * The function or constructor will be run in the then-current root job, and its
64
+ * value cached. If the function is a native generator function, it is
65
+ * automatically wrapped with {@link fork}(), so that its job will not end when
66
+ * the generator ends, and the result can be waited on by multiple callers. (If
67
+ * your factory is *not* a native generator function but still returns a
68
+ * generator to produce an async result, you should wrap that generator with
69
+ * {@link fork} before returning it.)
70
+ *
71
+ * Note: if an original or replacement factory directly or indirectly requests
72
+ * its own value (even via a {@link service}() accessor), an error is thrown to
73
+ * prevent infinite recursion. An error is also thrown if a reactive value is
74
+ * directly or indirectly accessed during the factory's execution, to prevent
75
+ * your cached service from unintentionally retaining a stale value. (Rules
76
+ * and {@link uneventful/signals.fx fx()} are unaffected, as they will update
77
+ * their state as needed.)
78
+ *
79
+ * @category Types and Interfaces
80
+ */
81
+ type ServiceFactory<T> = (() => T) | (new () => T);
47
82
  /**
48
83
  * Proxy an object so it "expires" (becomes inaccessible) with the calling job.
49
84
  *
@@ -65,31 +100,49 @@ declare function fork<T, F extends (...args: any[]) => Yielding<T>>(genFunc: F,
65
100
  declare function fork<T, F extends (...args: any[]) => Yielding<T>, D extends {
66
101
  value?: F;
67
102
  }>(clsOrProto: any, name: string | symbol, desc: D): D;
68
- /** @inline */
69
- type Factory<T> = (() => T) | (new () => T);
70
103
  /**
71
- * Return a singleton instance for the given factory
104
+ * A function, or class constructor producing a value that will be cached by
105
+ * ```$``()``` as a permanent-per-signal constant at a given call site.
106
+ *
107
+ * The function or constructor will be run *without* an active job, and its
108
+ * value cached. While it runs, any attempt to directly access a reactive value
109
+ * or expression will be blocked by a thrown error, to prevent your cached
110
+ * result from capturing a stale value.
111
+ *
112
+ * Note that unlike {@link ServiceFactory}, a ConstantFactory *cannot* use job
113
+ * APIs, rules, or fx(), nor is there any special handling for generator
114
+ * functions. None of these things make any sense for a lazy constant, as there
115
+ * is no way to clean up after them: they simply exist for the life of the
116
+ * signal (or root job, for global constants) and so should be relatively
117
+ * stateless.
118
+ *
119
+ * @category Types and Interfaces
120
+ */
121
+ type ConstantFactory<T> = (() => T) | (new () => T);
122
+ /**
123
+ * Return a lazily-initialized constant value for the given factory
124
+ *
125
+ * Every call to `$()` with a given factory will return the same result.
126
+ * (Until/unless a new root job is started.)
72
127
  *
73
- * Every call to `$()` with a given factory will return the same result. (Unless
74
- * overridden using {@link $cache.set}, {@link $cache.unset} or
75
- * {@link $cache.replace}.) On first use, the factory is called (or
76
- * constructed, if it's a class) and the result (if not an error) is cached for
77
- * future calls.
128
+ * On first use, the factory is called (or constructed, if it's a class) and the
129
+ * result (if not an error) is cached for future calls.
78
130
  *
131
+ * @param factory The {@link ConstantFactory} function or class whose
132
+ * shared/cached value you want to get. (See {@link ConstantFactory} for
133
+ * important details on how the factory is run and the restrictions on what it
134
+ * can do.)
79
135
  */
80
- declare function $<T>(factory: Factory<T>): T;
136
+ declare function $<T>(factory: ConstantFactory<T>): T;
81
137
  /**
82
138
  * Create a per-signal lazy constant, via ```$``()```
83
139
  *
84
140
  * When you call ```$``(factory)``` inside a given signal function for the first
85
- * time, `factory()` will be called (or constructed, if it's a class) and
86
- * returned, and the result cached for future calls *at the same location in
87
- * that specific signal*. An error results if called outside a signal function.
88
- *
89
- * The primary difference between this and the singleton operator (plain `$()`),
90
- * is that lazy constants are singletons *per call-site*, *per signal*. A
91
- * specific invocation of ```$``()``` in a specific signal will always return
92
- * the same value.
141
+ * time, the {@link ConstantFactory} will be called (or constructed, if it's a
142
+ * class) and the returned result will be cached for ALL future calls *at the
143
+ * same code location in that specific signal*. An error results if called
144
+ * outside a signal function. See the {@link ConstantFactory} docs for more
145
+ * details on how the factory is called, and the restrictions on what it can do.
93
146
  *
94
147
  * @remarks
95
148
  * Lazy constants are somewhat similar in concept to a React `useMemo()`, but
@@ -107,41 +160,9 @@ declare function $<T>(factory: Factory<T>): T;
107
160
  * call a wrapping function more than once in a signal, and expect to get
108
161
  * different results: a lazy constant is a per-signal *constant*, not a React
109
162
  * hook!)
110
- */
111
- declare function $(callSite: CallSite): <T>(factory: Factory<T>) => T;
112
- /**
113
- * Utilities for manipulating the singleton cache (e.g. for testing)
114
163
  *
115
- * @category Singletons & Lazy Constants
116
- * @namespace
117
164
  * @experimental
118
165
  */
119
- declare const $cache: {
120
- /**
121
- * Set the cached singleton instance for a given factory. (e.g. for
122
- * testing)
123
- *
124
- * All subsequent calls to `$(factory)` will return the given result, until
125
- * manually set again, or reset via {@link $cache.unset}.
126
- */
127
- set<T>(factory: Factory<T>, result: T): void;
128
- /**
129
- * Unset the cached singleton for a given factory, such that the next call
130
- * to `$(factory)` will create a new instance.
131
- */
132
- unset<T>(factory: Factory<T>): void;
133
- /**
134
- * Replace the implementation for a given factory, such that future calls to
135
- * `$(factory)` will call or construct the replacement instead.
136
- *
137
- * If the replacement is omitted, null, or undefined, future calls will
138
- * invoke the original factory again.
139
- *
140
- * (Note: in all cases the replacement will not take effect if there's
141
- * already a cached singleton, so you may wish to call
142
- * {@link $cache.unset}() to ensure a future call is actually executed.)
143
- */
144
- replace<T>(factory: Factory<T>, replacement?: Factory<T>): void;
145
- };
166
+ declare function $(callSite: CallSite): <T>(factory: ConstantFactory<T>) => T;
146
167
 
147
- export { $, $cache, expiring, fork, service };
168
+ export { $, type ConstantFactory, type ServiceAccessor, type ServiceFactory, expiring, fork, service };
package/dist/shared.mjs CHANGED
@@ -1,24 +1,27 @@
1
- import { p as perSignal } from './hooks-BnMYHRlM.mjs';
2
- import { d as root, m as must, s as start, n as noop } from './jobutils-O9tOTNKC.mjs';
3
- import { a as isGeneratorFunction, b as decorateMethod, i as isFunction, c as apply, s as setMap, e as isClass } from './utils-BgqyDPjA.mjs';
1
+ import { L as lazyConstants, m as must, s as start, n as noop, M as pushCtx, N as popCtx, O as rootId, d as root } from './jobutils-WMcB-H_8.mjs';
2
+ import { p as perSignal } from './hooks-SVgnmOfF.mjs';
3
+ import { i as isFunction, s as setMap, a as decorateMethod, b as apply, c as isClass, e as isGeneratorFunction } from './utils-XKvfJLkI.mjs';
4
4
 
5
- function service(factory) {
6
- let known = false, value = void 0;
7
- if (isGeneratorFunction(factory))
8
- factory = fork(factory);
9
- return () => {
10
- if (known)
11
- return value;
12
- root.start(() => {
13
- value = factory();
14
- known = true;
15
- must(() => {
16
- value = void 0;
17
- known = false;
18
- });
19
- });
20
- return value;
21
- };
5
+ function service(defaultFactory) {
6
+ let validFor = -1;
7
+ let value = noop;
8
+ let currentFactory = defaultFactory;
9
+ function get() {
10
+ return validFor === rootId ? value : (value = createSingleton(get, currentFactory, root), validFor = rootId, value);
11
+ }
12
+ return Object.assign(get, {
13
+ set(result) {
14
+ validFor = rootId;
15
+ value = result;
16
+ },
17
+ unset() {
18
+ validFor = -1;
19
+ value = void 0;
20
+ },
21
+ replace(replacement = defaultFactory) {
22
+ currentFactory = replacement != null && replacement !== get ? replacement : defaultFactory;
23
+ }
24
+ });
22
25
  }
23
26
  function expiring(obj) {
24
27
  const p = Proxy.revocable(obj, {});
@@ -49,52 +52,33 @@ function fork(genOrFunc, ...args) {
49
52
  }
50
53
  }
51
54
  const forks = /* @__PURE__ */ new WeakMap();
52
- const constants = /* @__PURE__ */ new WeakMap(), factories = /* @__PURE__ */ new WeakMap();
53
55
  function $(key) {
54
56
  if (isFunction(key)) {
55
- return constants.has(key) ? constants.get(key) : setMap(
56
- constants,
57
+ return lazyConstants.has(key) ? lazyConstants.get(key) : setMap(
58
+ lazyConstants,
57
59
  key,
58
- callOrConstruct(factories.has(key) ? factories.get(key) : key)
60
+ createSingleton(key)
59
61
  );
60
62
  }
61
63
  return perSignal(callOrConstruct, key, "$``() ");
62
64
  }
65
+ const stack = [];
66
+ function createSingleton(key, f = key, runIn) {
67
+ if (stack.indexOf(key) > -1)
68
+ throw new Error("Factory depends on itself");
69
+ if (runIn && isGeneratorFunction(f))
70
+ f = fork(f);
71
+ stack.unshift(key);
72
+ pushCtx(runIn, false);
73
+ try {
74
+ return callOrConstruct(f);
75
+ } finally {
76
+ stack.shift();
77
+ popCtx();
78
+ }
79
+ }
63
80
  function callOrConstruct(f) {
64
81
  return isClass(f) ? new f() : f();
65
82
  }
66
- const $cache = {
67
- /**
68
- * Set the cached singleton instance for a given factory. (e.g. for
69
- * testing)
70
- *
71
- * All subsequent calls to `$(factory)` will return the given result, until
72
- * manually set again, or reset via {@link $cache.unset}.
73
- */
74
- set(factory, result) {
75
- constants.set(factory, result);
76
- },
77
- /**
78
- * Unset the cached singleton for a given factory, such that the next call
79
- * to `$(factory)` will create a new instance.
80
- */
81
- unset(factory) {
82
- constants.delete(factory);
83
- },
84
- /**
85
- * Replace the implementation for a given factory, such that future calls to
86
- * `$(factory)` will call or construct the replacement instead.
87
- *
88
- * If the replacement is omitted, null, or undefined, future calls will
89
- * invoke the original factory again.
90
- *
91
- * (Note: in all cases the replacement will not take effect if there's
92
- * already a cached singleton, so you may wish to call
93
- * {@link $cache.unset}() to ensure a future call is actually executed.)
94
- */
95
- replace(factory, replacement) {
96
- replacement != null && replacement !== factory ? factories.set(factory, replacement) : factories.delete(factory);
97
- }
98
- };
99
83
 
100
- export { $, $cache, expiring, fork, service };
84
+ export { $, expiring, fork, service };
package/dist/signals.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AnyFunction, O as OptionalCleanup, D as DisposeFn, L as SignalSource, Y as Yielding, S as Source, P as PlainFunction, a as Stream } from './types-pElgImr7.js';
2
- import { U as UntilMethod } from './sinks-B_LfTZgF.js';
1
+ import { A as AnyFunction, O as OptionalCleanup, D as DisposeFn, m as SignalSource, Y as Yielding, S as Source, P as PlainFunction, a as Stream } from './types-C3WWddF2.js';
2
+ import { U as UntilMethod } from './sinks-CoXxbJrs.js';
3
3
 
4
4
  /**
5
5
  * A decorator function that supports both TC39 and "legacy" decorator protocols
package/dist/signals.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { d as root, o as currentCell, g as getJob, m as must, L as currentJob, w as reject, b as resolve } from './jobutils-O9tOTNKC.mjs';
2
- import { C as Cell, r as ruleQueue, d as defaultQ, c as currentRule, p as perSignal, g as getCell } from './hooks-BnMYHRlM.mjs';
3
- export { a as CircularDependency, W as WriteConflict } from './hooks-BnMYHRlM.mjs';
4
- import { d as defer, C as CallableObject, c as apply, s as setMap, b as decorateMethod, i as isFunction, f as isPlainFunction, g as arrayEq } from './utils-BgqyDPjA.mjs';
5
- import { c as callOrWait } from './call-or-wait-CvOF0pao.mjs';
1
+ import { d as root, l as currentCell, g as getJob, m as must, P as currentJob, H as reject, r as resolve } from './jobutils-WMcB-H_8.mjs';
2
+ import { C as Cell, r as ruleQueue, d as defaultQ, c as currentRule, p as perSignal, g as getCell } from './hooks-SVgnmOfF.mjs';
3
+ export { a as CircularDependency, W as WriteConflict } from './hooks-SVgnmOfF.mjs';
4
+ import { d as defer, C as CallableObject, b as apply, s as setMap, a as decorateMethod, i as isFunction, f as isPlainFunction, g as arrayEq } from './utils-XKvfJLkI.mjs';
5
+ import { c as callOrWait } from './call-or-wait-DgI1Y5BE.mjs';
6
6
 
7
7
  class RF extends CallableObject {
8
8
  constructor(q) {
@@ -96,9 +96,12 @@ function fx(f, ...args) {
96
96
  let jobs, cell = Cell.mkCached(f);
97
97
  return () => {
98
98
  if (currentCell) {
99
- if (currentCell.isObserved())
99
+ if (currentCell.isObserved()) {
100
+ cell.isObserved() || (cell.validThrough = 0);
100
101
  cell.getValue();
102
+ }
101
103
  } else {
104
+ cell.isObserved() || (cell.validThrough = 0);
102
105
  if (!sosHas(jobs, getJob())) {
103
106
  const job = currentJob;
104
107
  jobs = sosAdd(jobs, job);
@@ -1,4 +1,4 @@
1
- import { h as Suspend, a as Stream, Y as Yielding, b as Sink, I as Inlet, K as Connection, i as RecalcSource } from './types-pElgImr7.js';
1
+ import { n as Suspend, Y as Yielding, a as Stream, b as Sink, I as Inlet, h as Connection, R as RecalcSource } from './types-C3WWddF2.js';
2
2
 
3
3
  /**
4
4
  * The result type returned from calls to {@link Each}.next()
@@ -204,4 +204,4 @@ declare function recalcWhen<T extends WeakKey>(key: T, factory: (key: T) => Reca
204
204
  */
205
205
  declare function isObserved(): boolean | undefined;
206
206
 
207
- export { type EachResult as E, type NextMethod as N, type UntilMethod as U, type Each as a, each as e, forEach as f, isObserved as i, next as n, recalcWhen as r };
207
+ export { type Each as E, type NextMethod as N, type UntilMethod as U, type EachResult as a, each as e, forEach as f, isObserved as i, next as n, recalcWhen as r };
@@ -914,4 +914,4 @@ interface Request<T> {
914
914
  */
915
915
  type RecalcSource = ((cb: () => void) => unknown);
916
916
 
917
- export { type AnyFunction as A, type Backpressure as B, type CleanupFn as C, type DisposeFn as D, ErrorResult as E, backpressure as F, type Throttle as G, type HandledError as H, type Inlet as I, type Job as J, type Connection as K, type SignalSource as L, IsStream as M, type Nothing as N, type OptionalCleanup as O, type PlainFunction as P, connect as Q, type Request as R, type Source as S, type Transformer as T, type UnhandledError as U, ValueResult as V, throttle as W, pipe as X, type Yielding as Y, compose as Z, into as _, type Stream as a, type Sink as b, type StartFn as c, type StartObj as d, type AsyncStart as e, type SyncStart as f, type JobIterator as g, type Suspend as h, type RecalcSource as i, reject as j, resolver as k, rejecter as l, CancelResult as m, noop as n, type JobResult as o, isCancel as p, isValue as q, resolve as r, isError as s, isUnhandled as t, isHandled as u, markHandled as v, getResult as w, fulfillPromise as x, propagateResult as y, CancelError as z };
917
+ export { type AnyFunction as A, type Backpressure as B, type CleanupFn as C, type DisposeFn as D, ErrorResult as E, isValue as F, markHandled as G, type HandledError as H, type Inlet as I, type Job as J, noop as K, pipe as L, propagateResult as M, type Nothing as N, type OptionalCleanup as O, type PlainFunction as P, reject as Q, type RecalcSource as R, type Source as S, type Transformer as T, type UnhandledError as U, ValueResult as V, rejecter as W, resolve as X, type Yielding as Y, resolver as Z, throttle as _, type Stream as a, type Sink as b, type StartFn as c, type StartObj as d, type AsyncStart as e, CancelError as f, CancelResult as g, type Connection as h, IsStream as i, type JobIterator as j, type JobResult as k, type Request as l, type SignalSource as m, type Suspend as n, type SyncStart as o, type Throttle as p, backpressure as q, compose as r, connect as s, fulfillPromise as t, getResult as u, into as v, isCancel as w, isError as x, isHandled as y, isUnhandled as z };
@@ -10,7 +10,7 @@ class _Batch {
10
10
  this._flags = 0 /* Unset */;
11
11
  this.q = /* @__PURE__ */ new Set();
12
12
  this._run = () => {
13
- this._flags &= ~2 /* Scheduled */;
13
+ this._flags &= -3 /* Scheduled */;
14
14
  this.flush();
15
15
  };
16
16
  /** Run all pending items */
@@ -24,7 +24,7 @@ class _Batch {
24
24
  try {
25
25
  this.reap(queue);
26
26
  } finally {
27
- this._flags &= ~1 /* Running */;
27
+ this._flags &= -2 /* Running */;
28
28
  !queue.size || this._flags & 2 /* Scheduled */ || this._sched();
29
29
  }
30
30
  };
@@ -123,4 +123,4 @@ function isGeneratorFunction(fn) {
123
123
  return isFunction(fn) && fn.prototype instanceof GeneratorBase;
124
124
  }
125
125
 
126
- export { CallableObject as C, GeneratorBase as G, isGeneratorFunction as a, decorateMethod as b, apply as c, defer as d, isClass as e, isPlainFunction as f, arrayEq as g, batch as h, isFunction as i, isArray as j, isPlainObject as k, call as l, setMap as s };
126
+ export { CallableObject as C, GeneratorBase as G, decorateMethod as a, apply as b, isClass as c, defer as d, isGeneratorFunction as e, isPlainFunction as f, arrayEq as g, batch as h, isFunction as i, call as j, isArray as k, isPlainObject as l, setMap as s };
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AnyFunction } from './types-pElgImr7.js';
1
+ import { A as AnyFunction } from './types-C3WWddF2.js';
2
2
 
3
3
  /**
4
4
  * A generic batch processing queue, implemented as a set. (So items are
package/dist/utils.mjs CHANGED
@@ -1 +1 @@
1
- export { C as CallableObject, G as GeneratorBase, c as apply, g as arrayEq, h as batch, l as call, b as decorateMethod, j as isArray, e as isClass, i as isFunction, a as isGeneratorFunction, f as isPlainFunction, k as isPlainObject, s as setMap } from './utils-BgqyDPjA.mjs';
1
+ export { C as CallableObject, G as GeneratorBase, b as apply, g as arrayEq, h as batch, j as call, a as decorateMethod, k as isArray, c as isClass, i as isFunction, e as isGeneratorFunction, f as isPlainFunction, l as isPlainObject, s as setMap } from './utils-XKvfJLkI.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uneventful",
3
- "version": "0.0.13",
3
+ "version": "0.0.16",
4
4
  "description": "Declarative, event-driven reactivity: signals, streams, structured concurrency, and easy resource cleanup",
5
5
  "keywords": [
6
6
  "signals",
@@ -84,7 +84,7 @@
84
84
  "chai-as-promised": "^7.1.1",
85
85
  "cross-env": "^7.0.3",
86
86
  "markdown-it-footnote": "^4.0.0",
87
- "mocha": "^10.2.0",
87
+ "mocha": "^10.8.2",
88
88
  "monkey-around": "^3",
89
89
  "pkgroll": "^2.1.1",
90
90
  "sinon": "^17.0.1",
@@ -92,7 +92,7 @@
92
92
  "ts-expect": "^1.3.0",
93
93
  "ts-node": "^10.9.1",
94
94
  "tsx": "^4.6.1",
95
- "typedoc": "pjeby/typedoc#no-merged-comments",
95
+ "typedoc": "^0.28.17",
96
96
  "typescript": "^5.9.3"
97
97
  }
98
98
  }