@zeix/cause-effect 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +30 -4
- package/index.dev.js +6 -2
- package/index.js +1 -1
- package/index.ts +2 -1
- package/package.json +3 -3
- package/src/nodes/effect.ts +65 -8
- package/test/effect.test.ts +88 -0
- package/types/index.d.ts +2 -2
- package/types/src/nodes/effect.d.ts +36 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Single-signal overload for `match()`**: `match(signal, handlers)` now accepts a bare signal (not wrapped in an array). The `ok` handler receives the resolved value directly as `(value: T)`, and `err` receives a single `Error` rather than `readonly Error[]`. The existing tuple form is unchanged. This eliminates the boilerplate of wrapping a single source in `[source]`, destructuring `values[0]` in `ok`, and unwrapping `errors[0]!` in `err`.
|
|
8
|
+
- **`SingleMatchHandlers<T>` type**: New exported type that describes the handler object for the single-signal overload. Counterpart to the existing `MatchHandlers<T>` for tuple usage.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Async handler documentation**: Added `@remarks` to the `match()` JSDoc and an expanded section in `README.md` clarifying that async `ok`/`err` handlers are intended for external side effects only (logging, DOM writes, analytics). Any async work that needs to drive reactive state should use a `Task` node, which receives an `AbortSignal` and is auto-cancelled on re-run. Documents the known limitation that rejected async handlers from stale (superseded) runs still call `err`, since the library cannot cancel operations it did not initiate.
|
|
13
|
+
|
|
3
14
|
## 1.0.2
|
|
4
15
|
|
|
5
16
|
### Added
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Cause & Effect
|
|
2
2
|
|
|
3
|
-
Version 1.0
|
|
3
|
+
Version 1.1.0
|
|
4
4
|
|
|
5
5
|
**Cause & Effect** is a reactive state management primitives library for TypeScript. It provides the foundational building blocks for managing complex, dynamic, composite, and asynchronous state — correctly and performantly — in a unified signal graph.
|
|
6
6
|
|
|
@@ -392,14 +392,40 @@ const userData = createTask(async (_, abort) => {
|
|
|
392
392
|
})
|
|
393
393
|
|
|
394
394
|
createEffect(() => {
|
|
395
|
-
match(
|
|
396
|
-
ok:
|
|
395
|
+
match(userData, {
|
|
396
|
+
ok: user => console.log('User:', user),
|
|
397
397
|
nil: () => console.log('Loading...'),
|
|
398
|
-
err:
|
|
398
|
+
err: error => console.error(error)
|
|
399
399
|
})
|
|
400
400
|
})
|
|
401
401
|
```
|
|
402
402
|
|
|
403
|
+
**When to make a handler async.** The `ok` (and `err`) handler may return a `Promise`. Use this for *external* side effects whose result does not need to drive reactive state — sending analytics, writing to IndexedDB, triggering a toast notification, or any fire-and-forget call. A cleanup function returned by the resolved Promise is registered and called synchronously before the next re-run.
|
|
404
|
+
|
|
405
|
+
**Do not set signal state inside an async handler.** If the async result needs to update the graph, model it as a `Task` instead. `Task` receives an `AbortSignal`, is auto-cancelled when its dependencies change, and exposes its pending / resolved / error states as first-class reactive values that compose naturally with `nil` and `err`.
|
|
406
|
+
|
|
407
|
+
```js
|
|
408
|
+
// ✗ Don't: async handler that writes back into the graph
|
|
409
|
+
createEffect(() => match(trigger, {
|
|
410
|
+
ok: async () => {
|
|
411
|
+
const data = await fetch('/api/data').then(r => r.json())
|
|
412
|
+
result.set(data) // ← side-channel write, not tracked, no cancellation
|
|
413
|
+
}
|
|
414
|
+
}))
|
|
415
|
+
|
|
416
|
+
// ✓ Do: derive the async value as a Task, read it in match()
|
|
417
|
+
const result = createTask(async (_, signal) =>
|
|
418
|
+
fetch('/api/data', { signal }).then(r => r.json()))
|
|
419
|
+
|
|
420
|
+
createEffect(() => match(result, {
|
|
421
|
+
ok: data => render(data),
|
|
422
|
+
nil: () => showSpinner(),
|
|
423
|
+
err: e => showError(e)
|
|
424
|
+
}))
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Stale-run rejections still reach `err`.** When a signal changes and the effect re-runs, the in-flight async handler from the previous run cannot be cancelled (the library did not initiate the underlying operation). If that stale operation eventually rejects, `err` will be called even though a newer run is already active. This is another reason to keep async handlers free of state writes — routing errors to `err` is safe when `err` is a pure side effect (logging, displaying a notification), but it becomes incorrect if `err` calls `.set()` on a signal that run 2 has already updated.
|
|
428
|
+
|
|
403
429
|
### Utilities
|
|
404
430
|
|
|
405
431
|
Polymorphic factories and type predicates for generic and library-author code.
|
package/index.dev.js
CHANGED
|
@@ -1229,10 +1229,14 @@ function createEffect(fn) {
|
|
|
1229
1229
|
runEffect(node);
|
|
1230
1230
|
return dispose;
|
|
1231
1231
|
}
|
|
1232
|
-
function match(
|
|
1232
|
+
function match(signalOrSignals, handlers) {
|
|
1233
1233
|
if (!activeOwner)
|
|
1234
1234
|
throw new RequiredOwnerError("match");
|
|
1235
|
-
const
|
|
1235
|
+
const isSingle = !Array.isArray(signalOrSignals);
|
|
1236
|
+
const signals = isSingle ? [signalOrSignals] : signalOrSignals;
|
|
1237
|
+
const { nil } = handlers;
|
|
1238
|
+
const ok = isSingle ? (values2) => handlers.ok(values2[0]) : (values2) => handlers.ok(values2);
|
|
1239
|
+
const err = isSingle && handlers.err ? (errors2) => handlers.err(errors2[0]) : handlers.err ?? console.error;
|
|
1236
1240
|
let errors;
|
|
1237
1241
|
let pending = false;
|
|
1238
1242
|
const values = new Array(signals.length);
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function g($){return typeof $==="function"}function o($){return g($)&&$.constructor.name==="AsyncFunction"}function X$($){return g($)&&$.constructor.name!=="AsyncFunction"}function f($,J){return Object.prototype.toString.call($)===`[object ${J}]`}function E($){return f($,"Object")}function f$($,J=(z)=>z!=null){return Array.isArray($)&&$.every(J)}function D$($){return typeof $==="string"?`"${$}"`:!!$&&typeof $==="object"?JSON.stringify($):String($)}class Z$ extends Error{constructor($){super(`[${$}] Circular dependency detected`);this.name="CircularDependencyError"}}class A$ extends TypeError{constructor($){super(`[${$}] Signal value cannot be null or undefined`);this.name="NullishSignalValueError"}}class i extends Error{constructor($){super(`[${$}] Signal value is unset`);this.name="UnsetSignalValueError"}}class W$ extends TypeError{constructor($,J){super(`[${$}] Signal value ${D$(J)} is invalid`);this.name="InvalidSignalValueError"}}class b$ extends TypeError{constructor($,J){super(`[${$}] Callback ${D$(J)} is invalid`);this.name="InvalidCallbackError"}}class P$ extends Error{constructor($){super(`[${$}] Signal is read-only`);this.name="ReadonlySignalError"}}class G$ extends Error{constructor($){super(`[${$}] Active owner is required`);this.name="RequiredOwnerError"}}class e extends Error{constructor($,J,z){super(`[${$}] Could not add key "${J}"${z?` with value ${JSON.stringify(z)}`:""} because it already exists`);this.name="DuplicateKeyError"}}function K($,J,z){if(J==null)throw new A$($);if(z&&!z(J))throw new W$($,J)}function j$($,J){if(J==null)throw new i($)}function S($,J,z=g){if(!z(J))throw new b$($,J)}var c="State",u="Memo",d="Task",s="Sensor",L="List",t="Collection",l="Store",r="Slot",p=0,$$=1,P=2,U$=4,b=8,m=null,_=null,C$=[],R=0,_$=!1,k=($,J)=>$===J,L$=($,J)=>!1;function g$($,J){let z=J.sourcesTail;if(z){let X=J.sources;while(X){if(X===$)return!0;if(X===z)break;X=X.nextSource}}return!1}function F($,J){let z=J.sourcesTail;if(z?.source===$)return;let X=null,j=J.flags&U$;if(j){if(X=z?z.nextSource:J.sources,X?.source===$){J.sourcesTail=X;return}}let B=$.sinksTail;if(B?.sink===J&&(!j||g$(B,J)))return;let D={source:$,sink:J,nextSource:X,prevSink:B,nextSink:null};if(J.sourcesTail=$.sinksTail=D,z)z.nextSource=D;else J.sources=D;if(B)B.nextSink=D;else $.sinks=D}function k$($){let{source:J,nextSource:z,nextSink:X,prevSink:j}=$;if(X)X.prevSink=j;else J.sinksTail=j;if(j)j.nextSink=X;else J.sinks=X;if(!J.sinks){if(J.stop)J.stop(),J.stop=void 0;if("sources"in J&&J.sources){let B=J;B.sourcesTail=null,H$(B)}}return z}function H$($){let J=$.sourcesTail,z=J?J.nextSource:$.sources;while(z)z=k$(z);if(J)J.nextSource=null;else $.sources=null}function x($,J=P){let z=$.flags;if("sinks"in $){if((z&(P|$$))>=J)return;if($.flags=z|J,"controller"in $&&$.controller)$.controller.abort(),$.controller=void 0;for(let X=$.sinks;X;X=X.nextSink)x(X.sink,$$)}else{if((z&(P|$$))>=J)return;let X=z&(P|$$);if($.flags=J,!X)C$.push($)}}function N$($,J){if($.equals($.value,J))return;$.value=J;for(let z=$.sinks;z;z=z.nextSink)x(z.sink);if(R===0)I()}function J$($,J){if(!$.cleanup)$.cleanup=J;else if(Array.isArray($.cleanup))$.cleanup.push(J);else $.cleanup=[$.cleanup,J]}function K$($){if(!$.cleanup)return;if(Array.isArray($.cleanup))for(let J=0;J<$.cleanup.length;J++)$.cleanup[J]();else $.cleanup();$.cleanup=null}function v$($){let J=m;m=$,$.sourcesTail=null,$.flags=U$;let z=!1;try{let X=$.fn($.value);if($.error||!$.equals(X,$.value))$.value=X,$.error=void 0,z=!0}catch(X){z=!0,$.error=X instanceof Error?X:Error(String(X))}finally{m=J,H$($)}if(z){for(let X=$.sinks;X;X=X.nextSink)if(X.sink.flags&$$)X.sink.flags|=P}$.flags=p}function c$($){$.controller?.abort();let J=new AbortController;$.controller=J,$.error=void 0;let z=m;m=$,$.sourcesTail=null,$.flags=U$;let X;try{X=$.fn($.value,J.signal)}catch(j){$.controller=void 0,$.error=j instanceof Error?j:Error(String(j));return}finally{m=z,H$($)}X.then((j)=>{if(J.signal.aborted)return;if($.controller=void 0,$.error||!$.equals(j,$.value)){$.value=j,$.error=void 0;for(let B=$.sinks;B;B=B.nextSink)x(B.sink);if(R===0)I()}},(j)=>{if(J.signal.aborted)return;$.controller=void 0;let B=j instanceof Error?j:Error(String(j));if(!$.error||B.name!==$.error.name||B.message!==$.error.message){$.error=B;for(let D=$.sinks;D;D=D.nextSink)x(D.sink);if(R===0)I()}}),$.flags=p}function T$($){K$($);let J=m,z=_;m=_=$,$.sourcesTail=null,$.flags=U$;try{let X=$.fn();if(typeof X==="function")J$($,X)}finally{m=J,_=z,H$($)}$.flags=p}function w($){if($.flags&$$)for(let J=$.sources;J;J=J.nextSource){if("fn"in J.source)w(J.source);if($.flags&P)break}if($.flags&U$)throw new Z$("controller"in $?d:("value"in $)?u:"Effect");if($.flags&P)if("controller"in $)c$($);else if("value"in $)v$($);else T$($);else $.flags=p}function I(){if(_$)return;_$=!0;try{for(let $=0;$<C$.length;$++){let J=C$[$];if(J.flags&(P|$$))w(J)}C$.length=0}finally{_$=!1}}function z$($){R++;try{$()}finally{if(R--,R===0)I()}}function v($){let J=m;m=null;try{return $()}finally{m=J}}function u$($){let J=_,z={cleanup:null};_=z;try{let X=$();if(typeof X==="function")J$(z,X);let j=()=>K$(z);if(J)J$(J,j);return j}finally{_=J}}function d$($){let J=_;_=null;try{return $()}finally{_=J}}function y($,J){K(c,$,J?.guard);let z={value:$,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard};return{[Symbol.toStringTag]:c,get(){if(m)F(z,m);return z.value},set(X){K(c,X,z.guard),N$(z,X)},update(X){S(c,X);let j=X(z.value);K(c,j,z.guard),N$(z,j)}}}function V$($){return f($,c)}function n($,J,z){if(Object.is($,J))return!0;if(typeof $!==typeof J)return!1;if($==null||typeof $!=="object"||J==null||typeof J!=="object")return!1;if(!z)z=new WeakSet;if(z.has($)||z.has(J))throw new Z$("isEqual");z.add($),z.add(J);try{let X=Array.isArray($);if(X!==Array.isArray(J))return!1;if(X){let j=$,B=J;if(j.length!==B.length)return!1;for(let D=0;D<j.length;D++)if(!n(j[D],B[D],z))return!1;return!0}if(E($)&&E(J)){let j=Object.keys($),B=Object.keys(J);if(j.length!==B.length)return!1;for(let D of j){if(!(D in J))return!1;if(!n($[D],J[D],z))return!1}return!0}return!1}finally{z.delete($),z.delete(J)}}function O$($,J){if($.length!==J.length)return!1;for(let z=0;z<$.length;z++)if($[z]!==J[z])return!1;return!0}function E$($){let J=0,z=typeof $==="function";return[typeof $==="string"?()=>`${$}${J++}`:z?(X)=>$(X)||String(J++):()=>String(J++),z]}function s$($,J,z,X,j){let B=new WeakSet,D={},M={},C={},N=[],Q=!1,W=new Map;for(let q=0;q<$.length;q++){let Z=z[q],H=$[q];if(Z&&H!==void 0)W.set(Z,H)}let G=new Set;for(let q=0;q<J.length;q++){let Z=J[q];if(Z===void 0)continue;let H=j?X(Z):z[q]??X(Z);if(G.has(H))throw new e(L,H,Z);if(N.push(H),G.add(H),!W.has(H))D[H]=Z,Q=!0;else if(!n(W.get(H),Z,B))M[H]=Z,Q=!0}for(let[q]of W)if(!G.has(q))C[q]=null,Q=!0;if(!Q&&!O$(z,N))Q=!0;return{add:D,change:M,remove:C,newKeys:N,changed:Q}}function Q$($,J){K(L,$,Array.isArray);let z=new Map,X=[],[j,B]=E$(J?.keyConfig),D=()=>X.map((Z)=>z.get(Z)?.get()).filter((Z)=>Z!==void 0),M={fn:D,value:$,flags:P,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},C=(Z)=>{let H={};for(let U=0;U<Z.length;U++){let V=Z[U];if(V===void 0)continue;let O=X[U];if(!O)O=j(V),X[U]=O;H[O]=V}return H},N=(Z)=>{let H=!1;for(let U in Z.add){let V=Z.add[U];K(`${L} item for key "${U}"`,V),z.set(U,y(V)),H=!0}if(Object.keys(Z.change).length)z$(()=>{for(let U in Z.change){let V=Z.change[U];K(`${L} item for key "${U}"`,V);let O=z.get(U);if(O)O.set(V)}});for(let U in Z.remove){z.delete(U);let V=X.indexOf(U);if(V!==-1)X.splice(V,1);H=!0}if(H)M.flags|=b;return Z.changed},Q=J?.watched,W=Q?()=>{if(m){if(!M.sinks)M.stop=Q();F(M,m)}}:()=>{if(m)F(M,m)},G=C($);for(let Z in G){let H=G[Z];K(`${L} item for key "${Z}"`,H),z.set(Z,y(H))}M.value=$,M.flags=0;let q={[Symbol.toStringTag]:L,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of X){let H=z.get(Z);if(H)yield H}},get length(){return W(),X.length},get(){if(W(),M.sources){if(M.flags){let Z=M.flags&b;if(M.value=v(D),Z){if(M.flags=P,w(M),M.error)throw M.error}else M.flags=p}}else if(w(M),M.error)throw M.error;return M.value},set(Z){let H=M.flags&P?D():M.value,U=s$(H,Z,X,j,B);if(U.changed){X=U.newKeys,N(U),M.flags|=P;for(let V=M.sinks;V;V=V.nextSink)x(V.sink);if(R===0)I()}},update(Z){q.set(Z(q.get()))},at(Z){let H=X[Z];return H!==void 0?z.get(H):void 0},keys(){return W(),X.values()},byKey(Z){return z.get(Z)},keyAt(Z){return X[Z]},indexOfKey(Z){return X.indexOf(Z)},add(Z){let H=j(Z);if(z.has(H))throw new e(L,H,Z);if(!X.includes(H))X.push(H);K(`${L} item for key "${H}"`,Z),z.set(H,y(Z)),M.flags|=P|b;for(let U=M.sinks;U;U=U.nextSink)x(U.sink);if(R===0)I();return H},remove(Z){let H=typeof Z==="number"?X[Z]:Z;if(H===void 0)return;if(z.delete(H)){let V=typeof Z==="number"?Z:X.indexOf(H);if(V>=0)X.splice(V,1);M.flags|=P|b;for(let O=M.sinks;O;O=O.nextSink)x(O.sink);if(R===0)I()}},replace(Z,H){let U=z.get(Z);if(!U)return;if(K(`${L} item for key "${Z}"`,H),U.get()===H)return;U.set(H),M.flags|=P;for(let V=M.sinks;V;V=V.nextSink)x(V.sink);if(R===0)I()},sort(Z){let U=X.map((V)=>[V,z.get(V)?.get()]).sort(g(Z)?(V,O)=>Z(V[1],O[1]):(V,O)=>String(V[1]).localeCompare(String(O[1]))).map(([V])=>V);if(!O$(X,U)){X=U,M.flags|=P;for(let V=M.sinks;V;V=V.nextSink)x(V.sink);if(R===0)I()}},splice(Z,H,...U){let V=X.length,O=Z<0?Math.max(0,V+Z):Math.min(Z,V),Y=Math.max(0,Math.min(H??Math.max(0,V-Math.max(0,O)),V-O)),A={},T={};for(let h=0;h<Y;h++){let a=O+h,Y$=X[a];if(Y$){let y$=z.get(Y$);if(y$)T[Y$]=y$.get()}}let w$=X.slice(0,O);for(let h of U){let a=j(h);if(z.has(a)&&!(a in T))throw new e(L,a,h);w$.push(a),A[a]=h}w$.push(...X.slice(O+Y));let h$=!!(Object.keys(A).length||Object.keys(T).length);if(h$){N({add:A,change:{},remove:T,changed:h$}),X=w$,M.flags|=P;for(let h=M.sinks;h;h=h.nextSink)x(h.sink);if(R===0)I()}return Object.values(T)},deriveCollection(Z){return x$(q,Z)}};return q}function R$($){return f($,L)}function B$($,J){if(S(u,$,X$),J?.value!==void 0)K(u,J.value,J?.guard);let z={fn:$,value:J?.value,flags:P,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0,stop:void 0},X=J?.watched,j=X?()=>{if(m){if(!z.sinks)z.stop=X(()=>{if(x(z),R===0)I()});F(z,m)}}:()=>{if(m)F(z,m)};return{[Symbol.toStringTag]:u,get(){if(j(),w(z),z.error)throw z.error;return j$(u,z.value),z.value}}}function S$($){return f($,u)}function q$($,J){if(S(d,$,o),J?.value!==void 0)K(d,J.value,J?.guard);let z={fn:$,value:J?.value,sources:null,sourcesTail:null,sinks:null,sinksTail:null,flags:P,equals:J?.equals??k,controller:void 0,error:void 0,stop:void 0},X=J?.watched,j=X?()=>{if(m){if(!z.sinks)z.stop=X(()=>{if(x(z),R===0)I()});F(z,m)}}:()=>{if(m)F(z,m)};return{[Symbol.toStringTag]:d,get(){if(j(),w(z),z.error)throw z.error;return j$(d,z.value),z.value},isPending(){return!!z.controller},abort(){z.controller?.abort(),z.controller=void 0}}}function p$($){return f($,d)}function x$($,J){S(t,J);let z=o(J),X=new Map,j=[],B=(q)=>{let Z=z?q$(async(H,U)=>{let V=$.byKey(q)?.get();if(V==null)return H;return J(V,U)}):B$(()=>{let H=$.byKey(q)?.get();if(H==null)return;return J(H)});X.set(q,Z)};function D(q){if(!O$(j,q)){let Z=new Set(j),H=new Set(q);for(let U of j)if(!H.has(U))X.delete(U);for(let U of q)if(!Z.has(U))B(U);j=q,N.flags|=b}}function M(){D(Array.from($.keys()));let q=[];for(let Z of j)try{let H=X.get(Z)?.get();if(H!=null)q.push(H)}catch(H){if(!(H instanceof i))throw H}return q}let N={fn:M,value:[],flags:P,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:(q,Z)=>{if(q.length!==Z.length)return!1;for(let H=0;H<q.length;H++)if(q[H]!==Z[H])return!1;return!0},error:void 0};function Q(){if(N.sources){if(N.flags)if(N.value=v(M),N.flags&b){if(N.flags=P,w(N),N.error)throw N.error}else N.flags=p}else if(N.sinks){if(w(N),N.error)throw N.error}else N.value=v(M)}let W=Array.from(v(()=>$.keys()));for(let q of W)B(q);j=W;let G={[Symbol.toStringTag]:t,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let q of j){let Z=X.get(q);if(Z)yield Z}},get length(){if(m)F(N,m);return Q(),j.length},keys(){if(m)F(N,m);return Q(),j.values()},get(){if(m)F(N,m);return Q(),N.value},at(q){let Z=j[q];return Z!==void 0?X.get(Z):void 0},byKey(q){return X.get(q)},keyAt(q){return j[q]},indexOfKey(q){return j.indexOf(q)},deriveCollection(q){return x$(G,q)}};return G}function t$($,J){let z=J?.value??[];if(z.length)K(t,z,Array.isArray);S(t,$,X$);let X=new Map,j=[],B=new Map,[D,M]=E$(J?.keyConfig),C=(Z)=>B.get(Z)??(M?D(Z):void 0),N=J?.createItem??y;function Q(){let Z=[];for(let H of j)try{let U=X.get(H)?.get();if(U!=null)Z.push(U)}catch(U){if(!(U instanceof i))throw U}return Z}let W={fn:Q,value:z,flags:P,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:L$,error:void 0};for(let Z of z){let H=D(Z);X.set(H,N(Z)),B.set(Z,H),j.push(H)}W.value=z,W.flags=P;function G(){if(m){if(!W.sinks)W.stop=$((Z)=>{let{add:H,change:U,remove:V}=Z;if(!H?.length&&!U?.length&&!V?.length)return;let O=!1;z$(()=>{if(H)for(let Y of H){let A=D(Y);if(X.set(A,N(Y)),B.set(Y,A),!j.includes(A))j.push(A);O=!0}if(U)for(let Y of U){let A=C(Y);if(!A)continue;let T=X.get(A);if(T&&V$(T))B.delete(T.get()),T.set(Y),B.set(Y,A)}if(V)for(let Y of V){let A=C(Y);if(!A)continue;B.delete(Y),X.delete(A);let T=j.indexOf(A);if(T!==-1)j.splice(T,1);O=!0}W.flags=P|(O?b:0);for(let Y=W.sinks;Y;Y=Y.nextSink)x(Y.sink)})});F(W,m)}}let q={[Symbol.toStringTag]:t,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of j){let H=X.get(Z);if(H)yield H}},get length(){return G(),j.length},keys(){return G(),j.values()},get(){if(G(),W.sources){if(W.flags){let Z=W.flags&b;if(W.value=v(Q),Z){if(W.flags=P,w(W),W.error)throw W.error}else W.flags=p}}else if(w(W),W.error)throw W.error;return W.value},at(Z){let H=j[Z];return H!==void 0?X.get(H):void 0},byKey(Z){return X.get(Z)},keyAt(Z){return j[Z]},indexOfKey(Z){return j.indexOf(Z)},deriveCollection(Z){return x$(q,Z)}};return q}function l$($){return f($,t)}function r$($){S("Effect",$);let J={fn:$,flags:P,sources:null,sourcesTail:null,cleanup:null},z=()=>{K$(J),J.fn=void 0,J.flags=p,J.sourcesTail=null,H$(J)};if(_)J$(_,z);return T$(J),z}function o$($,J){if(!_)throw new G$("match");let{ok:z,err:X=console.error,nil:j}=J,B,D=!1,M=Array($.length);for(let N=0;N<$.length;N++)try{M[N]=$[N].get()}catch(Q){if(Q instanceof i){D=!0;continue}if(!B)B=[];B.push(Q instanceof Error?Q:Error(String(Q)))}let C;try{if(D)C=j?.();else if(B)C=X(B);else C=z(M)}catch(N){X([N instanceof Error?N:Error(String(N))])}if(typeof C==="function")return C;if(C instanceof Promise){let N=_,Q=new AbortController;J$(N,()=>Q.abort()),C.then((W)=>{if(!Q.signal.aborted&&typeof W==="function")J$(N,W)}).catch((W)=>{X([W instanceof Error?W:Error(String(W))])})}}function i$($,J){if(S(s,$,X$),J?.value!==void 0)K(s,J.value,J?.guard);let z={value:J?.value,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard,stop:void 0};return{[Symbol.toStringTag]:s,get(){if(m){if(!z.sinks)z.stop=$((X)=>{K(s,X,z.guard),N$(z,X)});F(z,m)}return j$(s,z.value),z.value}}}function n$($){return f($,s)}function a$($,J){let z=E($)||Array.isArray($),X=E(J)||Array.isArray(J);if(!z||!X){let W=!Object.is($,J);return{changed:W,add:W&&X?J:{},change:{},remove:W&&z?$:{}}}let j=new WeakSet,B={},D={},M={},C=!1,N=Object.keys($),Q=Object.keys(J);for(let W of Q)if(W in $){if(!n($[W],J[W],j))D[W]=J[W],C=!0}else B[W]=J[W],C=!0;for(let W of N)if(!(W in J))M[W]=void 0,C=!0;return{add:B,change:D,remove:M,changed:C}}function m$($,J){K(l,$,E);let z=new Map,X=(Q,W)=>{if(K(`${l} for key "${Q}"`,W),Array.isArray(W))z.set(Q,Q$(W));else if(E(W))z.set(Q,m$(W));else z.set(Q,y(W))},j=()=>{let Q={};return z.forEach((W,G)=>{Q[G]=W.get()}),Q},B={fn:j,value:$,flags:P,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},D=(Q)=>{let W=!1;for(let G in Q.add)X(G,Q.add[G]),W=!0;if(Object.keys(Q.change).length)z$(()=>{for(let G in Q.change){let q=Q.change[G];K(`${l} for key "${G}"`,q);let Z=z.get(G);if(Z)if(E(q)!==F$(Z))X(G,q),W=!0;else Z.set(q)}});for(let G in Q.remove)z.delete(G),W=!0;if(W)B.flags|=b;return Q.changed},M=J?.watched,C=M?()=>{if(m){if(!B.sinks)B.stop=M();F(B,m)}}:()=>{if(m)F(B,m)};for(let Q of Object.keys($))X(Q,$[Q]);let N={[Symbol.toStringTag]:l,[Symbol.isConcatSpreadable]:!1,*[Symbol.iterator](){for(let Q of Array.from(z.keys())){let W=z.get(Q);if(W)yield[Q,W]}},keys(){return C(),z.keys()},byKey(Q){return z.get(Q)},get(){if(C(),B.sources){if(B.flags){let Q=B.flags&b;if(B.value=v(j),Q){if(B.flags=P,w(B),B.error)throw B.error}else B.flags=p}}else if(w(B),B.error)throw B.error;return B.value},set(Q){let W=B.flags&P?j():B.value,G=a$(W,Q);if(D(G)){B.flags|=P;for(let q=B.sinks;q;q=q.nextSink)x(q.sink);if(R===0)I()}},update(Q){N.set(Q(N.get()))},add(Q,W){if(z.has(Q))throw new e(l,Q,W);X(Q,W),B.flags|=P|b;for(let G=B.sinks;G;G=G.nextSink)x(G.sink);if(R===0)I();return Q},remove(Q){if(z.delete(Q)){B.flags|=P|b;for(let G=B.sinks;G;G=G.nextSink)x(G.sink);if(R===0)I()}}};return new Proxy(N,{get(Q,W){if(W in Q)return Reflect.get(Q,W);if(typeof W!=="symbol")return Q.byKey(W)},has(Q,W){if(W in Q)return!0;return Q.byKey(String(W))!==void 0},ownKeys(Q){return Array.from(Q.keys())},getOwnPropertyDescriptor(Q,W){if(W in Q)return Reflect.getOwnPropertyDescriptor(Q,W);if(typeof W==="symbol")return;let G=Q.byKey(String(W));return G?{enumerable:!0,configurable:!0,writable:!0,value:G}:void 0}})}function F$($){return f($,l)}function e$($,J){return o($)?q$($,J):B$($,J)}function $J($){if(M$($))return $;if($==null)throw new W$("createSignal",$);if(o($))return q$($);if(g($))return B$($);if(f$($))return Q$($);if(E($))return m$($);return y($)}function JJ($){if(I$($))return $;if($==null||g($)||M$($))throw new W$("createMutableSignal",$);if(f$($))return Q$($);if(E($))return m$($);return y($)}function zJ($){return S$($)||p$($)}function M$($){let J=[c,u,d,s,r,L,t,l],z=Object.prototype.toString.call($).slice(8,-1);return J.includes(z)}function I$($){return V$($)||F$($)||R$($)}function XJ($,J){K(r,$,M$);let z=$,X=J?.guard,j={fn:()=>z.get(),value:void 0,flags:P,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0},B=()=>{if(m)F(j,m);if(w(j),j.error)throw j.error;return j.value},D=(C)=>{if(!I$(z))throw new P$(r);K(r,C,X),z.set(C)},M=(C)=>{K(r,C,M$),z=C,j.flags|=P;for(let N=j.sinks;N;N=N.nextSink)x(N.sink);if(R===0)I()};return{[Symbol.toStringTag]:r,configurable:!0,enumerable:!0,get:B,set:D,replace:M,current:()=>z}}function ZJ($){return f($,r)}export{D$ as valueString,v as untrack,d$ as unown,o$ as match,p$ as isTask,F$ as isStore,V$ as isState,ZJ as isSlot,M$ as isSignal,n$ as isSensor,E as isRecord,f as isObjectOfType,I$ as isMutableSignal,S$ as isMemo,R$ as isList,g as isFunction,n as isEqual,zJ as isComputed,l$ as isCollection,o as isAsyncFunction,q$ as createTask,m$ as createStore,y as createState,XJ as createSlot,$J as createSignal,i$ as createSensor,u$ as createScope,JJ as createMutableSignal,B$ as createMemo,Q$ as createList,r$ as createEffect,e$ as createComputed,t$ as createCollection,z$ as batch,i as UnsetSignalValueError,L$ as SKIP_EQUALITY,G$ as RequiredOwnerError,P$ as ReadonlySignalError,A$ as NullishSignalValueError,W$ as InvalidSignalValueError,b$ as InvalidCallbackError,Z$ as CircularDependencyError};
|
|
1
|
+
function g($){return typeof $==="function"}function o($){return g($)&&$.constructor.name==="AsyncFunction"}function X$($){return g($)&&$.constructor.name!=="AsyncFunction"}function Y($,J){return Object.prototype.toString.call($)===`[object ${J}]`}function E($){return Y($,"Object")}function Y$($,J=(z)=>z!=null){return Array.isArray($)&&$.every(J)}function D$($){return typeof $==="string"?`"${$}"`:!!$&&typeof $==="object"?JSON.stringify($):String($)}class Z$ extends Error{constructor($){super(`[${$}] Circular dependency detected`);this.name="CircularDependencyError"}}class A$ extends TypeError{constructor($){super(`[${$}] Signal value cannot be null or undefined`);this.name="NullishSignalValueError"}}class i extends Error{constructor($){super(`[${$}] Signal value is unset`);this.name="UnsetSignalValueError"}}class j$ extends TypeError{constructor($,J){super(`[${$}] Signal value ${D$(J)} is invalid`);this.name="InvalidSignalValueError"}}class b$ extends TypeError{constructor($,J){super(`[${$}] Callback ${D$(J)} is invalid`);this.name="InvalidCallbackError"}}class P$ extends Error{constructor($){super(`[${$}] Signal is read-only`);this.name="ReadonlySignalError"}}class G$ extends Error{constructor($){super(`[${$}] Active owner is required`);this.name="RequiredOwnerError"}}class e extends Error{constructor($,J,z){super(`[${$}] Could not add key "${J}"${z?` with value ${JSON.stringify(z)}`:""} because it already exists`);this.name="DuplicateKeyError"}}function C($,J,z){if(J==null)throw new A$($);if(z&&!z(J))throw new j$($,J)}function W$($,J){if(J==null)throw new i($)}function S($,J,z=g){if(!z(J))throw new b$($,J)}var c="State",u="Memo",d="Task",t="Sensor",L="List",s="Collection",r="Store",l="Slot",p=0,$$=1,G=2,U$=4,b=8,V=null,_=null,C$=[],O=0,_$=!1,k=($,J)=>$===J,L$=($,J)=>!1;function g$($,J){let z=J.sourcesTail;if(z){let X=J.sources;while(X){if(X===$)return!0;if(X===z)break;X=X.nextSource}}return!1}function F($,J){let z=J.sourcesTail;if(z?.source===$)return;let X=null,W=J.flags&U$;if(W){if(X=z?z.nextSource:J.sources,X?.source===$){J.sourcesTail=X;return}}let B=$.sinksTail;if(B?.sink===J&&(!W||g$(B,J)))return;let D={source:$,sink:J,nextSource:X,prevSink:B,nextSink:null};if(J.sourcesTail=$.sinksTail=D,z)z.nextSource=D;else J.sources=D;if(B)B.nextSink=D;else $.sinks=D}function k$($){let{source:J,nextSource:z,nextSink:X,prevSink:W}=$;if(X)X.prevSink=W;else J.sinksTail=W;if(W)W.nextSink=X;else J.sinks=X;if(!J.sinks){if(J.stop)J.stop(),J.stop=void 0;if("sources"in J&&J.sources){let B=J;B.sourcesTail=null,H$(B)}}return z}function H$($){let J=$.sourcesTail,z=J?J.nextSource:$.sources;while(z)z=k$(z);if(J)J.nextSource=null;else $.sources=null}function x($,J=G){let z=$.flags;if("sinks"in $){if((z&(G|$$))>=J)return;if($.flags=z|J,"controller"in $&&$.controller)$.controller.abort(),$.controller=void 0;for(let X=$.sinks;X;X=X.nextSink)x(X.sink,$$)}else{if((z&(G|$$))>=J)return;let X=z&(G|$$);if($.flags=J,!X)C$.push($)}}function N$($,J){if($.equals($.value,J))return;$.value=J;for(let z=$.sinks;z;z=z.nextSink)x(z.sink);if(O===0)w()}function J$($,J){if(!$.cleanup)$.cleanup=J;else if(Array.isArray($.cleanup))$.cleanup.push(J);else $.cleanup=[$.cleanup,J]}function K$($){if(!$.cleanup)return;if(Array.isArray($.cleanup))for(let J=0;J<$.cleanup.length;J++)$.cleanup[J]();else $.cleanup();$.cleanup=null}function v$($){let J=V;V=$,$.sourcesTail=null,$.flags=U$;let z=!1;try{let X=$.fn($.value);if($.error||!$.equals(X,$.value))$.value=X,$.error=void 0,z=!0}catch(X){z=!0,$.error=X instanceof Error?X:Error(String(X))}finally{V=J,H$($)}if(z){for(let X=$.sinks;X;X=X.nextSink)if(X.sink.flags&$$)X.sink.flags|=G}$.flags=p}function c$($){$.controller?.abort();let J=new AbortController;$.controller=J,$.error=void 0;let z=V;V=$,$.sourcesTail=null,$.flags=U$;let X;try{X=$.fn($.value,J.signal)}catch(W){$.controller=void 0,$.error=W instanceof Error?W:Error(String(W));return}finally{V=z,H$($)}X.then((W)=>{if(J.signal.aborted)return;if($.controller=void 0,$.error||!$.equals(W,$.value)){$.value=W,$.error=void 0;for(let B=$.sinks;B;B=B.nextSink)x(B.sink);if(O===0)w()}},(W)=>{if(J.signal.aborted)return;$.controller=void 0;let B=W instanceof Error?W:Error(String(W));if(!$.error||B.name!==$.error.name||B.message!==$.error.message){$.error=B;for(let D=$.sinks;D;D=D.nextSink)x(D.sink);if(O===0)w()}}),$.flags=p}function T$($){K$($);let J=V,z=_;V=_=$,$.sourcesTail=null,$.flags=U$;try{let X=$.fn();if(typeof X==="function")J$($,X)}finally{V=J,_=z,H$($)}$.flags=p}function I($){if($.flags&$$)for(let J=$.sources;J;J=J.nextSource){if("fn"in J.source)I(J.source);if($.flags&G)break}if($.flags&U$)throw new Z$("controller"in $?d:("value"in $)?u:"Effect");if($.flags&G)if("controller"in $)c$($);else if("value"in $)v$($);else T$($);else $.flags=p}function w(){if(_$)return;_$=!0;try{for(let $=0;$<C$.length;$++){let J=C$[$];if(J.flags&(G|$$))I(J)}C$.length=0}finally{_$=!1}}function z$($){O++;try{$()}finally{if(O--,O===0)w()}}function v($){let J=V;V=null;try{return $()}finally{V=J}}function u$($){let J=_,z={cleanup:null};_=z;try{let X=$();if(typeof X==="function")J$(z,X);let W=()=>K$(z);if(J)J$(J,W);return W}finally{_=J}}function d$($){let J=_;_=null;try{return $()}finally{_=J}}function y($,J){C(c,$,J?.guard);let z={value:$,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard};return{[Symbol.toStringTag]:c,get(){if(V)F(z,V);return z.value},set(X){C(c,X,z.guard),N$(z,X)},update(X){S(c,X);let W=X(z.value);C(c,W,z.guard),N$(z,W)}}}function V$($){return Y($,c)}function n($,J,z){if(Object.is($,J))return!0;if(typeof $!==typeof J)return!1;if($==null||typeof $!=="object"||J==null||typeof J!=="object")return!1;if(!z)z=new WeakSet;if(z.has($)||z.has(J))throw new Z$("isEqual");z.add($),z.add(J);try{let X=Array.isArray($);if(X!==Array.isArray(J))return!1;if(X){let W=$,B=J;if(W.length!==B.length)return!1;for(let D=0;D<W.length;D++)if(!n(W[D],B[D],z))return!1;return!0}if(E($)&&E(J)){let W=Object.keys($),B=Object.keys(J);if(W.length!==B.length)return!1;for(let D of W){if(!(D in J))return!1;if(!n($[D],J[D],z))return!1}return!0}return!1}finally{z.delete($),z.delete(J)}}function R$($,J){if($.length!==J.length)return!1;for(let z=0;z<$.length;z++)if($[z]!==J[z])return!1;return!0}function E$($){let J=0,z=typeof $==="function";return[typeof $==="string"?()=>`${$}${J++}`:z?(X)=>$(X)||String(J++):()=>String(J++),z]}function t$($,J,z,X,W){let B=new WeakSet,D={},M={},R={},P=[],Q=!1,j=new Map;for(let q=0;q<$.length;q++){let Z=z[q],H=$[q];if(Z&&H!==void 0)j.set(Z,H)}let m=new Set;for(let q=0;q<J.length;q++){let Z=J[q];if(Z===void 0)continue;let H=W?X(Z):z[q]??X(Z);if(m.has(H))throw new e(L,H,Z);if(P.push(H),m.add(H),!j.has(H))D[H]=Z,Q=!0;else if(!n(j.get(H),Z,B))M[H]=Z,Q=!0}for(let[q]of j)if(!m.has(q))R[q]=null,Q=!0;if(!Q&&!R$(z,P))Q=!0;return{add:D,change:M,remove:R,newKeys:P,changed:Q}}function Q$($,J){C(L,$,Array.isArray);let z=new Map,X=[],[W,B]=E$(J?.keyConfig),D=()=>X.map((Z)=>z.get(Z)?.get()).filter((Z)=>Z!==void 0),M={fn:D,value:$,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},R=(Z)=>{let H={};for(let U=0;U<Z.length;U++){let N=Z[U];if(N===void 0)continue;let K=X[U];if(!K)K=W(N),X[U]=K;H[K]=N}return H},P=(Z)=>{let H=!1;for(let U in Z.add){let N=Z.add[U];C(`${L} item for key "${U}"`,N),z.set(U,y(N)),H=!0}if(Object.keys(Z.change).length)z$(()=>{for(let U in Z.change){let N=Z.change[U];C(`${L} item for key "${U}"`,N);let K=z.get(U);if(K)K.set(N)}});for(let U in Z.remove){z.delete(U);let N=X.indexOf(U);if(N!==-1)X.splice(N,1);H=!0}if(H)M.flags|=b;return Z.changed},Q=J?.watched,j=Q?()=>{if(V){if(!M.sinks)M.stop=Q();F(M,V)}}:()=>{if(V)F(M,V)},m=R($);for(let Z in m){let H=m[Z];C(`${L} item for key "${Z}"`,H),z.set(Z,y(H))}M.value=$,M.flags=0;let q={[Symbol.toStringTag]:L,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of X){let H=z.get(Z);if(H)yield H}},get length(){return j(),X.length},get(){if(j(),M.sources){if(M.flags){let Z=M.flags&b;if(M.value=v(D),Z){if(M.flags=G,I(M),M.error)throw M.error}else M.flags=p}}else if(I(M),M.error)throw M.error;return M.value},set(Z){let H=M.flags&G?D():M.value,U=t$(H,Z,X,W,B);if(U.changed){X=U.newKeys,P(U),M.flags|=G;for(let N=M.sinks;N;N=N.nextSink)x(N.sink);if(O===0)w()}},update(Z){q.set(Z(q.get()))},at(Z){let H=X[Z];return H!==void 0?z.get(H):void 0},keys(){return j(),X.values()},byKey(Z){return z.get(Z)},keyAt(Z){return X[Z]},indexOfKey(Z){return X.indexOf(Z)},add(Z){let H=W(Z);if(z.has(H))throw new e(L,H,Z);if(!X.includes(H))X.push(H);C(`${L} item for key "${H}"`,Z),z.set(H,y(Z)),M.flags|=G|b;for(let U=M.sinks;U;U=U.nextSink)x(U.sink);if(O===0)w();return H},remove(Z){let H=typeof Z==="number"?X[Z]:Z;if(H===void 0)return;if(z.delete(H)){let N=typeof Z==="number"?Z:X.indexOf(H);if(N>=0)X.splice(N,1);M.flags|=G|b;for(let K=M.sinks;K;K=K.nextSink)x(K.sink);if(O===0)w()}},replace(Z,H){let U=z.get(Z);if(!U)return;if(C(`${L} item for key "${Z}"`,H),U.get()===H)return;U.set(H),M.flags|=G;for(let N=M.sinks;N;N=N.nextSink)x(N.sink);if(O===0)w()},sort(Z){let U=X.map((N)=>[N,z.get(N)?.get()]).sort(g(Z)?(N,K)=>Z(N[1],K[1]):(N,K)=>String(N[1]).localeCompare(String(K[1]))).map(([N])=>N);if(!R$(X,U)){X=U,M.flags|=G;for(let N=M.sinks;N;N=N.nextSink)x(N.sink);if(O===0)w()}},splice(Z,H,...U){let N=X.length,K=Z<0?Math.max(0,N+Z):Math.min(Z,N),f=Math.max(0,Math.min(H??Math.max(0,N-Math.max(0,K)),N-K)),A={},T={};for(let h=0;h<f;h++){let a=K+h,f$=X[a];if(f$){let y$=z.get(f$);if(y$)T[f$]=y$.get()}}let I$=X.slice(0,K);for(let h of U){let a=W(h);if(z.has(a)&&!(a in T))throw new e(L,a,h);I$.push(a),A[a]=h}I$.push(...X.slice(K+f));let h$=!!(Object.keys(A).length||Object.keys(T).length);if(h$){P({add:A,change:{},remove:T,changed:h$}),X=I$,M.flags|=G;for(let h=M.sinks;h;h=h.nextSink)x(h.sink);if(O===0)w()}return Object.values(T)},deriveCollection(Z){return x$(q,Z)}};return q}function O$($){return Y($,L)}function B$($,J){if(S(u,$,X$),J?.value!==void 0)C(u,J.value,J?.guard);let z={fn:$,value:J?.value,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0,stop:void 0},X=J?.watched,W=X?()=>{if(V){if(!z.sinks)z.stop=X(()=>{if(x(z),O===0)w()});F(z,V)}}:()=>{if(V)F(z,V)};return{[Symbol.toStringTag]:u,get(){if(W(),I(z),z.error)throw z.error;return W$(u,z.value),z.value}}}function S$($){return Y($,u)}function q$($,J){if(S(d,$,o),J?.value!==void 0)C(d,J.value,J?.guard);let z={fn:$,value:J?.value,sources:null,sourcesTail:null,sinks:null,sinksTail:null,flags:G,equals:J?.equals??k,controller:void 0,error:void 0,stop:void 0},X=J?.watched,W=X?()=>{if(V){if(!z.sinks)z.stop=X(()=>{if(x(z),O===0)w()});F(z,V)}}:()=>{if(V)F(z,V)};return{[Symbol.toStringTag]:d,get(){if(W(),I(z),z.error)throw z.error;return W$(d,z.value),z.value},isPending(){return!!z.controller},abort(){z.controller?.abort(),z.controller=void 0}}}function p$($){return Y($,d)}function x$($,J){S(s,J);let z=o(J),X=new Map,W=[],B=(q)=>{let Z=z?q$(async(H,U)=>{let N=$.byKey(q)?.get();if(N==null)return H;return J(N,U)}):B$(()=>{let H=$.byKey(q)?.get();if(H==null)return;return J(H)});X.set(q,Z)};function D(q){if(!R$(W,q)){let Z=new Set(W),H=new Set(q);for(let U of W)if(!H.has(U))X.delete(U);for(let U of q)if(!Z.has(U))B(U);W=q,P.flags|=b}}function M(){D(Array.from($.keys()));let q=[];for(let Z of W)try{let H=X.get(Z)?.get();if(H!=null)q.push(H)}catch(H){if(!(H instanceof i))throw H}return q}let P={fn:M,value:[],flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:(q,Z)=>{if(q.length!==Z.length)return!1;for(let H=0;H<q.length;H++)if(q[H]!==Z[H])return!1;return!0},error:void 0};function Q(){if(P.sources){if(P.flags)if(P.value=v(M),P.flags&b){if(P.flags=G,I(P),P.error)throw P.error}else P.flags=p}else if(P.sinks){if(I(P),P.error)throw P.error}else P.value=v(M)}let j=Array.from(v(()=>$.keys()));for(let q of j)B(q);W=j;let m={[Symbol.toStringTag]:s,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let q of W){let Z=X.get(q);if(Z)yield Z}},get length(){if(V)F(P,V);return Q(),W.length},keys(){if(V)F(P,V);return Q(),W.values()},get(){if(V)F(P,V);return Q(),P.value},at(q){let Z=W[q];return Z!==void 0?X.get(Z):void 0},byKey(q){return X.get(q)},keyAt(q){return W[q]},indexOfKey(q){return W.indexOf(q)},deriveCollection(q){return x$(m,q)}};return m}function s$($,J){let z=J?.value??[];if(z.length)C(s,z,Array.isArray);S(s,$,X$);let X=new Map,W=[],B=new Map,[D,M]=E$(J?.keyConfig),R=(Z)=>B.get(Z)??(M?D(Z):void 0),P=J?.createItem??y;function Q(){let Z=[];for(let H of W)try{let U=X.get(H)?.get();if(U!=null)Z.push(U)}catch(U){if(!(U instanceof i))throw U}return Z}let j={fn:Q,value:z,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:L$,error:void 0};for(let Z of z){let H=D(Z);X.set(H,P(Z)),B.set(Z,H),W.push(H)}j.value=z,j.flags=G;function m(){if(V){if(!j.sinks)j.stop=$((Z)=>{let{add:H,change:U,remove:N}=Z;if(!H?.length&&!U?.length&&!N?.length)return;let K=!1;z$(()=>{if(H)for(let f of H){let A=D(f);if(X.set(A,P(f)),B.set(f,A),!W.includes(A))W.push(A);K=!0}if(U)for(let f of U){let A=R(f);if(!A)continue;let T=X.get(A);if(T&&V$(T))B.delete(T.get()),T.set(f),B.set(f,A)}if(N)for(let f of N){let A=R(f);if(!A)continue;B.delete(f),X.delete(A);let T=W.indexOf(A);if(T!==-1)W.splice(T,1);K=!0}j.flags=G|(K?b:0);for(let f=j.sinks;f;f=f.nextSink)x(f.sink)})});F(j,V)}}let q={[Symbol.toStringTag]:s,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of W){let H=X.get(Z);if(H)yield H}},get length(){return m(),W.length},keys(){return m(),W.values()},get(){if(m(),j.sources){if(j.flags){let Z=j.flags&b;if(j.value=v(Q),Z){if(j.flags=G,I(j),j.error)throw j.error}else j.flags=p}}else if(I(j),j.error)throw j.error;return j.value},at(Z){let H=W[Z];return H!==void 0?X.get(H):void 0},byKey(Z){return X.get(Z)},keyAt(Z){return W[Z]},indexOfKey(Z){return W.indexOf(Z)},deriveCollection(Z){return x$(q,Z)}};return q}function r$($){return Y($,s)}function l$($){S("Effect",$);let J={fn:$,flags:G,sources:null,sourcesTail:null,cleanup:null},z=()=>{K$(J),J.fn=void 0,J.flags=p,J.sourcesTail=null,H$(J)};if(_)J$(_,z);return T$(J),z}function o$($,J){if(!_)throw new G$("match");let z=!Array.isArray($),X=z?[$]:$,{nil:W}=J,B=z?(j)=>J.ok(j[0]):(j)=>J.ok(j),D=z&&J.err?(j)=>J.err(j[0]):J.err??console.error,M,R=!1,P=Array(X.length);for(let j=0;j<X.length;j++)try{P[j]=X[j].get()}catch(m){if(m instanceof i){R=!0;continue}if(!M)M=[];M.push(m instanceof Error?m:Error(String(m)))}let Q;try{if(R)Q=W?.();else if(M)Q=D(M);else Q=B(P)}catch(j){D([j instanceof Error?j:Error(String(j))])}if(typeof Q==="function")return Q;if(Q instanceof Promise){let j=_,m=new AbortController;J$(j,()=>m.abort()),Q.then((q)=>{if(!m.signal.aborted&&typeof q==="function")J$(j,q)}).catch((q)=>{D([q instanceof Error?q:Error(String(q))])})}}function i$($,J){if(S(t,$,X$),J?.value!==void 0)C(t,J.value,J?.guard);let z={value:J?.value,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard,stop:void 0};return{[Symbol.toStringTag]:t,get(){if(V){if(!z.sinks)z.stop=$((X)=>{C(t,X,z.guard),N$(z,X)});F(z,V)}return W$(t,z.value),z.value}}}function n$($){return Y($,t)}function a$($,J){let z=E($)||Array.isArray($),X=E(J)||Array.isArray(J);if(!z||!X){let j=!Object.is($,J);return{changed:j,add:j&&X?J:{},change:{},remove:j&&z?$:{}}}let W=new WeakSet,B={},D={},M={},R=!1,P=Object.keys($),Q=Object.keys(J);for(let j of Q)if(j in $){if(!n($[j],J[j],W))D[j]=J[j],R=!0}else B[j]=J[j],R=!0;for(let j of P)if(!(j in J))M[j]=void 0,R=!0;return{add:B,change:D,remove:M,changed:R}}function m$($,J){C(r,$,E);let z=new Map,X=(Q,j)=>{if(C(`${r} for key "${Q}"`,j),Array.isArray(j))z.set(Q,Q$(j));else if(E(j))z.set(Q,m$(j));else z.set(Q,y(j))},W=()=>{let Q={};return z.forEach((j,m)=>{Q[m]=j.get()}),Q},B={fn:W,value:$,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},D=(Q)=>{let j=!1;for(let m in Q.add)X(m,Q.add[m]),j=!0;if(Object.keys(Q.change).length)z$(()=>{for(let m in Q.change){let q=Q.change[m];C(`${r} for key "${m}"`,q);let Z=z.get(m);if(Z)if(E(q)!==F$(Z))X(m,q),j=!0;else Z.set(q)}});for(let m in Q.remove)z.delete(m),j=!0;if(j)B.flags|=b;return Q.changed},M=J?.watched,R=M?()=>{if(V){if(!B.sinks)B.stop=M();F(B,V)}}:()=>{if(V)F(B,V)};for(let Q of Object.keys($))X(Q,$[Q]);let P={[Symbol.toStringTag]:r,[Symbol.isConcatSpreadable]:!1,*[Symbol.iterator](){for(let Q of Array.from(z.keys())){let j=z.get(Q);if(j)yield[Q,j]}},keys(){return R(),z.keys()},byKey(Q){return z.get(Q)},get(){if(R(),B.sources){if(B.flags){let Q=B.flags&b;if(B.value=v(W),Q){if(B.flags=G,I(B),B.error)throw B.error}else B.flags=p}}else if(I(B),B.error)throw B.error;return B.value},set(Q){let j=B.flags&G?W():B.value,m=a$(j,Q);if(D(m)){B.flags|=G;for(let q=B.sinks;q;q=q.nextSink)x(q.sink);if(O===0)w()}},update(Q){P.set(Q(P.get()))},add(Q,j){if(z.has(Q))throw new e(r,Q,j);X(Q,j),B.flags|=G|b;for(let m=B.sinks;m;m=m.nextSink)x(m.sink);if(O===0)w();return Q},remove(Q){if(z.delete(Q)){B.flags|=G|b;for(let m=B.sinks;m;m=m.nextSink)x(m.sink);if(O===0)w()}}};return new Proxy(P,{get(Q,j){if(j in Q)return Reflect.get(Q,j);if(typeof j!=="symbol")return Q.byKey(j)},has(Q,j){if(j in Q)return!0;return Q.byKey(String(j))!==void 0},ownKeys(Q){return Array.from(Q.keys())},getOwnPropertyDescriptor(Q,j){if(j in Q)return Reflect.getOwnPropertyDescriptor(Q,j);if(typeof j==="symbol")return;let m=Q.byKey(String(j));return m?{enumerable:!0,configurable:!0,writable:!0,value:m}:void 0}})}function F$($){return Y($,r)}function e$($,J){return o($)?q$($,J):B$($,J)}function $J($){if(M$($))return $;if($==null)throw new j$("createSignal",$);if(o($))return q$($);if(g($))return B$($);if(Y$($))return Q$($);if(E($))return m$($);return y($)}function JJ($){if(w$($))return $;if($==null||g($)||M$($))throw new j$("createMutableSignal",$);if(Y$($))return Q$($);if(E($))return m$($);return y($)}function zJ($){return S$($)||p$($)}function M$($){let J=[c,u,d,t,l,L,s,r],z=Object.prototype.toString.call($).slice(8,-1);return J.includes(z)}function w$($){return V$($)||F$($)||O$($)}function XJ($,J){C(l,$,M$);let z=$,X=J?.guard,W={fn:()=>z.get(),value:void 0,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0},B=()=>{if(V)F(W,V);if(I(W),W.error)throw W.error;return W.value},D=(R)=>{if(!w$(z))throw new P$(l);C(l,R,X),z.set(R)},M=(R)=>{C(l,R,M$),z=R,W.flags|=G;for(let P=W.sinks;P;P=P.nextSink)x(P.sink);if(O===0)w()};return{[Symbol.toStringTag]:l,configurable:!0,enumerable:!0,get:B,set:D,replace:M,current:()=>z}}function ZJ($){return Y($,l)}export{D$ as valueString,v as untrack,d$ as unown,o$ as match,p$ as isTask,F$ as isStore,V$ as isState,ZJ as isSlot,M$ as isSignal,n$ as isSensor,E as isRecord,Y as isObjectOfType,w$ as isMutableSignal,S$ as isMemo,O$ as isList,g as isFunction,n as isEqual,zJ as isComputed,r$ as isCollection,o as isAsyncFunction,q$ as createTask,m$ as createStore,y as createState,XJ as createSlot,$J as createSignal,i$ as createSensor,u$ as createScope,JJ as createMutableSignal,B$ as createMemo,Q$ as createList,l$ as createEffect,e$ as createComputed,s$ as createCollection,z$ as batch,i as UnsetSignalValueError,L$ as SKIP_EQUALITY,G$ as RequiredOwnerError,P$ as ReadonlySignalError,A$ as NullishSignalValueError,j$ as InvalidSignalValueError,b$ as InvalidCallbackError,Z$ as CircularDependencyError};
|
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name Cause & Effect
|
|
3
|
-
* @version 1.0
|
|
3
|
+
* @version 1.1.0
|
|
4
4
|
* @author Esther Brunner
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -41,6 +41,7 @@ export {
|
|
|
41
41
|
export {
|
|
42
42
|
createEffect,
|
|
43
43
|
type MatchHandlers,
|
|
44
|
+
type SingleMatchHandlers,
|
|
44
45
|
type MaybePromise,
|
|
45
46
|
match,
|
|
46
47
|
} from './src/nodes/effect'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeix/cause-effect",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"author": "Esther Brunner",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
"types": "types/index.d.ts",
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"@biomejs/biome": "2.4.6",
|
|
11
|
-
"bun
|
|
11
|
+
"@types/bun": "latest",
|
|
12
12
|
"mitata": "^1.0.34",
|
|
13
13
|
"random": "^5.4.1",
|
|
14
|
-
"typescript": "
|
|
14
|
+
"typescript": "^6.0.2"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"typescript": ">=5.8.0"
|
package/src/nodes/effect.ts
CHANGED
|
@@ -39,6 +39,20 @@ type MatchHandlers<T extends readonly Signal<unknown & {}>[]> = {
|
|
|
39
39
|
nil?: () => MaybePromise<MaybeCleanup>
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Handlers for a single signal passed to `match()`.
|
|
44
|
+
*
|
|
45
|
+
* @template T - The value type of the signal being matched
|
|
46
|
+
*/
|
|
47
|
+
type SingleMatchHandlers<T extends {}> = {
|
|
48
|
+
/** Called when the signal has a value. Receives the resolved value directly. */
|
|
49
|
+
ok: (value: T) => MaybePromise<MaybeCleanup>
|
|
50
|
+
/** Called when the signal holds an error. Receives the error directly. Defaults to `console.error`. */
|
|
51
|
+
err?: (error: Error) => MaybePromise<MaybeCleanup>
|
|
52
|
+
/** Called when the signal is unset (pending). */
|
|
53
|
+
nil?: () => MaybePromise<MaybeCleanup>
|
|
54
|
+
}
|
|
55
|
+
|
|
42
56
|
/* === Exported Functions === */
|
|
43
57
|
|
|
44
58
|
/**
|
|
@@ -96,6 +110,20 @@ function createEffect(fn: EffectCallback): Cleanup {
|
|
|
96
110
|
return dispose
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Reads one or more signals and dispatches to the appropriate handler based on their state.
|
|
115
|
+
* Must be called within an active owner (effect or scope) so async cleanup can be registered.
|
|
116
|
+
*
|
|
117
|
+
* @since 1.1
|
|
118
|
+
* @param signal - A single signal to read.
|
|
119
|
+
* @param handlers - Object with an `ok` branch (receives the value directly) and optional `err` and `nil` branches.
|
|
120
|
+
* @returns An optional cleanup function if the active handler returns one.
|
|
121
|
+
* @throws RequiredOwnerError If called without an active owner.
|
|
122
|
+
*/
|
|
123
|
+
function match<T extends {}>(
|
|
124
|
+
signal: Signal<T>,
|
|
125
|
+
handlers: SingleMatchHandlers<T>,
|
|
126
|
+
): MaybeCleanup
|
|
99
127
|
/**
|
|
100
128
|
* Reads one or more signals and dispatches to the appropriate handler based on their state.
|
|
101
129
|
* Must be called within an active owner (effect or scope) so async cleanup can be registered.
|
|
@@ -105,13 +133,41 @@ function createEffect(fn: EffectCallback): Cleanup {
|
|
|
105
133
|
* @param handlers - Object with an `ok` branch and optional `err` and `nil` branches.
|
|
106
134
|
* @returns An optional cleanup function if the active handler returns one.
|
|
107
135
|
* @throws RequiredOwnerError If called without an active owner.
|
|
136
|
+
*
|
|
137
|
+
* @remarks
|
|
138
|
+
* **Async handlers are for external side effects only** — DOM mutations, analytics, logging,
|
|
139
|
+
* or any fire-and-forget API call whose result does not need to drive reactive state.
|
|
140
|
+
* Do not call `.set()` on a signal inside an async handler: use a `Task` node instead,
|
|
141
|
+
* which receives an `AbortSignal`, is auto-cancelled on re-run, and integrates cleanly
|
|
142
|
+
* with `nil` and `err` branches.
|
|
143
|
+
*
|
|
144
|
+
* Rejections from async handlers are always routed to `err`, including rejections from
|
|
145
|
+
* stale runs that were already superseded by a newer signal value. The library cannot
|
|
146
|
+
* cancel external operations it did not start.
|
|
108
147
|
*/
|
|
109
148
|
function match<T extends readonly Signal<unknown & {}>[]>(
|
|
110
149
|
signals: readonly [...T],
|
|
111
150
|
handlers: MatchHandlers<T>,
|
|
151
|
+
): MaybeCleanup
|
|
152
|
+
function match(
|
|
153
|
+
signalOrSignals: Signal<unknown & {}> | readonly Signal<unknown & {}>[],
|
|
154
|
+
// biome-ignore lint/suspicious/noExplicitAny: implementation overload, not part of the public API
|
|
155
|
+
handlers: any,
|
|
112
156
|
): MaybeCleanup {
|
|
113
157
|
if (!activeOwner) throw new RequiredOwnerError('match')
|
|
114
|
-
|
|
158
|
+
|
|
159
|
+
const isSingle = !Array.isArray(signalOrSignals)
|
|
160
|
+
const signals = isSingle ? [signalOrSignals] : signalOrSignals
|
|
161
|
+
|
|
162
|
+
const { nil } = handlers
|
|
163
|
+
const ok = isSingle
|
|
164
|
+
? (values: unknown[]) => handlers.ok(values[0])
|
|
165
|
+
: (values: unknown[]) => handlers.ok(values)
|
|
166
|
+
const err: (errors: readonly Error[]) => MaybePromise<MaybeCleanup> =
|
|
167
|
+
isSingle && handlers.err
|
|
168
|
+
? (errors: readonly Error[]) => handlers.err(errors[0])
|
|
169
|
+
: (handlers.err ?? console.error)
|
|
170
|
+
|
|
115
171
|
let errors: Error[] | undefined
|
|
116
172
|
let pending = false
|
|
117
173
|
const values = new Array(signals.length)
|
|
@@ -133,12 +189,7 @@ function match<T extends readonly Signal<unknown & {}>[]>(
|
|
|
133
189
|
try {
|
|
134
190
|
if (pending) out = nil?.()
|
|
135
191
|
else if (errors) out = err(errors)
|
|
136
|
-
else
|
|
137
|
-
out = ok(
|
|
138
|
-
values as {
|
|
139
|
-
[K in keyof T]: T[K] extends Signal<infer V> ? V : never
|
|
140
|
-
},
|
|
141
|
-
)
|
|
192
|
+
else out = ok(values)
|
|
142
193
|
} catch (e) {
|
|
143
194
|
err([e instanceof Error ? e : new Error(String(e))])
|
|
144
195
|
}
|
|
@@ -158,4 +209,10 @@ function match<T extends readonly Signal<unknown & {}>[]>(
|
|
|
158
209
|
}
|
|
159
210
|
}
|
|
160
211
|
|
|
161
|
-
export {
|
|
212
|
+
export {
|
|
213
|
+
type MaybePromise,
|
|
214
|
+
type MatchHandlers,
|
|
215
|
+
type SingleMatchHandlers,
|
|
216
|
+
createEffect,
|
|
217
|
+
match,
|
|
218
|
+
}
|
package/test/effect.test.ts
CHANGED
|
@@ -475,6 +475,94 @@ describe('match', () => {
|
|
|
475
475
|
expect(() => match([], { ok: () => {} })).toThrow(RequiredOwnerError)
|
|
476
476
|
})
|
|
477
477
|
|
|
478
|
+
describe('Single-signal overload', () => {
|
|
479
|
+
test('should call ok with unwrapped value', () => {
|
|
480
|
+
const s = createState(42)
|
|
481
|
+
let result = 0
|
|
482
|
+
createEffect(() =>
|
|
483
|
+
match(s, {
|
|
484
|
+
ok: value => {
|
|
485
|
+
result = value
|
|
486
|
+
},
|
|
487
|
+
}),
|
|
488
|
+
)
|
|
489
|
+
expect(result).toBe(42)
|
|
490
|
+
s.set(99)
|
|
491
|
+
expect(result).toBe(99)
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
test('should call nil handler when signal is unset', async () => {
|
|
495
|
+
const task = createTask(async () => {
|
|
496
|
+
await wait(50)
|
|
497
|
+
return 42
|
|
498
|
+
})
|
|
499
|
+
let okCount = 0
|
|
500
|
+
let nilCount = 0
|
|
501
|
+
createEffect(() =>
|
|
502
|
+
match(task, {
|
|
503
|
+
ok: value => {
|
|
504
|
+
okCount++
|
|
505
|
+
expect(value).toBe(42)
|
|
506
|
+
},
|
|
507
|
+
nil: () => {
|
|
508
|
+
nilCount++
|
|
509
|
+
},
|
|
510
|
+
}),
|
|
511
|
+
)
|
|
512
|
+
expect(okCount).toBe(0)
|
|
513
|
+
expect(nilCount).toBe(1)
|
|
514
|
+
await wait(60)
|
|
515
|
+
expect(okCount).toBeGreaterThan(0)
|
|
516
|
+
expect(nilCount).toBe(1)
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
test('should call err with unwrapped Error', () => {
|
|
520
|
+
const a = createState(1)
|
|
521
|
+
const b = createMemo(() => {
|
|
522
|
+
if (a.get() > 5) throw new Error('Too high')
|
|
523
|
+
return a.get() * 2
|
|
524
|
+
})
|
|
525
|
+
let okCount = 0
|
|
526
|
+
let errCount = 0
|
|
527
|
+
createEffect(() =>
|
|
528
|
+
match(b, {
|
|
529
|
+
ok: () => {
|
|
530
|
+
okCount++
|
|
531
|
+
},
|
|
532
|
+
err: error => {
|
|
533
|
+
errCount++
|
|
534
|
+
expect(error.message).toBe('Too high')
|
|
535
|
+
},
|
|
536
|
+
}),
|
|
537
|
+
)
|
|
538
|
+
expect(okCount).toBe(1)
|
|
539
|
+
a.set(6)
|
|
540
|
+
expect(errCount).toBe(1)
|
|
541
|
+
a.set(3)
|
|
542
|
+
expect(okCount).toBe(2)
|
|
543
|
+
expect(errCount).toBe(1)
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
test('should fall back to console.error for single signal without err handler', () => {
|
|
547
|
+
const originalConsoleError = console.error
|
|
548
|
+
const mockConsoleError = mock(() => {})
|
|
549
|
+
console.error = mockConsoleError
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
const a = createState(1)
|
|
553
|
+
const b = createMemo(() => {
|
|
554
|
+
if (a.get() > 5) throw new Error('Too high')
|
|
555
|
+
return a.get() * 2
|
|
556
|
+
})
|
|
557
|
+
createEffect(() => match(b, { ok: () => {} }))
|
|
558
|
+
a.set(6)
|
|
559
|
+
expect(mockConsoleError).toHaveBeenCalled()
|
|
560
|
+
} finally {
|
|
561
|
+
console.error = originalConsoleError
|
|
562
|
+
}
|
|
563
|
+
})
|
|
564
|
+
})
|
|
565
|
+
|
|
478
566
|
test('should resolve multiple async tasks without waterfalls', async () => {
|
|
479
567
|
const a = createTask(async () => {
|
|
480
568
|
await wait(20)
|
package/types/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name Cause & Effect
|
|
3
|
-
* @version 1.0
|
|
3
|
+
* @version 1.1.0
|
|
4
4
|
* @author Esther Brunner
|
|
5
5
|
*/
|
|
6
6
|
export { CircularDependencyError, type Guard, InvalidCallbackError, InvalidSignalValueError, NullishSignalValueError, ReadonlySignalError, RequiredOwnerError, UnsetSignalValueError, } from './src/errors';
|
|
7
7
|
export { batch, type Cleanup, type ComputedOptions, createScope, type EffectCallback, type MaybeCleanup, type MemoCallback, type Signal, type SignalOptions, SKIP_EQUALITY, type TaskCallback, unown, untrack, } from './src/graph';
|
|
8
8
|
export { type Collection, type CollectionCallback, type CollectionChanges, type CollectionOptions, createCollection, type DeriveCollectionCallback, isCollection, } from './src/nodes/collection';
|
|
9
|
-
export { createEffect, type MatchHandlers, type MaybePromise, match, } from './src/nodes/effect';
|
|
9
|
+
export { createEffect, type MatchHandlers, type SingleMatchHandlers, type MaybePromise, match, } from './src/nodes/effect';
|
|
10
10
|
export { createList, isEqual, isList, type KeyConfig, type List, type ListOptions, } from './src/nodes/list';
|
|
11
11
|
export { createMemo, isMemo, type Memo } from './src/nodes/memo';
|
|
12
12
|
export { createSensor, isSensor, type Sensor, type SensorCallback, type SensorOptions, } from './src/nodes/sensor';
|
|
@@ -16,6 +16,19 @@ type MatchHandlers<T extends readonly Signal<unknown & {}>[]> = {
|
|
|
16
16
|
/** Called when one or more signals are unset (pending). */
|
|
17
17
|
nil?: () => MaybePromise<MaybeCleanup>;
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Handlers for a single signal passed to `match()`.
|
|
21
|
+
*
|
|
22
|
+
* @template T - The value type of the signal being matched
|
|
23
|
+
*/
|
|
24
|
+
type SingleMatchHandlers<T extends {}> = {
|
|
25
|
+
/** Called when the signal has a value. Receives the resolved value directly. */
|
|
26
|
+
ok: (value: T) => MaybePromise<MaybeCleanup>;
|
|
27
|
+
/** Called when the signal holds an error. Receives the error directly. Defaults to `console.error`. */
|
|
28
|
+
err?: (error: Error) => MaybePromise<MaybeCleanup>;
|
|
29
|
+
/** Called when the signal is unset (pending). */
|
|
30
|
+
nil?: () => MaybePromise<MaybeCleanup>;
|
|
31
|
+
};
|
|
19
32
|
/**
|
|
20
33
|
* Creates a reactive effect that automatically runs when its dependencies change.
|
|
21
34
|
* Effects run immediately upon creation and re-run when any tracked signal changes.
|
|
@@ -46,6 +59,17 @@ type MatchHandlers<T extends readonly Signal<unknown & {}>[]> = {
|
|
|
46
59
|
* ```
|
|
47
60
|
*/
|
|
48
61
|
declare function createEffect(fn: EffectCallback): Cleanup;
|
|
62
|
+
/**
|
|
63
|
+
* Reads one or more signals and dispatches to the appropriate handler based on their state.
|
|
64
|
+
* Must be called within an active owner (effect or scope) so async cleanup can be registered.
|
|
65
|
+
*
|
|
66
|
+
* @since 1.1
|
|
67
|
+
* @param signal - A single signal to read.
|
|
68
|
+
* @param handlers - Object with an `ok` branch (receives the value directly) and optional `err` and `nil` branches.
|
|
69
|
+
* @returns An optional cleanup function if the active handler returns one.
|
|
70
|
+
* @throws RequiredOwnerError If called without an active owner.
|
|
71
|
+
*/
|
|
72
|
+
declare function match<T extends {}>(signal: Signal<T>, handlers: SingleMatchHandlers<T>): MaybeCleanup;
|
|
49
73
|
/**
|
|
50
74
|
* Reads one or more signals and dispatches to the appropriate handler based on their state.
|
|
51
75
|
* Must be called within an active owner (effect or scope) so async cleanup can be registered.
|
|
@@ -55,6 +79,17 @@ declare function createEffect(fn: EffectCallback): Cleanup;
|
|
|
55
79
|
* @param handlers - Object with an `ok` branch and optional `err` and `nil` branches.
|
|
56
80
|
* @returns An optional cleanup function if the active handler returns one.
|
|
57
81
|
* @throws RequiredOwnerError If called without an active owner.
|
|
82
|
+
*
|
|
83
|
+
* @remarks
|
|
84
|
+
* **Async handlers are for external side effects only** — DOM mutations, analytics, logging,
|
|
85
|
+
* or any fire-and-forget API call whose result does not need to drive reactive state.
|
|
86
|
+
* Do not call `.set()` on a signal inside an async handler: use a `Task` node instead,
|
|
87
|
+
* which receives an `AbortSignal`, is auto-cancelled on re-run, and integrates cleanly
|
|
88
|
+
* with `nil` and `err` branches.
|
|
89
|
+
*
|
|
90
|
+
* Rejections from async handlers are always routed to `err`, including rejections from
|
|
91
|
+
* stale runs that were already superseded by a newer signal value. The library cannot
|
|
92
|
+
* cancel external operations it did not start.
|
|
58
93
|
*/
|
|
59
94
|
declare function match<T extends readonly Signal<unknown & {}>[]>(signals: readonly [...T], handlers: MatchHandlers<T>): MaybeCleanup;
|
|
60
|
-
export { type MaybePromise, type MatchHandlers, createEffect, match };
|
|
95
|
+
export { type MaybePromise, type MatchHandlers, type SingleMatchHandlers, createEffect, match, };
|