@zeix/cause-effect 0.18.5 → 1.0.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/ARCHITECTURE.md CHANGED
@@ -1,4 +1,4 @@
1
- # Cause & Effect v0.18 - Signal Graph Architecture
1
+ # Cause & Effect - Signal Graph Architecture
2
2
 
3
3
  This document describes the reactive signal graph engine implemented in `src/graph.ts` and the node types built on top of it in `src/nodes/`.
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Changed
6
+
7
+ - **Stricter TypeScript configuration**: Enabled `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `useUnknownInCatchVariables`, `noUncheckedSideEffectImports`, and `noFallthroughCasesInSwitch` in `tsconfig.json`. All internal array and indexed object accesses have been updated to satisfy these checks. Runtime behaviour is unchanged.
8
+ - **`stop` on node types now typed as `Cleanup | undefined`**: The `stop` property in `SourceFields` (and by extension `StateNode`, `MemoNode`, `TaskNode`) is now declared `stop?: Cleanup | undefined` rather than `stop?: Cleanup`. Under `exactOptionalPropertyTypes`, this is required to allow clearing the property by assignment (`= undefined`) rather than deletion — preserving V8 hidden-class stability on hot-path nodes. Consumers reading `stop` from a node should already be handling `undefined` since the property is optional, but TypeScript will now surface this requirement explicitly.
9
+ - **`guard` on options types now requires explicit presence**: Under `exactOptionalPropertyTypes`, passing `{ guard: undefined }` to `SignalOptions`, `ComputedOptions`, or `SensorOptions` is now a type error. Omit the property entirely to leave it unset.
10
+
3
11
  ## 0.18.5
4
12
 
5
13
  ### Added
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Cause & Effect
2
2
 
3
- Version 0.18.5
3
+ Version 1.0.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
 
@@ -122,7 +122,8 @@ function setupMux(fw: ReactiveFramework) {
122
122
  Object.fromEntries(heads.map(h => h.read()).entries()),
123
123
  )
124
124
  const splited = heads
125
- .map((_, index) => fw.computed(() => mux.read()[index]))
125
+ // biome-ignore lint/style/noNonNullAssertion: fixed-size array
126
+ .map((_, index) => fw.computed(() => mux.read()[index]!))
126
127
  .map(x => fw.computed(() => x.read() + 1))
127
128
  for (const x of splited) {
128
129
  fw.effect(() => {
@@ -133,7 +134,8 @@ function setupMux(fw: ReactiveFramework) {
133
134
  return () => {
134
135
  const idx = i % heads.length
135
136
  fw.withBatch(() => {
136
- heads[idx].write(++i)
137
+ // biome-ignore lint/style/noNonNullAssertion: fixed-size array
138
+ heads[idx]!.write(++i)
137
139
  })
138
140
  }
139
141
  }
@@ -211,10 +213,16 @@ function setupCellx(fw: ReactiveFramework, layers: number) {
211
213
  prop3: fw.signal(3),
212
214
  prop4: fw.signal(4),
213
215
  }
214
- let layer: Record<string, { read(): number }> = start
216
+ type CellxLayer = {
217
+ prop1: { read(): number }
218
+ prop2: { read(): number }
219
+ prop3: { read(): number }
220
+ prop4: { read(): number }
221
+ }
222
+ let layer: CellxLayer = start
215
223
 
216
224
  for (let i = layers; i > 0; i--) {
217
- const m = layer
225
+ const m: CellxLayer = layer
218
226
  const s = {
219
227
  prop1: fw.computed(() => m.prop2.read()),
220
228
  prop2: fw.computed(() => m.prop1.read() - m.prop3.read()),
@@ -283,10 +291,13 @@ function setupMolWire(fw: ReactiveFramework) {
283
291
  const D = fw.computed(() =>
284
292
  numbers.map(i => ({ x: i + (A.read() % 2) - (B.read() % 2) })),
285
293
  )
286
- const E = fw.computed(() => hard(C.read() + A.read() + D.read()[0].x, 'E'))
287
- const F = fw.computed(() => hard(D.read()[2].x || B.read(), 'F'))
294
+ // biome-ignore lint/style/noNonNullAssertion: fixed-size array
295
+ const E = fw.computed(() => hard(C.read() + A.read() + D.read()[0]!.x, 'E'))
296
+ // biome-ignore lint/style/noNonNullAssertion: fixed-size array
297
+ const F = fw.computed(() => hard(D.read()[2]!.x || B.read(), 'F'))
288
298
  const G = fw.computed(
289
- () => C.read() + (C.read() || E.read() % 2) + D.read()[4].x + F.read(),
299
+ // biome-ignore lint/style/noNonNullAssertion: fixed-size array
300
+ () => C.read() + (C.read() || E.read() % 2) + D.read()[4]!.x + F.read(),
290
301
  )
291
302
  fw.effect(() => {
292
303
  hard(G.read(), 'H')
package/biome.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://biomejs.dev/schemas/2.1.4/schema.json",
2
+ "$schema": "https://biomejs.dev/schemas/2.4.6/schema.json",
3
3
  "vcs": {
4
4
  "enabled": false,
5
5
  "clientKind": "git",
package/index.dev.js CHANGED
@@ -514,8 +514,9 @@ function diffArrays(prev, next, prevKeys, generateKey, contentBased) {
514
514
  const prevByKey = new Map;
515
515
  for (let i = 0;i < prev.length; i++) {
516
516
  const key = prevKeys[i];
517
- if (key && prev[i])
518
- prevByKey.set(key, prev[i]);
517
+ const item = prev[i];
518
+ if (key && item !== undefined)
519
+ prevByKey.set(key, item);
519
520
  }
520
521
  const seenKeys = new Set;
521
522
  for (let i = 0;i < next.length; i++) {
@@ -679,7 +680,8 @@ function createList(value, options) {
679
680
  list.set(fn(list.get()));
680
681
  },
681
682
  at(index) {
682
- return signals.get(keys[index]);
683
+ const key = keys[index];
684
+ return key !== undefined ? signals.get(key) : undefined;
683
685
  },
684
686
  keys() {
685
687
  subscribe();
@@ -711,6 +713,8 @@ function createList(value, options) {
711
713
  },
712
714
  remove(keyOrIndex) {
713
715
  const key = typeof keyOrIndex === "number" ? keys[keyOrIndex] : keyOrIndex;
716
+ if (key === undefined)
717
+ return;
714
718
  const ok = signals.delete(key);
715
719
  if (ok) {
716
720
  const index = typeof keyOrIndex === "number" ? keyOrIndex : keys.indexOf(key);
@@ -1012,7 +1016,8 @@ function deriveCollection(source, callback) {
1012
1016
  return node.value;
1013
1017
  },
1014
1018
  at(index) {
1015
- return signals.get(keys[index]);
1019
+ const key = keys[index];
1020
+ return key !== undefined ? signals.get(key) : undefined;
1016
1021
  },
1017
1022
  byKey(key) {
1018
1023
  return signals.get(key);
@@ -1167,7 +1172,8 @@ function createCollection(watched, options) {
1167
1172
  return node.value;
1168
1173
  },
1169
1174
  at(index) {
1170
- return signals.get(keys[index]);
1175
+ const key = keys[index];
1176
+ return key !== undefined ? signals.get(key) : undefined;
1171
1177
  },
1172
1178
  byKey(key) {
1173
1179
  return signals.get(key);
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 Y($,J){return Object.prototype.toString.call($)===`[object ${J}]`}function T($){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 O($,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 E($,J,z=g){if(!z(J))throw new b$($,J)}var c="State",u="Memo",d="Task",t="Sensor",S="List",s="Collection",l="Store",r="Slot",p=0,$$=1,G=2,U$=4,b=8,m=null,_=null,C$=[],x=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 R($,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 Q=$.sinksTail;if(Q?.sink===J&&(!W||g$(Q,J)))return;let D={source:$,sink:J,nextSource:X,prevSink:Q,nextSink:null};if(J.sourcesTail=$.sinksTail=D,z)z.nextSource=D;else J.sources=D;if(Q)Q.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 Q=J;Q.sourcesTail=null,H$(Q)}}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 F($,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)F(X.sink,$$)}else{if((z&(G|$$))>=J)return;let X=z&(G|$$);if($.flags=J,!X)C$.push($)}}function m$($,J){if($.equals($.value,J))return;$.value=J;for(let z=$.sinks;z;z=z.nextSink)F(z.sink);if(x===0)I()}function J$($,J){if(!$.cleanup)$.cleanup=J;else if(Array.isArray($.cleanup))$.cleanup.push(J);else $.cleanup=[$.cleanup,J]}function O$($){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|=G}$.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(W){$.controller=void 0,$.error=W instanceof Error?W:Error(String(W));return}finally{m=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 Q=$.sinks;Q;Q=Q.nextSink)F(Q.sink);if(x===0)I()}},(W)=>{if(J.signal.aborted)return;$.controller=void 0;let Q=W instanceof Error?W:Error(String(W));if(!$.error||Q.name!==$.error.name||Q.message!==$.error.message){$.error=Q;for(let D=$.sinks;D;D=D.nextSink)F(D.sink);if(x===0)I()}}),$.flags=p}function T$($){O$($);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 f($){if($.flags&$$)for(let J=$.sources;J;J=J.nextSource){if("fn"in J.source)f(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 I(){if(_$)return;_$=!0;try{for(let $=0;$<C$.length;$++){let J=C$[$];if(J.flags&(G|$$))f(J)}C$.length=0}finally{_$=!1}}function z$($){x++;try{$()}finally{if(x--,x===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 W=()=>O$(z);if(J)J$(J,W);return W}finally{_=J}}function d$($){let J=_;_=null;try{return $()}finally{_=J}}function y($,J){O(c,$,J?.guard);let z={value:$,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard};return{[Symbol.toStringTag]:c,get(){if(m)R(z,m);return z.value},set(X){O(c,X,z.guard),m$(z,X)},update(X){E(c,X);let W=X(z.value);O(c,W,z.guard),m$(z,W)}}}function N$($){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=$,Q=J;if(W.length!==Q.length)return!1;for(let D=0;D<W.length;D++)if(!n(W[D],Q[D],z))return!1;return!0}if(T($)&&T(J)){let W=Object.keys($),Q=Object.keys(J);if(W.length!==Q.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 K$($,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 Q=new WeakSet,D={},M={},C={},U=[],H=!1,j=new Map;for(let q=0;q<$.length;q++){let Z=z[q];if(Z&&$[q])j.set(Z,$[q])}let P=new Set;for(let q=0;q<J.length;q++){let Z=J[q];if(Z===void 0)continue;let B=W?X(Z):z[q]??X(Z);if(P.has(B))throw new e(S,B,Z);if(U.push(B),P.add(B),!j.has(B))D[B]=Z,H=!0;else if(!n(j.get(B),Z,Q))M[B]=Z,H=!0}for(let[q]of j)if(!P.has(q))C[q]=null,H=!0;if(!H&&!K$(z,U))H=!0;return{add:D,change:M,remove:C,newKeys:U,changed:H}}function Q$($,J){O(S,$,Array.isArray);let z=new Map,X=[],[W,Q]=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},C=(Z)=>{let B={};for(let N=0;N<Z.length;N++){let V=Z[N];if(V===void 0)continue;let K=X[N];if(!K)K=W(V),X[N]=K;B[K]=V}return B},U=(Z)=>{let B=!1;for(let N in Z.add){let V=Z.add[N];O(`${S} item for key "${N}"`,V),z.set(N,y(V)),B=!0}if(Object.keys(Z.change).length)z$(()=>{for(let N in Z.change){let V=Z.change[N];O(`${S} item for key "${N}"`,V);let K=z.get(N);if(K)K.set(V)}});for(let N in Z.remove){z.delete(N);let V=X.indexOf(N);if(V!==-1)X.splice(V,1);B=!0}if(B)M.flags|=b;return Z.changed},H=J?.watched,j=H?()=>{if(m){if(!M.sinks)M.stop=H();R(M,m)}}:()=>{if(m)R(M,m)},P=C($);for(let Z in P){let B=P[Z];O(`${S} item for key "${Z}"`,B),z.set(Z,y(B))}M.value=$,M.flags=0;let q={[Symbol.toStringTag]:S,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of X){let B=z.get(Z);if(B)yield B}},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,f(M),M.error)throw M.error}else M.flags=p}}else if(f(M),M.error)throw M.error;return M.value},set(Z){let B=M.flags&G?D():M.value,N=t$(B,Z,X,W,Q);if(N.changed){X=N.newKeys,U(N),M.flags|=G;for(let V=M.sinks;V;V=V.nextSink)F(V.sink);if(x===0)I()}},update(Z){q.set(Z(q.get()))},at(Z){return z.get(X[Z])},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 B=W(Z);if(z.has(B))throw new e(S,B,Z);if(!X.includes(B))X.push(B);O(`${S} item for key "${B}"`,Z),z.set(B,y(Z)),M.flags|=G|b;for(let N=M.sinks;N;N=N.nextSink)F(N.sink);if(x===0)I();return B},remove(Z){let B=typeof Z==="number"?X[Z]:Z;if(z.delete(B)){let V=typeof Z==="number"?Z:X.indexOf(B);if(V>=0)X.splice(V,1);M.flags|=G|b;for(let K=M.sinks;K;K=K.nextSink)F(K.sink);if(x===0)I()}},sort(Z){let N=X.map((V)=>[V,z.get(V)?.get()]).sort(g(Z)?(V,K)=>Z(V[1],K[1]):(V,K)=>String(V[1]).localeCompare(String(K[1]))).map(([V])=>V);if(!K$(X,N)){X=N,M.flags|=G;for(let V=M.sinks;V;V=V.nextSink)F(V.sink);if(x===0)I()}},splice(Z,B,...N){let V=X.length,K=Z<0?Math.max(0,V+Z):Math.min(Z,V),w=Math.max(0,Math.min(B??Math.max(0,V-Math.max(0,K)),V-K)),A={},L={};for(let h=0;h<w;h++){let a=K+h,w$=X[a];if(w$){let y$=z.get(w$);if(y$)L[w$]=y$.get()}}let f$=X.slice(0,K);for(let h of N){let a=W(h);if(z.has(a)&&!(a in L))throw new e(S,a,h);f$.push(a),A[a]=h}f$.push(...X.slice(K+w));let h$=!!(Object.keys(A).length||Object.keys(L).length);if(h$){U({add:A,change:{},remove:L,changed:h$}),X=f$,M.flags|=G;for(let h=M.sinks;h;h=h.nextSink)F(h.sink);if(x===0)I()}return Object.values(L)},deriveCollection(Z){return x$(q,Z)}};return q}function R$($){return Y($,S)}function B$($,J){if(E(u,$,X$),J?.value!==void 0)O(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(m){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,m)}}:()=>{if(m)R(z,m)};return{[Symbol.toStringTag]:u,get(){if(W(),f(z),z.error)throw z.error;return W$(u,z.value),z.value}}}function S$($){return Y($,u)}function q$($,J){if(E(d,$,o),J?.value!==void 0)O(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(m){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,m)}}:()=>{if(m)R(z,m)};return{[Symbol.toStringTag]:d,get(){if(W(),f(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){E(s,J);let z=o(J),X=new Map,W=[],Q=(q)=>{let Z=z?q$(async(B,N)=>{let V=$.byKey(q)?.get();if(V==null)return B;return J(V,N)}):B$(()=>{let B=$.byKey(q)?.get();if(B==null)return;return J(B)});X.set(q,Z)};function D(q){if(!K$(W,q)){let Z=new Set(W),B=new Set(q);for(let N of W)if(!B.has(N))X.delete(N);for(let N of q)if(!Z.has(N))Q(N);W=q,U.flags|=b}}function M(){D(Array.from($.keys()));let q=[];for(let Z of W)try{let B=X.get(Z)?.get();if(B!=null)q.push(B)}catch(B){if(!(B instanceof i))throw B}return q}let U={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 B=0;B<q.length;B++)if(q[B]!==Z[B])return!1;return!0},error:void 0};function H(){if(U.sources){if(U.flags)if(U.value=v(M),U.flags&b){if(U.flags=G,f(U),U.error)throw U.error}else U.flags=p}else if(U.sinks){if(f(U),U.error)throw U.error}else U.value=v(M)}let j=Array.from(v(()=>$.keys()));for(let q of j)Q(q);W=j;let P={[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(m)R(U,m);return H(),W.length},keys(){if(m)R(U,m);return H(),W.values()},get(){if(m)R(U,m);return H(),U.value},at(q){return X.get(W[q])},byKey(q){return X.get(q)},keyAt(q){return W[q]},indexOfKey(q){return W.indexOf(q)},deriveCollection(q){return x$(P,q)}};return P}function s$($,J){let z=J?.value??[];if(z.length)O(s,z,Array.isArray);E(s,$,X$);let X=new Map,W=[],Q=new Map,[D,M]=E$(J?.keyConfig),C=(Z)=>Q.get(Z)??(M?D(Z):void 0),U=J?.createItem??y;function H(){let Z=[];for(let B of W)try{let N=X.get(B)?.get();if(N!=null)Z.push(N)}catch(N){if(!(N instanceof i))throw N}return Z}let j={fn:H,value:z,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:L$,error:void 0};for(let Z of z){let B=D(Z);X.set(B,U(Z)),Q.set(Z,B),W.push(B)}j.value=z,j.flags=G;function P(){if(m){if(!j.sinks)j.stop=$((Z)=>{let{add:B,change:N,remove:V}=Z;if(!B?.length&&!N?.length&&!V?.length)return;let K=!1;z$(()=>{if(B)for(let w of B){let A=D(w);if(X.set(A,U(w)),Q.set(w,A),!W.includes(A))W.push(A);K=!0}if(N)for(let w of N){let A=C(w);if(!A)continue;let L=X.get(A);if(L&&N$(L))Q.delete(L.get()),L.set(w),Q.set(w,A)}if(V)for(let w of V){let A=C(w);if(!A)continue;Q.delete(w),X.delete(A);let L=W.indexOf(A);if(L!==-1)W.splice(L,1);K=!0}j.flags=G|(K?b:0);for(let w=j.sinks;w;w=w.nextSink)F(w.sink)})});R(j,m)}}let q={[Symbol.toStringTag]:s,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of W){let B=X.get(Z);if(B)yield B}},get length(){return P(),W.length},keys(){return P(),W.values()},get(){if(P(),j.sources){if(j.flags){let Z=j.flags&b;if(j.value=v(H),Z){if(j.flags=G,f(j),j.error)throw j.error}else j.flags=p}}else if(f(j),j.error)throw j.error;return j.value},at(Z){return X.get(W[Z])},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 l$($){return Y($,s)}function r$($){E("Effect",$);let J={fn:$,flags:G,sources:null,sourcesTail:null,cleanup:null},z=()=>{O$(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:W}=J,Q,D=!1,M=Array($.length);for(let U=0;U<$.length;U++)try{M[U]=$[U].get()}catch(H){if(H instanceof i){D=!0;continue}if(!Q)Q=[];Q.push(H instanceof Error?H:Error(String(H)))}let C;try{if(D)C=W?.();else if(Q)C=X(Q);else C=z(M)}catch(U){X([U instanceof Error?U:Error(String(U))])}if(typeof C==="function")return C;if(C instanceof Promise){let U=_,H=new AbortController;J$(U,()=>H.abort()),C.then((j)=>{if(!H.signal.aborted&&typeof j==="function")J$(U,j)}).catch((j)=>{X([j instanceof Error?j:Error(String(j))])})}}function i$($,J){if(E(t,$,X$),J?.value!==void 0)O(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(m){if(!z.sinks)z.stop=$((X)=>{O(t,X,z.guard),m$(z,X)});R(z,m)}return W$(t,z.value),z.value}}}function n$($){return Y($,t)}function a$($,J){let z=T($)||Array.isArray($),X=T(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,Q={},D={},M={},C=!1,U=Object.keys($),H=Object.keys(J);for(let j of H)if(j in $){if(!n($[j],J[j],W))D[j]=J[j],C=!0}else Q[j]=J[j],C=!0;for(let j of U)if(!(j in J))M[j]=void 0,C=!0;return{add:Q,change:D,remove:M,changed:C}}function V$($,J){O(l,$,T);let z=new Map,X=(H,j)=>{if(O(`${l} for key "${H}"`,j),Array.isArray(j))z.set(H,Q$(j));else if(T(j))z.set(H,V$(j));else z.set(H,y(j))},W=()=>{let H={};return z.forEach((j,P)=>{H[P]=j.get()}),H},Q={fn:W,value:$,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},D=(H)=>{let j=!1;for(let P in H.add)X(P,H.add[P]),j=!0;if(Object.keys(H.change).length)z$(()=>{for(let P in H.change){let q=H.change[P];O(`${l} for key "${P}"`,q);let Z=z.get(P);if(Z)if(T(q)!==F$(Z))X(P,q),j=!0;else Z.set(q)}});for(let P in H.remove)z.delete(P),j=!0;if(j)Q.flags|=b;return H.changed},M=J?.watched,C=M?()=>{if(m){if(!Q.sinks)Q.stop=M();R(Q,m)}}:()=>{if(m)R(Q,m)};for(let H of Object.keys($))X(H,$[H]);let U={[Symbol.toStringTag]:l,[Symbol.isConcatSpreadable]:!1,*[Symbol.iterator](){for(let H of Array.from(z.keys())){let j=z.get(H);if(j)yield[H,j]}},keys(){return C(),z.keys()},byKey(H){return z.get(H)},get(){if(C(),Q.sources){if(Q.flags){let H=Q.flags&b;if(Q.value=v(W),H){if(Q.flags=G,f(Q),Q.error)throw Q.error}else Q.flags=p}}else if(f(Q),Q.error)throw Q.error;return Q.value},set(H){let j=Q.flags&G?W():Q.value,P=a$(j,H);if(D(P)){Q.flags|=G;for(let q=Q.sinks;q;q=q.nextSink)F(q.sink);if(x===0)I()}},update(H){U.set(H(U.get()))},add(H,j){if(z.has(H))throw new e(l,H,j);X(H,j),Q.flags|=G|b;for(let P=Q.sinks;P;P=P.nextSink)F(P.sink);if(x===0)I();return H},remove(H){if(z.delete(H)){Q.flags|=G|b;for(let P=Q.sinks;P;P=P.nextSink)F(P.sink);if(x===0)I()}}};return new Proxy(U,{get(H,j){if(j in H)return Reflect.get(H,j);if(typeof j!=="symbol")return H.byKey(j)},has(H,j){if(j in H)return!0;return H.byKey(String(j))!==void 0},ownKeys(H){return Array.from(H.keys())},getOwnPropertyDescriptor(H,j){if(j in H)return Reflect.getOwnPropertyDescriptor(H,j);if(typeof j==="symbol")return;let P=H.byKey(String(j));return P?{enumerable:!0,configurable:!0,writable:!0,value:P}:void 0}})}function F$($){return Y($,l)}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(T($))return V$($);return y($)}function JJ($){if(I$($))return $;if($==null||g($)||M$($))throw new j$("createMutableSignal",$);if(Y$($))return Q$($);if(T($))return V$($);return y($)}function zJ($){return S$($)||p$($)}function M$($){let J=[c,u,d,t,r,S,s,l],z=Object.prototype.toString.call($).slice(8,-1);return J.includes(z)}function I$($){return N$($)||F$($)||R$($)}function XJ($,J){O(r,$,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},Q=()=>{if(m)R(W,m);if(f(W),W.error)throw W.error;return W.value},D=(C)=>{if(!I$(z))throw new P$(r);O(r,C,X),z.set(C)},M=(C)=>{O(r,C,M$),z=C,W.flags|=G;for(let U=W.sinks;U;U=U.nextSink)F(U.sink);if(x===0)I()};return{[Symbol.toStringTag]:r,configurable:!0,enumerable:!0,get:Q,set:D,replace:M,current:()=>z}}function ZJ($){return Y($,r)}export{D$ as valueString,v as untrack,d$ as unown,o$ as match,p$ as isTask,F$ as isStore,N$ as isState,ZJ as isSlot,M$ as isSignal,n$ as isSensor,T as isRecord,Y 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,V$ 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,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};
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 T($){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 O($,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 E($,J,z=g){if(!z(J))throw new b$($,J)}var c="State",u="Memo",d="Task",t="Sensor",S="List",s="Collection",l="Store",r="Slot",p=0,$$=1,G=2,U$=4,b=8,N=null,_=null,C$=[],x=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 R($,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 F($,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)F(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)F(z.sink);if(x===0)I()}function J$($,J){if(!$.cleanup)$.cleanup=J;else if(Array.isArray($.cleanup))$.cleanup.push(J);else $.cleanup=[$.cleanup,J]}function O$($){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=N;N=$,$.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{N=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=N;N=$,$.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{N=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)F(B.sink);if(x===0)I()}},(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)F(D.sink);if(x===0)I()}}),$.flags=p}function T$($){O$($);let J=N,z=_;N=_=$,$.sourcesTail=null,$.flags=U$;try{let X=$.fn();if(typeof X==="function")J$($,X)}finally{N=J,_=z,H$($)}$.flags=p}function f($){if($.flags&$$)for(let J=$.sources;J;J=J.nextSource){if("fn"in J.source)f(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 I(){if(_$)return;_$=!0;try{for(let $=0;$<C$.length;$++){let J=C$[$];if(J.flags&(G|$$))f(J)}C$.length=0}finally{_$=!1}}function z$($){x++;try{$()}finally{if(x--,x===0)I()}}function v($){let J=N;N=null;try{return $()}finally{N=J}}function u$($){let J=_,z={cleanup:null};_=z;try{let X=$();if(typeof X==="function")J$(z,X);let W=()=>O$(z);if(J)J$(J,W);return W}finally{_=J}}function d$($){let J=_;_=null;try{return $()}finally{_=J}}function y($,J){O(c,$,J?.guard);let z={value:$,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard};return{[Symbol.toStringTag]:c,get(){if(N)R(z,N);return z.value},set(X){O(c,X,z.guard),N$(z,X)},update(X){E(c,X);let W=X(z.value);O(c,W,z.guard),N$(z,W)}}}function m$($){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(T($)&&T(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 K$($,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={},C={},U=[],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 P=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(P.has(H))throw new e(S,H,Z);if(U.push(H),P.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(!P.has(q))C[q]=null,Q=!0;if(!Q&&!K$(z,U))Q=!0;return{add:D,change:M,remove:C,newKeys:U,changed:Q}}function Q$($,J){O(S,$,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},C=(Z)=>{let H={};for(let m=0;m<Z.length;m++){let V=Z[m];if(V===void 0)continue;let K=X[m];if(!K)K=W(V),X[m]=K;H[K]=V}return H},U=(Z)=>{let H=!1;for(let m in Z.add){let V=Z.add[m];O(`${S} item for key "${m}"`,V),z.set(m,y(V)),H=!0}if(Object.keys(Z.change).length)z$(()=>{for(let m in Z.change){let V=Z.change[m];O(`${S} item for key "${m}"`,V);let K=z.get(m);if(K)K.set(V)}});for(let m in Z.remove){z.delete(m);let V=X.indexOf(m);if(V!==-1)X.splice(V,1);H=!0}if(H)M.flags|=b;return Z.changed},Q=J?.watched,j=Q?()=>{if(N){if(!M.sinks)M.stop=Q();R(M,N)}}:()=>{if(N)R(M,N)},P=C($);for(let Z in P){let H=P[Z];O(`${S} item for key "${Z}"`,H),z.set(Z,y(H))}M.value=$,M.flags=0;let q={[Symbol.toStringTag]:S,[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,f(M),M.error)throw M.error}else M.flags=p}}else if(f(M),M.error)throw M.error;return M.value},set(Z){let H=M.flags&G?D():M.value,m=t$(H,Z,X,W,B);if(m.changed){X=m.newKeys,U(m),M.flags|=G;for(let V=M.sinks;V;V=V.nextSink)F(V.sink);if(x===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 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(S,H,Z);if(!X.includes(H))X.push(H);O(`${S} item for key "${H}"`,Z),z.set(H,y(Z)),M.flags|=G|b;for(let m=M.sinks;m;m=m.nextSink)F(m.sink);if(x===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|=G|b;for(let K=M.sinks;K;K=K.nextSink)F(K.sink);if(x===0)I()}},sort(Z){let m=X.map((V)=>[V,z.get(V)?.get()]).sort(g(Z)?(V,K)=>Z(V[1],K[1]):(V,K)=>String(V[1]).localeCompare(String(K[1]))).map(([V])=>V);if(!K$(X,m)){X=m,M.flags|=G;for(let V=M.sinks;V;V=V.nextSink)F(V.sink);if(x===0)I()}},splice(Z,H,...m){let V=X.length,K=Z<0?Math.max(0,V+Z):Math.min(Z,V),w=Math.max(0,Math.min(H??Math.max(0,V-Math.max(0,K)),V-K)),A={},L={};for(let h=0;h<w;h++){let a=K+h,w$=X[a];if(w$){let y$=z.get(w$);if(y$)L[w$]=y$.get()}}let f$=X.slice(0,K);for(let h of m){let a=W(h);if(z.has(a)&&!(a in L))throw new e(S,a,h);f$.push(a),A[a]=h}f$.push(...X.slice(K+w));let h$=!!(Object.keys(A).length||Object.keys(L).length);if(h$){U({add:A,change:{},remove:L,changed:h$}),X=f$,M.flags|=G;for(let h=M.sinks;h;h=h.nextSink)F(h.sink);if(x===0)I()}return Object.values(L)},deriveCollection(Z){return x$(q,Z)}};return q}function R$($){return Y($,S)}function B$($,J){if(E(u,$,X$),J?.value!==void 0)O(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(N){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,N)}}:()=>{if(N)R(z,N)};return{[Symbol.toStringTag]:u,get(){if(W(),f(z),z.error)throw z.error;return W$(u,z.value),z.value}}}function S$($){return Y($,u)}function q$($,J){if(E(d,$,o),J?.value!==void 0)O(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(N){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,N)}}:()=>{if(N)R(z,N)};return{[Symbol.toStringTag]:d,get(){if(W(),f(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){E(s,J);let z=o(J),X=new Map,W=[],B=(q)=>{let Z=z?q$(async(H,m)=>{let V=$.byKey(q)?.get();if(V==null)return H;return J(V,m)}):B$(()=>{let H=$.byKey(q)?.get();if(H==null)return;return J(H)});X.set(q,Z)};function D(q){if(!K$(W,q)){let Z=new Set(W),H=new Set(q);for(let m of W)if(!H.has(m))X.delete(m);for(let m of q)if(!Z.has(m))B(m);W=q,U.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 U={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(U.sources){if(U.flags)if(U.value=v(M),U.flags&b){if(U.flags=G,f(U),U.error)throw U.error}else U.flags=p}else if(U.sinks){if(f(U),U.error)throw U.error}else U.value=v(M)}let j=Array.from(v(()=>$.keys()));for(let q of j)B(q);W=j;let P={[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(N)R(U,N);return Q(),W.length},keys(){if(N)R(U,N);return Q(),W.values()},get(){if(N)R(U,N);return Q(),U.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$(P,q)}};return P}function s$($,J){let z=J?.value??[];if(z.length)O(s,z,Array.isArray);E(s,$,X$);let X=new Map,W=[],B=new Map,[D,M]=E$(J?.keyConfig),C=(Z)=>B.get(Z)??(M?D(Z):void 0),U=J?.createItem??y;function Q(){let Z=[];for(let H of W)try{let m=X.get(H)?.get();if(m!=null)Z.push(m)}catch(m){if(!(m instanceof i))throw m}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,U(Z)),B.set(Z,H),W.push(H)}j.value=z,j.flags=G;function P(){if(N){if(!j.sinks)j.stop=$((Z)=>{let{add:H,change:m,remove:V}=Z;if(!H?.length&&!m?.length&&!V?.length)return;let K=!1;z$(()=>{if(H)for(let w of H){let A=D(w);if(X.set(A,U(w)),B.set(w,A),!W.includes(A))W.push(A);K=!0}if(m)for(let w of m){let A=C(w);if(!A)continue;let L=X.get(A);if(L&&m$(L))B.delete(L.get()),L.set(w),B.set(w,A)}if(V)for(let w of V){let A=C(w);if(!A)continue;B.delete(w),X.delete(A);let L=W.indexOf(A);if(L!==-1)W.splice(L,1);K=!0}j.flags=G|(K?b:0);for(let w=j.sinks;w;w=w.nextSink)F(w.sink)})});R(j,N)}}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 P(),W.length},keys(){return P(),W.values()},get(){if(P(),j.sources){if(j.flags){let Z=j.flags&b;if(j.value=v(Q),Z){if(j.flags=G,f(j),j.error)throw j.error}else j.flags=p}}else if(f(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 l$($){return Y($,s)}function r$($){E("Effect",$);let J={fn:$,flags:G,sources:null,sourcesTail:null,cleanup:null},z=()=>{O$(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:W}=J,B,D=!1,M=Array($.length);for(let U=0;U<$.length;U++)try{M[U]=$[U].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=W?.();else if(B)C=X(B);else C=z(M)}catch(U){X([U instanceof Error?U:Error(String(U))])}if(typeof C==="function")return C;if(C instanceof Promise){let U=_,Q=new AbortController;J$(U,()=>Q.abort()),C.then((j)=>{if(!Q.signal.aborted&&typeof j==="function")J$(U,j)}).catch((j)=>{X([j instanceof Error?j:Error(String(j))])})}}function i$($,J){if(E(t,$,X$),J?.value!==void 0)O(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(N){if(!z.sinks)z.stop=$((X)=>{O(t,X,z.guard),N$(z,X)});R(z,N)}return W$(t,z.value),z.value}}}function n$($){return Y($,t)}function a$($,J){let z=T($)||Array.isArray($),X=T(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={},C=!1,U=Object.keys($),Q=Object.keys(J);for(let j of Q)if(j in $){if(!n($[j],J[j],W))D[j]=J[j],C=!0}else B[j]=J[j],C=!0;for(let j of U)if(!(j in J))M[j]=void 0,C=!0;return{add:B,change:D,remove:M,changed:C}}function V$($,J){O(l,$,T);let z=new Map,X=(Q,j)=>{if(O(`${l} for key "${Q}"`,j),Array.isArray(j))z.set(Q,Q$(j));else if(T(j))z.set(Q,V$(j));else z.set(Q,y(j))},W=()=>{let Q={};return z.forEach((j,P)=>{Q[P]=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 P in Q.add)X(P,Q.add[P]),j=!0;if(Object.keys(Q.change).length)z$(()=>{for(let P in Q.change){let q=Q.change[P];O(`${l} for key "${P}"`,q);let Z=z.get(P);if(Z)if(T(q)!==F$(Z))X(P,q),j=!0;else Z.set(q)}});for(let P in Q.remove)z.delete(P),j=!0;if(j)B.flags|=b;return Q.changed},M=J?.watched,C=M?()=>{if(N){if(!B.sinks)B.stop=M();R(B,N)}}:()=>{if(N)R(B,N)};for(let Q of Object.keys($))X(Q,$[Q]);let U={[Symbol.toStringTag]:l,[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 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(W),Q){if(B.flags=G,f(B),B.error)throw B.error}else B.flags=p}}else if(f(B),B.error)throw B.error;return B.value},set(Q){let j=B.flags&G?W():B.value,P=a$(j,Q);if(D(P)){B.flags|=G;for(let q=B.sinks;q;q=q.nextSink)F(q.sink);if(x===0)I()}},update(Q){U.set(Q(U.get()))},add(Q,j){if(z.has(Q))throw new e(l,Q,j);X(Q,j),B.flags|=G|b;for(let P=B.sinks;P;P=P.nextSink)F(P.sink);if(x===0)I();return Q},remove(Q){if(z.delete(Q)){B.flags|=G|b;for(let P=B.sinks;P;P=P.nextSink)F(P.sink);if(x===0)I()}}};return new Proxy(U,{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 P=Q.byKey(String(j));return P?{enumerable:!0,configurable:!0,writable:!0,value:P}:void 0}})}function F$($){return Y($,l)}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(T($))return V$($);return y($)}function JJ($){if(I$($))return $;if($==null||g($)||M$($))throw new j$("createMutableSignal",$);if(Y$($))return Q$($);if(T($))return V$($);return y($)}function zJ($){return S$($)||p$($)}function M$($){let J=[c,u,d,t,r,S,s,l],z=Object.prototype.toString.call($).slice(8,-1);return J.includes(z)}function I$($){return m$($)||F$($)||R$($)}function XJ($,J){O(r,$,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(N)R(W,N);if(f(W),W.error)throw W.error;return W.value},D=(C)=>{if(!I$(z))throw new P$(r);O(r,C,X),z.set(C)},M=(C)=>{O(r,C,M$),z=C,W.flags|=G;for(let U=W.sinks;U;U=U.nextSink)F(U.sink);if(x===0)I()};return{[Symbol.toStringTag]:r,configurable:!0,enumerable:!0,get:B,set:D,replace:M,current:()=>z}}function ZJ($){return Y($,r)}export{D$ as valueString,v as untrack,d$ as unown,o$ as match,p$ as isTask,F$ as isStore,m$ as isState,ZJ as isSlot,M$ as isSignal,n$ as isSensor,T as isRecord,Y 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,V$ 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,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 0.18.5
3
+ * @version 1.0.0
4
4
  * @author Esther Brunner
5
5
  */
6
6
 
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@zeix/cause-effect",
3
- "version": "0.18.5",
3
+ "version": "1.0.0",
4
4
  "author": "Esther Brunner",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "module": "index.ts",
8
8
  "types": "types/index.d.ts",
9
9
  "devDependencies": {
10
- "@biomejs/biome": "2.1.4",
10
+ "@biomejs/biome": "2.4.6",
11
11
  "@types/bun": "latest",
12
12
  "mitata": "^1.0.34",
13
13
  "random": "^5.4.1"
14
14
  },
15
15
  "peerDependencies": {
16
- "typescript": "^5.6.3"
16
+ "typescript": "^5.9.3"
17
17
  },
18
18
  "description": "Cause & Effect - reactive state management primitives library for TypeScript.",
19
19
  "license": "MIT",
@@ -28,7 +28,6 @@
28
28
  },
29
29
  "scripts": {
30
30
  "build": "bunx tsc --project tsconfig.build.json && bun build index.ts --outdir ./ --minify && bun build index.ts --outfile index.dev.js",
31
- "build:next": "bunx tsc --project tsconfig.build.next.json && bun build next.ts --outdir ./ --minify && bun build next.ts --outfile next.dev.js",
32
31
  "bench": "bun run bench/reactivity.bench.ts",
33
32
  "test": "bun test",
34
33
  "lint": "bunx biome lint --write"
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: cause-effect-dev
3
+ description: >
4
+ Expert developer for the @zeix/cause-effect reactive signals library. Use when
5
+ implementing features, fixing bugs, writing tests, or answering questions about
6
+ the library's internals, public API, or design decisions.
7
+ user_invocable: false
8
+ ---
9
+
10
+ # Cause & Effect — Developer Skill
11
+
12
+ You are an expert developer on the **@zeix/cause-effect** reactive state management primitives library (v1.0.0). Work only from authoritative sources listed below. Never guess API shapes or behaviors — read the source.
13
+
14
+ ## Authoritative Sources
15
+
16
+ | What you need | Where to look |
17
+ |---|---|
18
+ | Vision, audience, constraints, non-goals | `REQUIREMENTS.md` |
19
+ | Mental model, non-obvious behaviors, TS constraints | `CLAUDE.md` |
20
+ | Full API reference with examples | `README.md` |
21
+ | Mapping from React/Vue/Angular patterns; when to use each signal type | `GUIDE.md` |
22
+ | Graph engine architecture, node shapes, propagation | `ARCHITECTURE.md` |
23
+ | Public API surface (all exports, types) | `index.ts` |
24
+ | Core graph engine (flags, propagation, flush, ownership) | `src/graph.ts` |
25
+ | Error classes | `src/errors.ts` |
26
+ | Signal base types and type guards | `src/signal.ts` |
27
+ | Shared utilities | `src/util.ts` |
28
+
29
+ ## Source File Map
30
+
31
+ Each signal type lives in its own file:
32
+
33
+ | Signal | File | Create | Type guard |
34
+ |---|---|---|---|
35
+ | State | `src/nodes/state.ts` | `createState()` | `isState()` |
36
+ | Sensor | `src/nodes/sensor.ts` | `createSensor()` | `isSensor()` |
37
+ | Memo | `src/nodes/memo.ts` | `createMemo()` | `isMemo()` |
38
+ | Task | `src/nodes/task.ts` | `createTask()` | `isTask()` |
39
+ | Effect | `src/nodes/effect.ts` | `createEffect()` | — |
40
+ | Slot | `src/nodes/slot.ts` | `createSlot()` | `isSlot()` |
41
+ | Store | `src/nodes/store.ts` | `createStore()` | `isStore()` |
42
+ | List | `src/nodes/list.ts` | `createList()` | `isList()` |
43
+ | Collection | `src/nodes/collection.ts` | `createCollection()` / `deriveCollection()` | `isCollection()` |
44
+
45
+ `match()` and `MatchHandlers` live in `src/nodes/effect.ts` alongside `createEffect`.
46
+
47
+ ## Internal Node Shapes
48
+
49
+ ```
50
+ StateNode<T> — source only
51
+ MemoNode<T> — source + sink (also used by Slot, Store, List, Collection internals)
52
+ TaskNode<T> — source + sink + AbortController
53
+ EffectNode — sink + owner
54
+ Scope — owner only
55
+ ```
56
+
57
+ Two independent global pointers:
58
+ - `activeSink` — tracked for dependency edges (nulled by `untrack()`)
59
+ - `activeOwner` — tracked for cleanup registration (nulled by `unown()`)
60
+
61
+ ## Key API Facts
62
+
63
+ - **`T extends {}`** — all signal generics exclude `null` and `undefined`. Use wrapper types or sentinel values to represent absence.
64
+ - **`createScope(fn)`** — returns a single `Cleanup` function. `fn` receives no arguments and returns an optional cleanup.
65
+ - **`createEffect(fn)`** — returns a `Cleanup`. Must be called inside an owner (effect or scope).
66
+ - **`batch(fn)`** — defers flush until `fn` returns; multiple state writes coalesce into one propagation.
67
+ - **`untrack(fn)`** — runs `fn` without recording dependency edges (nulls `activeSink`).
68
+ - **`unown(fn)`** — runs `fn` without registering cleanup in the current owner (nulls `activeOwner`). Use in `connectedCallback` for DOM-owned lifecycles.
69
+ - **`SKIP_EQUALITY`** — sentinel for `options.equals`; forces propagation on every update (use with mutable-reference sensors).
70
+ - **Memo/Task callbacks receive `prev`** — the previous value as first argument, enabling reducer patterns without external state.
71
+ - **`Slot` is a property descriptor** — has `get`, `set`, `configurable`, `enumerable`; can be passed directly to `Object.defineProperty()`.
72
+
73
+ ## Non-Obvious Behaviors
74
+
75
+ **`byKey()`, `at()`, `keyAt()`, `indexOfKey()` do not create graph edges.** They are direct lookups. To react to structural changes (key added/removed), read `get()`, `keys()`, or `length`.
76
+
77
+ **Conditional reads delay `watched` activation.** Read signals eagerly before conditional logic to ensure `watched` fires immediately:
78
+
79
+ ```typescript
80
+ // Good — both signals tracked on every run
81
+ createEffect(() => {
82
+ match([task, derived], { ok: ([r, v]) => render(v, r), nil: () => showSpinner() })
83
+ })
84
+
85
+ // Bad — derived only tracked after task resolves
86
+ createEffect(() => {
87
+ match([task], { ok: ([r]) => render(derived.get(), r), nil: () => showSpinner() })
88
+ })
89
+ ```
90
+
91
+ **`equals` suppresses entire subtrees.** When a Memo recomputes to the same value, downstream nodes receive `FLAG_CHECK` and are skipped without running. A custom `equals` on an intermediate Memo can suppress whole subgraphs.
92
+
93
+ **`watched` stays stable through mutations.** Structural mutations on a List/Collection source do not restart the `watched` callback; it stays active as long as any downstream effect is subscribed.
94
+
95
+ ## Error Classes
96
+
97
+ | Class | When thrown |
98
+ |---|---|
99
+ | `NullishSignalValueError` | Signal value is `null` or `undefined` |
100
+ | `InvalidSignalValueError` | Value fails the `guard` check |
101
+ | `InvalidCallbackError` | A required callback argument is not a function |
102
+ | `DuplicateKeyError` | List/Collection key collision |
103
+ | `UnsetSignalValueError` | Reading a Sensor/Task before it has produced a value |
104
+ | `ReadonlySignalError` | Writing to a read-only signal |
105
+ | `RequiredOwnerError` | `createEffect` called outside an owner |
106
+ | `CircularDependencyError` | Cycle detected in the graph |
107
+
108
+ ## Workflow
109
+
110
+ 1. **Read before writing.** Always read the relevant source file(s) before proposing or making changes.
111
+ 2. **Check `ARCHITECTURE.md`** for graph-level questions (propagation, ownership, flag semantics).
112
+ 3. **Check `README.md`** for public API usage patterns and option signatures.
113
+ 4. **Check `REQUIREMENTS.md`** before adding anything new — the signal type set is complete and new types are explicitly out of scope.
114
+ 5. **Run `bun test`** after changes to verify correctness.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Cause & Effect Developer"
3
+ short_description: "Expert developer for the @zeix/cause-effect reactive signals library"
4
+ default_prompt: "Use $cause-effect-dev to implement, debug, or explain code using the @zeix/cause-effect library."
package/src/graph.ts CHANGED
@@ -6,12 +6,12 @@ type SourceFields<T extends {}> = {
6
6
  value: T
7
7
  sinks: Edge | null
8
8
  sinksTail: Edge | null
9
- stop?: Cleanup
9
+ stop?: Cleanup | undefined
10
10
  }
11
11
 
12
12
  type OptionsFields<T extends {}> = {
13
13
  equals: (a: T, b: T) => boolean
14
- guard?: Guard<T>
14
+ guard?: Guard<T> | undefined
15
15
  }
16
16
 
17
17
  type SinkFields = {
@@ -323,7 +323,8 @@ function runCleanup(owner: OwnerNode): void {
323
323
  if (!owner.cleanup) return
324
324
 
325
325
  if (Array.isArray(owner.cleanup))
326
- for (let i = 0; i < owner.cleanup.length; i++) owner.cleanup[i]()
326
+ // biome-ignore lint/style/noNonNullAssertion: index is always within bounds of a populated Cleanup[]
327
+ for (let i = 0; i < owner.cleanup.length; i++) owner.cleanup[i]!()
327
328
  else owner.cleanup()
328
329
  owner.cleanup = null
329
330
  }
@@ -471,7 +472,8 @@ function flush(): void {
471
472
  flushing = true
472
473
  try {
473
474
  for (let i = 0; i < queuedEffects.length; i++) {
474
- const effect = queuedEffects[i]
475
+ // biome-ignore lint/style/noNonNullAssertion: index is always within bounds of a populated EffectNode[]
476
+ const effect = queuedEffects[i]!
475
477
  if (effect.flags & (FLAG_DIRTY | FLAG_CHECK)) refresh(effect)
476
478
  }
477
479
  queuedEffects.length = 0
@@ -251,7 +251,8 @@ function deriveCollection<T extends {}, U extends {}>(
251
251
  },
252
252
 
253
253
  at(index: number) {
254
- return signals.get(keys[index])
254
+ const key = keys[index]
255
+ return key !== undefined ? signals.get(key) : undefined
255
256
  },
256
257
 
257
258
  byKey(key: string) {
@@ -452,7 +453,8 @@ function createCollection<T extends {}>(
452
453
  },
453
454
 
454
455
  at(index: number) {
455
- return signals.get(keys[index])
456
+ const key = keys[index]
457
+ return key !== undefined ? signals.get(key) : undefined
456
458
  },
457
459
 
458
460
  byKey(key: string) {
package/src/nodes/list.ts CHANGED
@@ -189,7 +189,8 @@ function diffArrays<T>(
189
189
  const prevByKey = new Map<string, T>()
190
190
  for (let i = 0; i < prev.length; i++) {
191
191
  const key = prevKeys[i]
192
- if (key && prev[i]) prevByKey.set(key, prev[i])
192
+ const item = prev[i]
193
+ if (key && item !== undefined) prevByKey.set(key, item)
193
194
  }
194
195
 
195
196
  // Track which old keys we've seen
@@ -422,7 +423,8 @@ function createList<T extends {}>(
422
423
  },
423
424
 
424
425
  at(index: number) {
425
- return signals.get(keys[index])
426
+ const key = keys[index]
427
+ return key !== undefined ? signals.get(key) : undefined
426
428
  },
427
429
 
428
430
  keys() {
@@ -458,6 +460,7 @@ function createList<T extends {}>(
458
460
  remove(keyOrIndex: string | number) {
459
461
  const key =
460
462
  typeof keyOrIndex === 'number' ? keys[keyOrIndex] : keyOrIndex
463
+ if (key === undefined) return
461
464
  const ok = signals.delete(key)
462
465
  if (ok) {
463
466
  const index =
@@ -298,7 +298,8 @@ for (const framework of [v18]) {
298
298
  Object.fromEntries(heads.map(h => h.read()).entries()),
299
299
  )
300
300
  const splited = heads
301
- .map((_, index) => framework.computed(() => mux.read()[index]))
301
+ // biome-ignore lint/style/noNonNullAssertion: test
302
+ .map((_, index) => framework.computed(() => mux.read()[index]!))
302
303
  .map(x => framework.computed(() => x.read() + 1))
303
304
 
304
305
  for (const x of splited) {
@@ -310,15 +311,19 @@ for (const framework of [v18]) {
310
311
  return () => {
311
312
  for (let i = 0; i < 10; i++) {
312
313
  framework.withBatch(() => {
313
- heads[i].write(i)
314
+ // biome-ignore lint/style/noNonNullAssertion: test
315
+ heads[i]!.write(i)
314
316
  })
315
- expect(splited[i].read()).toBe(i + 1)
317
+ // biome-ignore lint/style/noNonNullAssertion: test
318
+ expect(splited[i]!.read()).toBe(i + 1)
316
319
  }
317
320
  for (let i = 0; i < 10; i++) {
318
321
  framework.withBatch(() => {
319
- heads[i].write(i * 2)
322
+ // biome-ignore lint/style/noNonNullAssertion: test
323
+ heads[i]!.write(i * 2)
320
324
  })
321
- expect(splited[i].read()).toBe(i * 2 + 1)
325
+ // biome-ignore lint/style/noNonNullAssertion: test
326
+ expect(splited[i]!.read()).toBe(i * 2 + 1)
322
327
  }
323
328
  }
324
329
  })
@@ -455,16 +460,19 @@ for (const framework of [v18]) {
455
460
  })),
456
461
  )
457
462
  const E = framework.computed(() =>
458
- hard(C.read() + A.read() + D.read()[0].x, 'E'),
463
+ // biome-ignore lint/style/noNonNullAssertion: test
464
+ hard(C.read() + A.read() + D.read()[0]!.x, 'E'),
459
465
  )
460
466
  const F = framework.computed(() =>
461
- hard(D.read()[2].x || B.read(), 'F'),
467
+ // biome-ignore lint/style/noNonNullAssertion: test
468
+ hard(D.read()[2]!.x || B.read(), 'F'),
462
469
  )
463
470
  const G = framework.computed(
464
471
  () =>
465
472
  C.read() +
466
473
  (C.read() || E.read() % 2) +
467
- D.read()[4].x +
474
+ // biome-ignore lint/style/noNonNullAssertion: test
475
+ D.read()[4]!.x +
468
476
  F.read(),
469
477
  )
470
478
  framework.effect(() => {
@@ -527,10 +535,16 @@ for (const framework of [v18]) {
527
535
  prop3: framework.signal(3),
528
536
  prop4: framework.signal(4),
529
537
  }
530
- let layer: Record<string, Computed<number>> = start
538
+ type CellxLayer = {
539
+ prop1: Computed<number>
540
+ prop2: Computed<number>
541
+ prop3: Computed<number>
542
+ prop4: Computed<number>
543
+ }
544
+ let layer: CellxLayer = start
531
545
 
532
546
  for (let i = layers; i > 0; i--) {
533
- const m = layer
547
+ const m: CellxLayer = layer
534
548
  const s = {
535
549
  prop1: framework.computed(() => m.prop2.read()),
536
550
  prop2: framework.computed(
@@ -598,7 +612,7 @@ for (const framework of [v18]) {
598
612
  end.prop4.read(),
599
613
  ]
600
614
 
601
- return [before, after]
615
+ return [before, after] as [number[], number[]]
602
616
  }
603
617
 
604
618
  for (const layers in expected) {
@@ -498,9 +498,12 @@ describe('Collection', () => {
498
498
 
499
499
  const signals = [...doubled]
500
500
  expect(signals).toHaveLength(3)
501
- expect(signals[0].get()).toBe(2)
502
- expect(signals[1].get()).toBe(4)
503
- expect(signals[2].get()).toBe(6)
501
+ // biome-ignore lint/style/noNonNullAssertion: test
502
+ expect(signals[0]!.get()).toBe(2)
503
+ // biome-ignore lint/style/noNonNullAssertion: test
504
+ expect(signals[1]!.get()).toBe(4)
505
+ // biome-ignore lint/style/noNonNullAssertion: test
506
+ expect(signals[2]!.get()).toBe(6)
504
507
  })
505
508
 
506
509
  test('should react to source additions', () => {
@@ -414,7 +414,8 @@ describe('match', () => {
414
414
  },
415
415
  err: errors => {
416
416
  errCount++
417
- expect(errors[0].message).toBe('Too high')
417
+ // biome-ignore lint/style/noNonNullAssertion: test
418
+ expect(errors[0]!.message).toBe('Too high')
418
419
  },
419
420
  }),
420
421
  )
package/test/list.test.ts CHANGED
@@ -323,7 +323,8 @@ describe('List', () => {
323
323
  const list = createList([10, 20, 30])
324
324
  const allKeys = [...list.keys()]
325
325
  expect(allKeys).toHaveLength(3)
326
- expect(list.byKey(allKeys[0])?.get()).toBe(10)
326
+ // biome-ignore lint/style/noNonNullAssertion: test
327
+ expect(list.byKey(allKeys[0]!)?.get()).toBe(10)
327
328
  })
328
329
  })
329
330
 
@@ -353,9 +354,12 @@ describe('List', () => {
353
354
  const list = createList([10, 20, 30])
354
355
  const signals = [...list]
355
356
  expect(signals).toHaveLength(3)
356
- expect(signals[0].get()).toBe(10)
357
- expect(signals[1].get()).toBe(20)
358
- expect(signals[2].get()).toBe(30)
357
+ // biome-ignore lint/style/noNonNullAssertion: test
358
+ expect(signals[0]!.get()).toBe(10)
359
+ // biome-ignore lint/style/noNonNullAssertion: test
360
+ expect(signals[1]!.get()).toBe(20)
361
+ // biome-ignore lint/style/noNonNullAssertion: test
362
+ expect(signals[2]!.get()).toBe(30)
359
363
  })
360
364
  })
361
365
 
@@ -66,7 +66,8 @@ describe('Bundle size', () => {
66
66
  entrypoints: ['./index.ts'],
67
67
  minify: true,
68
68
  })
69
- const bytes = await result.outputs[0].arrayBuffer()
69
+ // biome-ignore lint/style/noNonNullAssertion: test
70
+ const bytes = await result.outputs[0]!.arrayBuffer()
70
71
  check('bundleMinified', bytes.byteLength, BUNDLE_MARGIN, 'B')
71
72
  })
72
73
 
@@ -75,7 +76,8 @@ describe('Bundle size', () => {
75
76
  entrypoints: ['./index.ts'],
76
77
  minify: true,
77
78
  })
78
- const bytes = await result.outputs[0].arrayBuffer()
79
+ // biome-ignore lint/style/noNonNullAssertion: test
80
+ const bytes = await result.outputs[0]!.arrayBuffer()
79
81
  const gzipped = gzipSync(new Uint8Array(bytes)).byteLength
80
82
  check('bundleGzipped', gzipped, BUNDLE_MARGIN, 'B')
81
83
  })
@@ -322,10 +322,14 @@ describe('Store', () => {
322
322
  const user = createStore({ name: 'John', age: 25 })
323
323
  const entries = [...user]
324
324
  expect(entries).toHaveLength(2)
325
- expect(entries[0][0]).toBe('name')
326
- expect(entries[0][1].get()).toBe('John')
327
- expect(entries[1][0]).toBe('age')
328
- expect(entries[1][1].get()).toBe(25)
325
+ // biome-ignore lint/style/noNonNullAssertion: test
326
+ expect(entries[0]![0]).toBe('name')
327
+ // biome-ignore lint/style/noNonNullAssertion: test
328
+ expect(entries[0]![1].get()).toBe('John')
329
+ // biome-ignore lint/style/noNonNullAssertion: test
330
+ expect(entries[1]![0]).toBe('age')
331
+ // biome-ignore lint/style/noNonNullAssertion: test
332
+ expect(entries[1]![1].get()).toBe(25)
329
333
  })
330
334
 
331
335
  test('should maintain property key ordering', () => {
@@ -53,7 +53,8 @@ export function runGraph(
53
53
  ): number {
54
54
  const rand = new Random('seed')
55
55
  const { sources, layers } = graph
56
- const leaves = layers[layers.length - 1]
56
+ // biome-ignore lint/style/noNonNullAssertion: test
57
+ const leaves = layers[layers.length - 1]!
57
58
  const skipCount = Math.round(leaves.length * (1 - readFraction))
58
59
  const readLeaves = removeElems(leaves, skipCount, rand)
59
60
  const frameworkName = framework.name.toLowerCase()
@@ -65,7 +66,8 @@ export function runGraph(
65
66
  for (let i = 0; i < iterations; i++) {
66
67
  framework.withBatch(() => {
67
68
  const sourceDex = i % sources.length
68
- sources[sourceDex].write(i + sourceDex)
69
+ // biome-ignore lint/style/noNonNullAssertion: test
70
+ sources[sourceDex]!.write(i + sourceDex)
69
71
  })
70
72
 
71
73
  for (const leaf of readLeaves) {
@@ -87,7 +89,8 @@ export function runGraph(
87
89
  } */
88
90
 
89
91
  const sourceDex = i % sources.length
90
- sources[sourceDex].write(i + sourceDex)
92
+ // biome-ignore lint/style/noNonNullAssertion: test
93
+ sources[sourceDex]!.write(i + sourceDex)
91
94
 
92
95
  for (const leaf of readLeaves) {
93
96
  leaf.read()
@@ -153,7 +156,8 @@ function makeRow(
153
156
  return sources.map((_, myDex) => {
154
157
  const mySources: Computed<number>[] = []
155
158
  for (let sourceDex = 0; sourceDex < nSources; sourceDex++) {
156
- mySources.push(sources[(myDex + sourceDex) % sources.length])
159
+ // biome-ignore lint/style/noNonNullAssertion: test
160
+ mySources.push(sources[(myDex + sourceDex) % sources.length]!)
157
161
  }
158
162
 
159
163
  const staticNode = random.float() < staticFraction
@@ -170,7 +174,8 @@ function makeRow(
170
174
  })
171
175
  } else {
172
176
  // dynamic node, drops one of the sources depending on the value of the first element
173
- const first = mySources[0]
177
+ // biome-ignore lint/style/noNonNullAssertion: test
178
+ const first = mySources[0]!
174
179
  const tail = mySources.slice(1)
175
180
  const node = framework.computed(() => {
176
181
  counter.count++
@@ -180,7 +185,8 @@ function makeRow(
180
185
 
181
186
  for (let i = 0; i < tail.length; i++) {
182
187
  if (shouldDrop && i === dropDex) continue
183
- sum += tail[i].read()
188
+ // biome-ignore lint/style/noNonNullAssertion: test
189
+ sum += tail[i]!.read()
184
190
  }
185
191
 
186
192
  return sum
package/tsconfig.json CHANGED
@@ -19,6 +19,10 @@
19
19
  // Best practices
20
20
  "strict": true,
21
21
  "skipLibCheck": true,
22
+ "noUncheckedIndexedAccess": true,
23
+ "exactOptionalPropertyTypes": true,
24
+ "useUnknownInCatchVariables": true,
25
+ "noUncheckedSideEffectImports": true,
22
26
  "noFallthroughCasesInSwitch": true,
23
27
 
24
28
  // Some stricter flags (disabled by default)
@@ -27,5 +31,5 @@
27
31
  "noPropertyAccessFromIndexSignature": false,
28
32
  },
29
33
  "include": ["./**/*.ts"],
30
- "exclude": ["node_modules", "types"],
34
+ "exclude": ["node_modules", "types", "index.js"],
31
35
  }
package/types/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @name Cause & Effect
3
- * @version 0.18.5
3
+ * @version 1.0.0
4
4
  * @author Esther Brunner
5
5
  */
6
6
  export { CircularDependencyError, type Guard, InvalidCallbackError, InvalidSignalValueError, NullishSignalValueError, ReadonlySignalError, RequiredOwnerError, UnsetSignalValueError, } from './src/errors';
@@ -3,11 +3,11 @@ type SourceFields<T extends {}> = {
3
3
  value: T;
4
4
  sinks: Edge | null;
5
5
  sinksTail: Edge | null;
6
- stop?: Cleanup;
6
+ stop?: Cleanup | undefined;
7
7
  };
8
8
  type OptionsFields<T extends {}> = {
9
9
  equals: (a: T, b: T) => boolean;
10
- guard?: Guard<T>;
10
+ guard?: Guard<T> | undefined;
11
11
  };
12
12
  type SinkFields = {
13
13
  fn: unknown;
package/OWNERSHIP_BUG.md DELETED
@@ -1,95 +0,0 @@
1
- # Ownership Bug: Component Scope Disposed by Parent Effect
2
-
3
- ## Symptom
4
-
5
- In `module-todo`, `form-checkbox` elements wired via `checkboxes: pass(...)` lose their
6
- reactive effects after the initial render — `setProperty('checked')` stops updating
7
- `input.checked`, and the `on('change')` event listener is silently removed. Reading
8
- `fc.checked` (a pull) still works correctly, but reactive push is gone.
9
-
10
- ## Root Cause
11
-
12
- `createScope` registers its `dispose` on `prevOwner` — the `activeOwner` at the time the
13
- scope is created. This is the right behavior for *hierarchical component trees* where a
14
- parent component logically owns its children. But custom elements have a different ownership
15
- model: **the DOM owns them**, via `connectedCallback` / `disconnectedCallback`.
16
-
17
- The problem arises when a custom element's `connectedCallback` fires *inside* a
18
- re-runnable reactive effect:
19
-
20
- 1. `module-todo`'s list sync effect runs inside `flush()` with `activeOwner = listSyncEffect`.
21
- 2. `list.append(li)` connects the `<li>`, which connects the `<form-checkbox>` inside it.
22
- 3. `form-checkbox.connectedCallback()` calls `runEffects(ui, setup(ui))`, which calls
23
- `createScope`. `prevOwner = listSyncEffect`, so `dispose` is **registered on
24
- `listSyncEffect`**.
25
- 4. Later, the `items = all('li[data-key]')` MutationObserver fires (the DOM mutation from
26
- step 2 is detected) and re-queues `listSyncEffect`.
27
- 5. `runEffect(listSyncEffect)` calls `runCleanup(listSyncEffect)`, which calls all
28
- registered cleanups — including `form-checkbox`'s `dispose`.
29
- 6. `dispose()` runs `runCleanup(fc1Scope)`, which removes the `on('change')` event
30
- listener and trims the `setProperty` effect's reactive subscriptions.
31
- 7. The `<form-checkbox>` elements are still in the DOM, but their effects are permanently
32
- gone. `connectedCallback` does not re-fire on already-connected elements.
33
-
34
- The same problem recurs whenever `listSyncEffect` re-runs for any reason (e.g. a new todo
35
- is added), disposing the scopes of all existing `<form-checkbox>` elements.
36
-
37
- ## Why `unown` Is the Correct Fix
38
-
39
- `createScope`'s "register on `prevOwner`" semantics model one ownership relationship:
40
- *parent reactive scope owns child*. Custom elements model a different one: *the DOM owns
41
- the component*. `disconnectedCallback` is the authoritative cleanup trigger, not the
42
- reactive graph.
43
-
44
- `unown` is the explicit handshake that says "this scope is DOM-owned". It prevents
45
- `createScope` from registering `dispose` on whatever reactive effect happens to be running
46
- when `connectedCallback` fires, while leaving `this.#cleanup` + `disconnectedCallback` as
47
- the sole lifecycle authority.
48
-
49
- A `createScope`-only approach (without `unown`) has two failure modes:
50
-
51
- | Scenario | Problem |
52
- |---|---|
53
- | Connects in static DOM (`activeOwner = null`) | `dispose` is discarded; effects never cleaned up on disconnect — memory leak |
54
- | Connects inside a re-runnable effect | Same disposal bug as described above |
55
-
56
- Per-item scopes (manually tracking a `Map<key, Cleanup>`) could also fix the disposal
57
- problem but require significant restructuring of the list sync effect and still need
58
- `unown` to prevent re-registration on each effect re-run.
59
-
60
- ## Required Changes
61
-
62
- ### `@zeix/cause-effect`
63
-
64
- **`src/graph.ts`** — Add `unown` next to `untrack`:
65
-
66
- ```typescript
67
- /**
68
- * Runs a callback without any active owner.
69
- * Any scopes or effects created inside the callback will not be registered as
70
- * children of the current active owner (e.g. a re-runnable effect). Use this
71
- * when a component or resource manages its own lifecycle independently of the
72
- * reactive graph.
73
- *
74
- * @since 0.18.5
75
- */
76
- function unown<T>(fn: () => T): T {
77
- const prev = activeOwner
78
- activeOwner = null
79
- try {
80
- return fn()
81
- } finally {
82
- activeOwner = prev
83
- }
84
- }
85
- ```
86
-
87
- Export it from the internal graph exports and from **`index.ts`**:
88
-
89
- ```typescript
90
- export {
91
- // ...existing exports...
92
- unown,
93
- untrack,
94
- } from './src/graph'
95
- ```