@vielzeug/ripple 2.2.4 → 3.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.
Files changed (51) hide show
  1. package/README.md +10 -32
  2. package/dist/_async.cjs +1 -1
  3. package/dist/_async.cjs.map +1 -1
  4. package/dist/_async.d.ts.map +1 -1
  5. package/dist/_async.js +33 -34
  6. package/dist/_async.js.map +1 -1
  7. package/dist/_default.cjs +1 -1
  8. package/dist/_default.cjs.map +1 -1
  9. package/dist/_default.d.ts +19 -8
  10. package/dist/_default.d.ts.map +1 -1
  11. package/dist/_default.js +22 -15
  12. package/dist/_default.js.map +1 -1
  13. package/dist/_subscribable.cjs +2 -0
  14. package/dist/_subscribable.cjs.map +1 -0
  15. package/dist/_subscribable.d.ts +17 -0
  16. package/dist/_subscribable.d.ts.map +1 -0
  17. package/dist/_subscribable.js +46 -0
  18. package/dist/_subscribable.js.map +1 -0
  19. package/dist/_watch.cjs +1 -1
  20. package/dist/_watch.cjs.map +1 -1
  21. package/dist/_watch.d.ts +1 -0
  22. package/dist/_watch.d.ts.map +1 -1
  23. package/dist/_watch.js +14 -5
  24. package/dist/_watch.js.map +1 -1
  25. package/dist/errors.cjs +1 -1
  26. package/dist/errors.cjs.map +1 -1
  27. package/dist/errors.d.ts +8 -0
  28. package/dist/errors.d.ts.map +1 -1
  29. package/dist/errors.js +14 -3
  30. package/dist/errors.js.map +1 -1
  31. package/dist/index.cjs +1 -1
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.ts +4 -2
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +5 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/ripple.cjs +1 -1
  38. package/dist/ripple.cjs.map +1 -1
  39. package/dist/ripple.iife.js +1 -1
  40. package/dist/ripple.iife.js.map +1 -1
  41. package/dist/ripple.js +1 -1
  42. package/dist/ripple.js.map +1 -1
  43. package/dist/runtime.cjs +1 -1
  44. package/dist/runtime.cjs.map +1 -1
  45. package/dist/runtime.d.ts +19 -7
  46. package/dist/runtime.d.ts.map +1 -1
  47. package/dist/runtime.js +79 -45
  48. package/dist/runtime.js.map +1 -1
  49. package/dist/types.d.ts +34 -13
  50. package/dist/types.d.ts.map +1 -1
  51. package/package.json +9 -8
package/README.md CHANGED
@@ -1,23 +1,21 @@
1
1
  # @vielzeug/ripple
2
2
 
3
- Framework-agnostic reactive graphs. Zero dependencies. ESM and CJS.
3
+ > Reactive runtime primitives: signals, derived values, effects, scopes, watchers, and async resources
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```sh
8
8
  pnpm add @vielzeug/ripple
9
+ npm install @vielzeug/ripple
10
+ yarn add @vielzeug/ripple
9
11
  ```
10
12
 
11
- ## Reactive graph
13
+ ## Quick Start
12
14
 
13
15
  ```ts
14
16
  import { createRipple } from '@vielzeug/ripple';
15
17
 
16
- const ripple = createRipple({
17
- onError(error, context) {
18
- console.error(context.kind, error);
19
- },
20
- });
18
+ const ripple = createRipple();
21
19
 
22
20
  const count = ripple.signal(0);
23
21
  const doubled = ripple.computed(() => count.value * 2);
@@ -32,34 +30,14 @@ stop.dispose();
32
30
  ripple.dispose();
33
31
  ```
34
32
 
35
- `ripple.dispose()` is terminal: create a new graph instead of reusing a disposed one. Use default exports (`signal`, `computed`, `effect`, `batch`, `watch`, `resource`) only when application has one graph for full lifetime.
36
-
37
- ## Bound helpers
38
-
39
- Every `Ripple` instance provides bound helpers:
40
-
41
- ```ts
42
- const user = ripple.resource(() => userId.value, loadUser);
43
- const cart = ripple.signal({ items: 0 });
44
- const stop = ripple.watch(() => cart.value.items, renderItems);
45
- ```
46
-
47
- Resource source and loader failures are handled through `resource.value.status === 'error'`; `onError` receives broken runtime callbacks, cleanup, listeners, and observers.
48
-
49
- Nested effects and resources created inside an effect automatically dispose before parent effect reruns:
50
-
51
- ```ts
52
- ripple.effect(() => {
53
- ripple.effect(() => render())
54
- })
55
- ```
56
-
57
33
  ## Documentation
58
34
 
59
35
  - [Overview](https://vielzeug.dev/ripple/)
60
- - [Usage guide](https://vielzeug.dev/ripple/usage)
61
- - [API reference](https://vielzeug.dev/ripple/api)
36
+ - [Usage Guide](https://vielzeug.dev/ripple/usage)
37
+ - [API Reference](https://vielzeug.dev/ripple/api)
38
+ - [Examples](https://vielzeug.dev/ripple/examples)
39
+ - [Migration Guide](https://vielzeug.dev/ripple/migration)
62
40
 
63
41
  ## License
64
42
 
65
- MIT © Helmuth Saatkamp
43
+ MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
package/dist/_async.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const e=require("./runtime.cjs");var t=t=>(n,r,i)=>{let a=t.signal({status:`pending`},{name:i?.name}),o=t.signal(0),s,c=!1,l=()=>{o.value,s?.abort();let e=a.peek(),t=e.status===`success`?e.value:`previous`in e?e.previous:void 0,i;try{i=n()}catch(e){a.value=t===void 0?{error:e,status:`error`}:{error:e,previous:t,status:`error`};return}let l=new AbortController;s=l,a.value=t===void 0?{status:`pending`}:{previous:t,status:`pending`};let u;try{u=Promise.resolve(r(i,{signal:l.signal}))}catch(e){u=Promise.reject(e)}u.then(e=>{!c&&!l.signal.aborted&&(a.value={status:`success`,value:e})},e=>{!c&&!l.signal.aborted&&(a.value=t===void 0?{error:e,status:`error`}:{error:e,previous:t,status:`error`})})},u=t.effect(()=>(l(),()=>s?.abort()),{name:i?.name});u.disposalSignal.addEventListener(`abort`,()=>{c=!0},{once:!0});let d={get disposalSignal(){return u.disposalSignal},dispose:()=>u.dispose(),get disposed(){return c},get name(){return a.name},peek:()=>a.peek(),reload:()=>{c||(o.value=o.peek()+1)},subscribe:e=>a.subscribe(e),[Symbol.dispose](){this.dispose()},get value(){return a.value}};return Object.defineProperty(d,e.REACTIVE,{value:!0}),d};exports.createResource=t;
1
+ const e=require("./errors.cjs"),t=require("./runtime.cjs");var n=n=>(r,i,a)=>{let o=n.signal({status:`pending`},{name:a?.name}),s=n.signal(0),c,l=!1,u,d=()=>{s.value,c?.abort();let e;try{e=r()}catch(e){o.value=l?{error:e,previous:u,status:`error`}:{error:e,status:`error`};return}let t=new AbortController;c=t,o.value=l?{previous:u,status:`pending`}:{status:`pending`};let n;try{n=Promise.resolve(i(e,{signal:t.signal}))}catch(e){n=Promise.reject(e)}n.then(e=>{!f.disposed&&!t.signal.aborted&&(l=!0,u=e,o.value={status:`success`,value:e})},e=>{!f.disposed&&!t.signal.aborted&&(o.value=l?{error:e,previous:u,status:`error`}:{error:e,status:`error`})})},f=n.effect(()=>(d(),()=>c?.abort()),{name:a?.name}),p=()=>{if(f.disposed)throw new e.RippleDisposedResourceError(`Cannot use a disposed resource.`)},m={get disposalSignal(){return f.disposalSignal},dispose:()=>f.dispose(),get disposed(){return f.disposed},get name(){return o.name},peek:()=>o.peek(),reload:()=>{p(),s.value=s.peek()+1},subscribe:e=>(p(),o.subscribe(e)),[Symbol.dispose](){this.dispose()},get value(){return o.value}};return Object.defineProperty(m,t.REACTIVE,{value:!0}),m};exports.createResource=n;
2
2
  //# sourceMappingURL=_async.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_async.cjs","names":[],"sources":["../src/_async.ts"],"sourcesContent":["import { REACTIVE } from './runtime';\nimport type { Disposable, EffectHandle, Readable, Signal } from './types';\n\nexport type AsyncState<T> =\n | { readonly previous?: T; readonly status: 'pending' }\n | { readonly status: 'success'; readonly value: T }\n | { readonly error: unknown; readonly previous?: T; readonly status: 'error' };\n\nexport interface Resource<T> extends Readable<AsyncState<T>>, Disposable {\n reload(): void;\n}\n\nexport type ResourceOptions = {\n name?: string;\n};\n\ntype AsyncRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n signal<T>(initial: T, options?: { name?: string }): Signal<T>;\n};\n\n/** Resource only depends on primitive runtime methods; graph binding stays private. */\nexport const createResource =\n (runtime: AsyncRuntime) =>\n <Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value> => {\n const state = runtime.signal<AsyncState<Value>>({ status: 'pending' }, { name: options?.name });\n const reloadEpoch = runtime.signal(0);\n let active: AbortController | undefined;\n let disposed = false;\n\n const run = (): void => {\n void reloadEpoch.value;\n active?.abort();\n\n const current = state.peek();\n const previous =\n current.status === 'success' ? current.value : 'previous' in current ? current.previous : undefined;\n let input: Source;\n\n try {\n input = source();\n } catch (error) {\n state.value = previous === undefined ? { error, status: 'error' } : { error, previous, status: 'error' };\n\n return;\n }\n\n const next = new AbortController();\n\n active = next;\n state.value = previous === undefined ? { status: 'pending' } : { previous, status: 'pending' };\n\n let request: Promise<Value>;\n\n try {\n request = Promise.resolve(loader(input, { signal: next.signal }));\n } catch (error) {\n request = Promise.reject(error);\n }\n\n void request.then(\n (value) => {\n if (!disposed && !next.signal.aborted) state.value = { status: 'success', value };\n },\n (error: unknown) => {\n if (!disposed && !next.signal.aborted) {\n state.value = previous === undefined ? { error, status: 'error' } : { error, previous, status: 'error' };\n }\n },\n );\n };\n\n const stop = runtime.effect(\n () => {\n run();\n\n return () => active?.abort();\n },\n { name: options?.name },\n );\n\n stop.disposalSignal.addEventListener(\n 'abort',\n () => {\n disposed = true;\n },\n { once: true },\n );\n\n const resource: Resource<Value> = {\n get disposalSignal() {\n return stop.disposalSignal;\n },\n dispose: () => stop.dispose(),\n get disposed() {\n return disposed;\n },\n get name() {\n return state.name;\n },\n peek: () => state.peek(),\n reload: () => {\n if (disposed) return;\n\n reloadEpoch.value = reloadEpoch.peek() + 1;\n },\n subscribe: (listener) => state.subscribe(listener),\n [Symbol.dispose]() {\n this.dispose();\n },\n get value() {\n return state.value;\n },\n };\n\n Object.defineProperty(resource, REACTIVE, { value: true });\n\n return resource;\n };\n"],"mappings":"iCAsBA,IAAa,EACV,IAEC,EACA,EACA,IACoB,CACpB,IAAM,EAAQ,EAAQ,OAA0B,CAAE,OAAQ,SAAU,EAAG,CAAE,KAAM,GAAS,IAAK,CAAC,EACxF,EAAc,EAAQ,OAAO,CAAC,EAChC,EACA,EAAW,GAET,MAAkB,CACtB,EAAiB,MACjB,GAAQ,MAAM,EAEd,IAAM,EAAU,EAAM,KAAK,EACrB,EACJ,EAAQ,SAAW,UAAY,EAAQ,MAAQ,aAAc,EAAU,EAAQ,SAAW,IAAA,GACxF,EAEJ,GAAI,CACF,EAAQ,EAAO,CACjB,OAAS,EAAO,CACd,EAAM,MAAQ,IAAa,IAAA,GAAY,CAAE,QAAO,OAAQ,OAAQ,EAAI,CAAE,QAAO,WAAU,OAAQ,OAAQ,EAEvG,MACF,CAEA,IAAM,EAAO,IAAI,gBAEjB,EAAS,EACT,EAAM,MAAQ,IAAa,IAAA,GAAY,CAAE,OAAQ,SAAU,EAAI,CAAE,WAAU,OAAQ,SAAU,EAE7F,IAAI,EAEJ,GAAI,CACF,EAAU,QAAQ,QAAQ,EAAO,EAAO,CAAE,OAAQ,EAAK,MAAO,CAAC,CAAC,CAClE,OAAS,EAAO,CACd,EAAU,QAAQ,OAAO,CAAK,CAChC,CAEA,EAAa,KACV,GAAU,CACL,CAAC,GAAY,CAAC,EAAK,OAAO,UAAS,EAAM,MAAQ,CAAE,OAAQ,UAAW,OAAM,EAClF,EACC,GAAmB,CACd,CAAC,GAAY,CAAC,EAAK,OAAO,UAC5B,EAAM,MAAQ,IAAa,IAAA,GAAY,CAAE,QAAO,OAAQ,OAAQ,EAAI,CAAE,QAAO,WAAU,OAAQ,OAAQ,EAE3G,CACF,CACF,EAEM,EAAO,EAAQ,YAEjB,EAAI,MAES,GAAQ,MAAM,GAE7B,CAAE,KAAM,GAAS,IAAK,CACxB,EAEA,EAAK,eAAe,iBAClB,YACM,CACJ,EAAW,EACb,EACA,CAAE,KAAM,EAAK,CACf,EAEA,IAAM,EAA4B,CAChC,IAAI,gBAAiB,CACnB,OAAO,EAAK,cACd,EACA,YAAe,EAAK,QAAQ,EAC5B,IAAI,UAAW,CACb,OAAO,CACT,EACA,IAAI,MAAO,CACT,OAAO,EAAM,IACf,EACA,SAAY,EAAM,KAAK,EACvB,WAAc,CACR,IAEJ,EAAY,MAAQ,EAAY,KAAK,EAAI,EAC3C,EACA,UAAY,GAAa,EAAM,UAAU,CAAQ,EACjD,CAAC,OAAO,UAAW,CACjB,KAAK,QAAQ,CACf,EACA,IAAI,OAAQ,CACV,OAAO,EAAM,KACf,CACF,EAIA,OAFA,OAAO,eAAe,EAAU,EAAA,SAAU,CAAE,MAAO,EAAK,CAAC,EAElD,CACT"}
1
+ {"version":3,"file":"_async.cjs","names":[],"sources":["../src/_async.ts"],"sourcesContent":["import { RippleDisposedResourceError } from './errors';\nimport { REACTIVE } from './runtime';\nimport type { Disposable, EffectHandle, Readable, Signal } from './types';\n\nexport type AsyncState<T> =\n | { readonly previous?: T; readonly status: 'pending' }\n | { readonly status: 'success'; readonly value: T }\n | { readonly error: unknown; readonly previous?: T; readonly status: 'error' };\n\nexport interface Resource<T> extends Readable<AsyncState<T>>, Disposable {\n reload(): void;\n}\n\nexport type ResourceOptions = {\n name?: string;\n};\n\ntype AsyncRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n signal<T>(initial: T, options?: { name?: string }): Signal<T>;\n};\n\n/** Resource only depends on primitive runtime methods; graph binding stays private. */\nexport const createResource =\n (runtime: AsyncRuntime) =>\n <Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value> => {\n const state = runtime.signal<AsyncState<Value>>({ status: 'pending' }, { name: options?.name });\n const reloadEpoch = runtime.signal(0);\n let active: AbortController | undefined;\n let hasPrevious = false;\n let previousValue: Value | undefined;\n\n const run = (): void => {\n void reloadEpoch.value;\n active?.abort();\n\n let input: Source;\n\n try {\n input = source();\n } catch (error) {\n state.value = hasPrevious\n ? { error, previous: previousValue as Value, status: 'error' }\n : { error, status: 'error' };\n\n return;\n }\n\n const next = new AbortController();\n\n active = next;\n state.value = hasPrevious ? { previous: previousValue as Value, status: 'pending' } : { status: 'pending' };\n\n let request: Promise<Value>;\n\n try {\n request = Promise.resolve(loader(input, { signal: next.signal }));\n } catch (error) {\n request = Promise.reject(error);\n }\n\n void request.then(\n (value) => {\n if (!stop.disposed && !next.signal.aborted) {\n hasPrevious = true;\n previousValue = value;\n state.value = { status: 'success', value };\n }\n },\n (error: unknown) => {\n if (!stop.disposed && !next.signal.aborted) {\n state.value = hasPrevious\n ? { error, previous: previousValue as Value, status: 'error' }\n : { error, status: 'error' };\n }\n },\n );\n };\n\n const stop = runtime.effect(\n () => {\n run();\n\n return () => active?.abort();\n },\n { name: options?.name },\n );\n\n const assertActive = (): void => {\n if (stop.disposed) throw new RippleDisposedResourceError('Cannot use a disposed resource.');\n };\n const resource: Resource<Value> = {\n get disposalSignal() {\n return stop.disposalSignal;\n },\n dispose: () => stop.dispose(),\n get disposed() {\n return stop.disposed;\n },\n get name() {\n return state.name;\n },\n peek: () => state.peek(),\n reload: () => {\n assertActive();\n reloadEpoch.value = reloadEpoch.peek() + 1;\n },\n subscribe: (listener) => {\n assertActive();\n return state.subscribe(listener);\n },\n [Symbol.dispose]() {\n this.dispose();\n },\n get value() {\n return state.value;\n },\n };\n\n Object.defineProperty(resource, REACTIVE, { value: true });\n\n return resource;\n };\n"],"mappings":"2DAuBA,IAAa,EACV,IAEC,EACA,EACA,IACoB,CACpB,IAAM,EAAQ,EAAQ,OAA0B,CAAE,OAAQ,SAAU,EAAG,CAAE,KAAM,GAAS,IAAK,CAAC,EACxF,EAAc,EAAQ,OAAO,CAAC,EAChC,EACA,EAAc,GACd,EAEE,MAAkB,CACtB,EAAiB,MACjB,GAAQ,MAAM,EAEd,IAAI,EAEJ,GAAI,CACF,EAAQ,EAAO,CACjB,OAAS,EAAO,CACd,EAAM,MAAQ,EACV,CAAE,QAAO,SAAU,EAAwB,OAAQ,OAAQ,EAC3D,CAAE,QAAO,OAAQ,OAAQ,EAE7B,MACF,CAEA,IAAM,EAAO,IAAI,gBAEjB,EAAS,EACT,EAAM,MAAQ,EAAc,CAAE,SAAU,EAAwB,OAAQ,SAAU,EAAI,CAAE,OAAQ,SAAU,EAE1G,IAAI,EAEJ,GAAI,CACF,EAAU,QAAQ,QAAQ,EAAO,EAAO,CAAE,OAAQ,EAAK,MAAO,CAAC,CAAC,CAClE,OAAS,EAAO,CACd,EAAU,QAAQ,OAAO,CAAK,CAChC,CAEA,EAAa,KACV,GAAU,CACL,CAAC,EAAK,UAAY,CAAC,EAAK,OAAO,UACjC,EAAc,GACd,EAAgB,EAChB,EAAM,MAAQ,CAAE,OAAQ,UAAW,OAAM,EAE7C,EACC,GAAmB,CACd,CAAC,EAAK,UAAY,CAAC,EAAK,OAAO,UACjC,EAAM,MAAQ,EACV,CAAE,QAAO,SAAU,EAAwB,OAAQ,OAAQ,EAC3D,CAAE,QAAO,OAAQ,OAAQ,EAEjC,CACF,CACF,EAEM,EAAO,EAAQ,YAEjB,EAAI,MAES,GAAQ,MAAM,GAE7B,CAAE,KAAM,GAAS,IAAK,CACxB,EAEM,MAA2B,CAC/B,GAAI,EAAK,SAAU,MAAM,IAAI,EAAA,4BAA4B,iCAAiC,CAC5F,EACM,EAA4B,CAChC,IAAI,gBAAiB,CACnB,OAAO,EAAK,cACd,EACA,YAAe,EAAK,QAAQ,EAC5B,IAAI,UAAW,CACb,OAAO,EAAK,QACd,EACA,IAAI,MAAO,CACT,OAAO,EAAM,IACf,EACA,SAAY,EAAM,KAAK,EACvB,WAAc,CACZ,EAAa,EACb,EAAY,MAAQ,EAAY,KAAK,EAAI,CAC3C,EACA,UAAY,IACV,EAAa,EACN,EAAM,UAAU,CAAQ,GAEjC,CAAC,OAAO,UAAW,CACjB,KAAK,QAAQ,CACf,EACA,IAAI,OAAQ,CACV,OAAO,EAAM,KACf,CACF,EAIA,OAFA,OAAO,eAAe,EAAU,EAAA,SAAU,CAAE,MAAO,EAAK,CAAC,EAElD,CACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"_async.d.ts","sourceRoot":"","sources":["../src/_async.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE1E,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjF,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU;IACtE,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,MAAM,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,CAAC;IAC5F,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,cAAc,GACxB,SAAS,YAAY,MACrB,MAAM,EAAE,KAAK,EACZ,QAAQ,MAAM,MAAM,EACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,KAAK,OAAO,CAAC,KAAK,CAAC,EACrF,UAAU,eAAe,KACxB,QAAQ,CAAC,KAAK,CA8FhB,CAAC"}
1
+ {"version":3,"file":"_async.d.ts","sourceRoot":"","sources":["../src/_async.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE1E,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjF,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU;IACtE,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,MAAM,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,CAAC;IAC5F,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,cAAc,GACxB,SAAS,YAAY,MACrB,MAAM,EAAE,KAAK,EACZ,QAAQ,MAAM,MAAM,EACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,KAAK,OAAO,CAAC,KAAK,CAAC,EACrF,UAAU,eAAe,KACxB,QAAQ,CAAC,KAAK,CAiGhB,CAAC"}
package/dist/_async.js CHANGED
@@ -1,78 +1,77 @@
1
- import { REACTIVE as e } from "./runtime.js";
1
+ import { RippleDisposedResourceError as e } from "./errors.js";
2
+ import { REACTIVE as t } from "./runtime.js";
2
3
  //#region src/_async.ts
3
- var t = (t) => (n, r, i) => {
4
- let a = t.signal({ status: "pending" }, { name: i?.name }), o = t.signal(0), s, c = !1, l = () => {
5
- o.value, s?.abort();
6
- let e = a.peek(), t = e.status === "success" ? e.value : "previous" in e ? e.previous : void 0, i;
4
+ var n = (n) => (r, i, a) => {
5
+ let o = n.signal({ status: "pending" }, { name: a?.name }), s = n.signal(0), c, l = !1, u, d = () => {
6
+ s.value, c?.abort();
7
+ let e;
7
8
  try {
8
- i = n();
9
+ e = r();
9
10
  } catch (e) {
10
- a.value = t === void 0 ? {
11
+ o.value = l ? {
11
12
  error: e,
13
+ previous: u,
12
14
  status: "error"
13
15
  } : {
14
16
  error: e,
15
- previous: t,
16
17
  status: "error"
17
18
  };
18
19
  return;
19
20
  }
20
- let l = new AbortController();
21
- s = l, a.value = t === void 0 ? { status: "pending" } : {
22
- previous: t,
21
+ let t = new AbortController();
22
+ c = t, o.value = l ? {
23
+ previous: u,
23
24
  status: "pending"
24
- };
25
- let u;
25
+ } : { status: "pending" };
26
+ let n;
26
27
  try {
27
- u = Promise.resolve(r(i, { signal: l.signal }));
28
+ n = Promise.resolve(i(e, { signal: t.signal }));
28
29
  } catch (e) {
29
- u = Promise.reject(e);
30
+ n = Promise.reject(e);
30
31
  }
31
- u.then((e) => {
32
- !c && !l.signal.aborted && (a.value = {
32
+ n.then((e) => {
33
+ !f.disposed && !t.signal.aborted && (l = !0, u = e, o.value = {
33
34
  status: "success",
34
35
  value: e
35
36
  });
36
37
  }, (e) => {
37
- !c && !l.signal.aborted && (a.value = t === void 0 ? {
38
+ !f.disposed && !t.signal.aborted && (o.value = l ? {
38
39
  error: e,
40
+ previous: u,
39
41
  status: "error"
40
42
  } : {
41
43
  error: e,
42
- previous: t,
43
44
  status: "error"
44
45
  });
45
46
  });
46
- }, u = t.effect(() => (l(), () => s?.abort()), { name: i?.name });
47
- u.disposalSignal.addEventListener("abort", () => {
48
- c = !0;
49
- }, { once: !0 });
50
- let d = {
47
+ }, f = n.effect(() => (d(), () => c?.abort()), { name: a?.name }), p = () => {
48
+ if (f.disposed) throw new e("Cannot use a disposed resource.");
49
+ }, m = {
51
50
  get disposalSignal() {
52
- return u.disposalSignal;
51
+ return f.disposalSignal;
53
52
  },
54
- dispose: () => u.dispose(),
53
+ dispose: () => f.dispose(),
55
54
  get disposed() {
56
- return c;
55
+ return f.disposed;
57
56
  },
58
57
  get name() {
59
- return a.name;
58
+ return o.name;
60
59
  },
61
- peek: () => a.peek(),
60
+ peek: () => o.peek(),
62
61
  reload: () => {
63
- c || (o.value = o.peek() + 1);
62
+ p(), s.value = s.peek() + 1;
64
63
  },
65
- subscribe: (e) => a.subscribe(e),
64
+ subscribe: (e) => (p(), o.subscribe(e)),
66
65
  [Symbol.dispose]() {
67
66
  this.dispose();
68
67
  },
69
68
  get value() {
70
- return a.value;
69
+ return o.value;
71
70
  }
72
71
  };
73
- return Object.defineProperty(d, e, { value: !0 }), d;
72
+ return Object.defineProperty(m, t, { value: !0 }), m;
74
73
  };
75
74
  //#endregion
76
- export { t as createResource };
75
+ export { n as createResource };
77
76
 
78
77
  //# sourceMappingURL=_async.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_async.js","names":[],"sources":["../src/_async.ts"],"sourcesContent":["import { REACTIVE } from './runtime';\nimport type { Disposable, EffectHandle, Readable, Signal } from './types';\n\nexport type AsyncState<T> =\n | { readonly previous?: T; readonly status: 'pending' }\n | { readonly status: 'success'; readonly value: T }\n | { readonly error: unknown; readonly previous?: T; readonly status: 'error' };\n\nexport interface Resource<T> extends Readable<AsyncState<T>>, Disposable {\n reload(): void;\n}\n\nexport type ResourceOptions = {\n name?: string;\n};\n\ntype AsyncRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n signal<T>(initial: T, options?: { name?: string }): Signal<T>;\n};\n\n/** Resource only depends on primitive runtime methods; graph binding stays private. */\nexport const createResource =\n (runtime: AsyncRuntime) =>\n <Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value> => {\n const state = runtime.signal<AsyncState<Value>>({ status: 'pending' }, { name: options?.name });\n const reloadEpoch = runtime.signal(0);\n let active: AbortController | undefined;\n let disposed = false;\n\n const run = (): void => {\n void reloadEpoch.value;\n active?.abort();\n\n const current = state.peek();\n const previous =\n current.status === 'success' ? current.value : 'previous' in current ? current.previous : undefined;\n let input: Source;\n\n try {\n input = source();\n } catch (error) {\n state.value = previous === undefined ? { error, status: 'error' } : { error, previous, status: 'error' };\n\n return;\n }\n\n const next = new AbortController();\n\n active = next;\n state.value = previous === undefined ? { status: 'pending' } : { previous, status: 'pending' };\n\n let request: Promise<Value>;\n\n try {\n request = Promise.resolve(loader(input, { signal: next.signal }));\n } catch (error) {\n request = Promise.reject(error);\n }\n\n void request.then(\n (value) => {\n if (!disposed && !next.signal.aborted) state.value = { status: 'success', value };\n },\n (error: unknown) => {\n if (!disposed && !next.signal.aborted) {\n state.value = previous === undefined ? { error, status: 'error' } : { error, previous, status: 'error' };\n }\n },\n );\n };\n\n const stop = runtime.effect(\n () => {\n run();\n\n return () => active?.abort();\n },\n { name: options?.name },\n );\n\n stop.disposalSignal.addEventListener(\n 'abort',\n () => {\n disposed = true;\n },\n { once: true },\n );\n\n const resource: Resource<Value> = {\n get disposalSignal() {\n return stop.disposalSignal;\n },\n dispose: () => stop.dispose(),\n get disposed() {\n return disposed;\n },\n get name() {\n return state.name;\n },\n peek: () => state.peek(),\n reload: () => {\n if (disposed) return;\n\n reloadEpoch.value = reloadEpoch.peek() + 1;\n },\n subscribe: (listener) => state.subscribe(listener),\n [Symbol.dispose]() {\n this.dispose();\n },\n get value() {\n return state.value;\n },\n };\n\n Object.defineProperty(resource, REACTIVE, { value: true });\n\n return resource;\n };\n"],"mappings":";;AAsBA,IAAa,KACV,OAEC,GACA,GACA,MACoB;CACpB,IAAM,IAAQ,EAAQ,OAA0B,EAAE,QAAQ,UAAU,GAAG,EAAE,MAAM,GAAS,KAAK,CAAC,GACxF,IAAc,EAAQ,OAAO,CAAC,GAChC,GACA,IAAW,IAET,UAAkB;EAEtB,AADA,EAAiB,OACjB,GAAQ,MAAM;EAEd,IAAM,IAAU,EAAM,KAAK,GACrB,IACJ,EAAQ,WAAW,YAAY,EAAQ,QAAQ,cAAc,IAAU,EAAQ,WAAW,KAAA,GACxF;EAEJ,IAAI;GACF,IAAQ,EAAO;EACjB,SAAS,GAAO;GACd,EAAM,QAAQ,MAAa,KAAA,IAAY;IAAE;IAAO,QAAQ;GAAQ,IAAI;IAAE;IAAO;IAAU,QAAQ;GAAQ;GAEvG;EACF;EAEA,IAAM,IAAO,IAAI,gBAAgB;EAGjC,AADA,IAAS,GACT,EAAM,QAAQ,MAAa,KAAA,IAAY,EAAE,QAAQ,UAAU,IAAI;GAAE;GAAU,QAAQ;EAAU;EAE7F,IAAI;EAEJ,IAAI;GACF,IAAU,QAAQ,QAAQ,EAAO,GAAO,EAAE,QAAQ,EAAK,OAAO,CAAC,CAAC;EAClE,SAAS,GAAO;GACd,IAAU,QAAQ,OAAO,CAAK;EAChC;EAEA,EAAa,MACV,MAAU;GACT,AAAI,CAAC,KAAY,CAAC,EAAK,OAAO,YAAS,EAAM,QAAQ;IAAE,QAAQ;IAAW;GAAM;EAClF,IACC,MAAmB;GAClB,AAAI,CAAC,KAAY,CAAC,EAAK,OAAO,YAC5B,EAAM,QAAQ,MAAa,KAAA,IAAY;IAAE;IAAO,QAAQ;GAAQ,IAAI;IAAE;IAAO;IAAU,QAAQ;GAAQ;EAE3G,CACF;CACF,GAEM,IAAO,EAAQ,cAEjB,EAAI,SAES,GAAQ,MAAM,IAE7B,EAAE,MAAM,GAAS,KAAK,CACxB;CAEA,EAAK,eAAe,iBAClB,eACM;EACJ,IAAW;CACb,GACA,EAAE,MAAM,GAAK,CACf;CAEA,IAAM,IAA4B;EAChC,IAAI,iBAAiB;GACnB,OAAO,EAAK;EACd;EACA,eAAe,EAAK,QAAQ;EAC5B,IAAI,WAAW;GACb,OAAO;EACT;EACA,IAAI,OAAO;GACT,OAAO,EAAM;EACf;EACA,YAAY,EAAM,KAAK;EACvB,cAAc;GACR,MAEJ,EAAY,QAAQ,EAAY,KAAK,IAAI;EAC3C;EACA,YAAY,MAAa,EAAM,UAAU,CAAQ;EACjD,CAAC,OAAO,WAAW;GACjB,KAAK,QAAQ;EACf;EACA,IAAI,QAAQ;GACV,OAAO,EAAM;EACf;CACF;CAIA,OAFA,OAAO,eAAe,GAAU,GAAU,EAAE,OAAO,GAAK,CAAC,GAElD;AACT"}
1
+ {"version":3,"file":"_async.js","names":[],"sources":["../src/_async.ts"],"sourcesContent":["import { RippleDisposedResourceError } from './errors';\nimport { REACTIVE } from './runtime';\nimport type { Disposable, EffectHandle, Readable, Signal } from './types';\n\nexport type AsyncState<T> =\n | { readonly previous?: T; readonly status: 'pending' }\n | { readonly status: 'success'; readonly value: T }\n | { readonly error: unknown; readonly previous?: T; readonly status: 'error' };\n\nexport interface Resource<T> extends Readable<AsyncState<T>>, Disposable {\n reload(): void;\n}\n\nexport type ResourceOptions = {\n name?: string;\n};\n\ntype AsyncRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n signal<T>(initial: T, options?: { name?: string }): Signal<T>;\n};\n\n/** Resource only depends on primitive runtime methods; graph binding stays private. */\nexport const createResource =\n (runtime: AsyncRuntime) =>\n <Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value> => {\n const state = runtime.signal<AsyncState<Value>>({ status: 'pending' }, { name: options?.name });\n const reloadEpoch = runtime.signal(0);\n let active: AbortController | undefined;\n let hasPrevious = false;\n let previousValue: Value | undefined;\n\n const run = (): void => {\n void reloadEpoch.value;\n active?.abort();\n\n let input: Source;\n\n try {\n input = source();\n } catch (error) {\n state.value = hasPrevious\n ? { error, previous: previousValue as Value, status: 'error' }\n : { error, status: 'error' };\n\n return;\n }\n\n const next = new AbortController();\n\n active = next;\n state.value = hasPrevious ? { previous: previousValue as Value, status: 'pending' } : { status: 'pending' };\n\n let request: Promise<Value>;\n\n try {\n request = Promise.resolve(loader(input, { signal: next.signal }));\n } catch (error) {\n request = Promise.reject(error);\n }\n\n void request.then(\n (value) => {\n if (!stop.disposed && !next.signal.aborted) {\n hasPrevious = true;\n previousValue = value;\n state.value = { status: 'success', value };\n }\n },\n (error: unknown) => {\n if (!stop.disposed && !next.signal.aborted) {\n state.value = hasPrevious\n ? { error, previous: previousValue as Value, status: 'error' }\n : { error, status: 'error' };\n }\n },\n );\n };\n\n const stop = runtime.effect(\n () => {\n run();\n\n return () => active?.abort();\n },\n { name: options?.name },\n );\n\n const assertActive = (): void => {\n if (stop.disposed) throw new RippleDisposedResourceError('Cannot use a disposed resource.');\n };\n const resource: Resource<Value> = {\n get disposalSignal() {\n return stop.disposalSignal;\n },\n dispose: () => stop.dispose(),\n get disposed() {\n return stop.disposed;\n },\n get name() {\n return state.name;\n },\n peek: () => state.peek(),\n reload: () => {\n assertActive();\n reloadEpoch.value = reloadEpoch.peek() + 1;\n },\n subscribe: (listener) => {\n assertActive();\n return state.subscribe(listener);\n },\n [Symbol.dispose]() {\n this.dispose();\n },\n get value() {\n return state.value;\n },\n };\n\n Object.defineProperty(resource, REACTIVE, { value: true });\n\n return resource;\n };\n"],"mappings":";;;AAuBA,IAAa,KACV,OAEC,GACA,GACA,MACoB;CACpB,IAAM,IAAQ,EAAQ,OAA0B,EAAE,QAAQ,UAAU,GAAG,EAAE,MAAM,GAAS,KAAK,CAAC,GACxF,IAAc,EAAQ,OAAO,CAAC,GAChC,GACA,IAAc,IACd,GAEE,UAAkB;EAEtB,AADA,EAAiB,OACjB,GAAQ,MAAM;EAEd,IAAI;EAEJ,IAAI;GACF,IAAQ,EAAO;EACjB,SAAS,GAAO;GACd,EAAM,QAAQ,IACV;IAAE;IAAO,UAAU;IAAwB,QAAQ;GAAQ,IAC3D;IAAE;IAAO,QAAQ;GAAQ;GAE7B;EACF;EAEA,IAAM,IAAO,IAAI,gBAAgB;EAGjC,AADA,IAAS,GACT,EAAM,QAAQ,IAAc;GAAE,UAAU;GAAwB,QAAQ;EAAU,IAAI,EAAE,QAAQ,UAAU;EAE1G,IAAI;EAEJ,IAAI;GACF,IAAU,QAAQ,QAAQ,EAAO,GAAO,EAAE,QAAQ,EAAK,OAAO,CAAC,CAAC;EAClE,SAAS,GAAO;GACd,IAAU,QAAQ,OAAO,CAAK;EAChC;EAEA,EAAa,MACV,MAAU;GACT,AAAI,CAAC,EAAK,YAAY,CAAC,EAAK,OAAO,YACjC,IAAc,IACd,IAAgB,GAChB,EAAM,QAAQ;IAAE,QAAQ;IAAW;GAAM;EAE7C,IACC,MAAmB;GAClB,AAAI,CAAC,EAAK,YAAY,CAAC,EAAK,OAAO,YACjC,EAAM,QAAQ,IACV;IAAE;IAAO,UAAU;IAAwB,QAAQ;GAAQ,IAC3D;IAAE;IAAO,QAAQ;GAAQ;EAEjC,CACF;CACF,GAEM,IAAO,EAAQ,cAEjB,EAAI,SAES,GAAQ,MAAM,IAE7B,EAAE,MAAM,GAAS,KAAK,CACxB,GAEM,UAA2B;EAC/B,IAAI,EAAK,UAAU,MAAM,IAAI,EAA4B,iCAAiC;CAC5F,GACM,IAA4B;EAChC,IAAI,iBAAiB;GACnB,OAAO,EAAK;EACd;EACA,eAAe,EAAK,QAAQ;EAC5B,IAAI,WAAW;GACb,OAAO,EAAK;EACd;EACA,IAAI,OAAO;GACT,OAAO,EAAM;EACf;EACA,YAAY,EAAM,KAAK;EACvB,cAAc;GAEZ,AADA,EAAa,GACb,EAAY,QAAQ,EAAY,KAAK,IAAI;EAC3C;EACA,YAAY,OACV,EAAa,GACN,EAAM,UAAU,CAAQ;EAEjC,CAAC,OAAO,WAAW;GACjB,KAAK,QAAQ;EACf;EACA,IAAI,QAAQ;GACV,OAAO,EAAM;EACf;CACF;CAIA,OAFA,OAAO,eAAe,GAAU,GAAU,EAAE,OAAO,GAAK,CAAC,GAElD;AACT"}
package/dist/_default.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const e=require("./runtime.cjs"),t=require("./_async.cjs"),n=require("./_watch.cjs");var r=r=>{let i=new e.ReactiveRuntime(r),a=t.createResource(i);return{batch:i.batch,computed:i.computed,createScope:i.createScope,dispose:()=>i.dispose(),get disposed(){return i.disposed},effect:i.effect,resource:a,signal:i.signal,untrack:i.untrack,watch:n.createWatch(i)}},i=r();exports.createRipple=r,exports.defaultRipple=i;
1
+ const e=require("./runtime.cjs"),t=require("./_async.cjs"),n=require("./_subscribable.cjs"),r=require("./_watch.cjs");var i=i=>{let a=new e.ReactiveRuntime(i),o=n.createFromSubscribable(a),s=t.createResource(a);return{batch:a.batch,computed:a.computed,createScope:a.createScope,get disposalSignal(){return a.disposalSignal},dispose:()=>a.dispose(),get disposed(){return a.disposed},effect:a.effect,fromSubscribable:o,resource:s,signal:a.signal,tap:a.tap,untrack:a.untrack,watch:r.createWatch(a),[Symbol.dispose]:()=>a.dispose()}},a=i();exports.createRipple=i,exports.defaultRipple=a;
2
2
  //# sourceMappingURL=_default.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_default.cjs","names":[],"sources":["../src/_default.ts"],"sourcesContent":["import { createResource, type Resource, type ResourceOptions } from './_async';\nimport { createWatch, type WatchOptions } from './_watch';\nimport { ReactiveRuntime } from './runtime';\nimport type {\n Cleanup,\n ComputedOptions,\n EffectHandle,\n EffectOptions,\n Readable,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n} from './types';\n\nexport interface Ripple {\n batch<T>(fn: () => T): T;\n computed<T>(derive: () => T, options?: ComputedOptions<T>): Readable<T>;\n createScope(name?: string): Scope;\n dispose(): void;\n readonly disposed: boolean;\n effect(callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle;\n resource<Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value>;\n signal<T>(initial: T, options?: SignalOptions<T>): Signal<T>;\n untrack<T>(fn: () => T): T;\n watch<T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle;\n}\n\n/** Creates one complete reactive graph. All factories on the object share its runtime. */\nexport const createRipple = (options?: RippleOptions): Ripple => {\n const runtime = new ReactiveRuntime(options);\n const resource = createResource(runtime);\n\n return {\n batch: runtime.batch,\n computed: runtime.computed,\n createScope: runtime.createScope,\n dispose: () => runtime.dispose(),\n get disposed() {\n return runtime.disposed;\n },\n effect: runtime.effect,\n resource,\n signal: runtime.signal,\n untrack: runtime.untrack,\n watch: createWatch(runtime),\n };\n};\n\n/**\n * The shared default reactive graph. Private — `signal`, `computed`, `effect`, `batch`,\n * `createScope`, `untrack`, `watch`, and `resource` are re-exported from the package root\n * as bound methods on this single graph instance.\n */\nexport const defaultRipple = createRipple();\n"],"mappings":"qFAqCA,IAAa,EAAgB,GAAoC,CAC/D,IAAM,EAAU,IAAI,EAAA,gBAAgB,CAAO,EACrC,EAAW,EAAA,eAAe,CAAO,EAEvC,MAAO,CACL,MAAO,EAAQ,MACf,SAAU,EAAQ,SAClB,YAAa,EAAQ,YACrB,YAAe,EAAQ,QAAQ,EAC/B,IAAI,UAAW,CACb,OAAO,EAAQ,QACjB,EACA,OAAQ,EAAQ,OAChB,WACA,OAAQ,EAAQ,OAChB,QAAS,EAAQ,QACjB,MAAO,EAAA,YAAY,CAAO,CAC5B,CACF,EAOa,EAAgB,EAAa"}
1
+ {"version":3,"file":"_default.cjs","names":[],"sources":["../src/_default.ts"],"sourcesContent":["import { createResource, type Resource, type ResourceOptions } from './_async';\nimport { type BridgedReadable, createFromSubscribable, type FromSubscribableOptions } from './_subscribable';\nimport { createWatch, type WatchOptions } from './_watch';\nimport { ReactiveRuntime } from './runtime';\nimport type {\n Cleanup,\n ComputedOptions,\n Disposable,\n EffectHandle,\n EffectOptions,\n Readable,\n RippleEvent,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n Subscribable,\n Unsubscribe,\n} from './types';\n\nexport interface Ripple extends Disposable {\n batch<T>(fn: () => T): T;\n computed<T>(derive: () => T, options?: ComputedOptions<T>): Readable<T>;\n createScope(name?: string): Scope;\n effect(callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle;\n fromSubscribable<T>(source: Subscribable<T>, options?: FromSubscribableOptions): BridgedReadable<T>;\n resource<Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value>;\n signal<T>(initial: T, options?: SignalOptions<T>): Signal<T>;\n tap(handler: (event: RippleEvent) => void, options?: { signal?: AbortSignal }): Unsubscribe;\n untrack<T>(fn: () => T): T;\n watch<T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle;\n}\n\n/**\n * Creates one complete reactive graph with its own ownership boundary. All\n * factories on the returned object share its runtime. Use this for tests, SSR\n * requests, embedded applications, or independently disposable features.\n * `dispose()` is terminal — create a new graph for a new lifetime.\n */\nexport const createRipple = (options?: RippleOptions): Ripple => {\n const runtime = new ReactiveRuntime(options);\n const fromSubscribable = createFromSubscribable(runtime);\n const resource = createResource(runtime);\n\n return {\n batch: runtime.batch,\n computed: runtime.computed,\n createScope: runtime.createScope,\n get disposalSignal() {\n return runtime.disposalSignal;\n },\n dispose: () => runtime.dispose(),\n get disposed() {\n return runtime.disposed;\n },\n effect: runtime.effect,\n fromSubscribable,\n resource,\n signal: runtime.signal,\n tap: runtime.tap,\n untrack: runtime.untrack,\n watch: createWatch(runtime),\n [Symbol.dispose]: () => runtime.dispose(),\n };\n};\n\n/**\n * The shared default reactive graph — process-lifetime. Root helpers\n * (`signal`, `computed`, `effect`, `batch`, `createScope`, `untrack`, `watch`, `resource`, `fromSubscribable`)\n * are re-exported from the package root as bound methods on this single graph\n * instance. Use these only when the application has one graph for its entire\n * lifetime; they are never disposed. For isolated, disposable graphs (tests,\n * SSR, embedded features) use `createRipple()` instead.\n */\nexport const defaultRipple = createRipple();\n"],"mappings":"sHA+CA,IAAa,EAAgB,GAAoC,CAC/D,IAAM,EAAU,IAAI,EAAA,gBAAgB,CAAO,EACrC,EAAmB,EAAA,uBAAuB,CAAO,EACjD,EAAW,EAAA,eAAe,CAAO,EAEvC,MAAO,CACL,MAAO,EAAQ,MACf,SAAU,EAAQ,SAClB,YAAa,EAAQ,YACrB,IAAI,gBAAiB,CACnB,OAAO,EAAQ,cACjB,EACA,YAAe,EAAQ,QAAQ,EAC/B,IAAI,UAAW,CACb,OAAO,EAAQ,QACjB,EACA,OAAQ,EAAQ,OAChB,mBACA,WACA,OAAQ,EAAQ,OAChB,IAAK,EAAQ,IACb,QAAS,EAAQ,QACjB,MAAO,EAAA,YAAY,CAAO,GACzB,OAAO,aAAgB,EAAQ,QAAQ,CAC1C,CACF,EAUa,EAAgB,EAAa"}
@@ -1,26 +1,37 @@
1
1
  import { type Resource, type ResourceOptions } from './_async';
2
+ import { type BridgedReadable, type FromSubscribableOptions } from './_subscribable';
2
3
  import { type WatchOptions } from './_watch';
3
- import type { Cleanup, ComputedOptions, EffectHandle, EffectOptions, Readable, RippleOptions, Scope, Signal, SignalOptions } from './types';
4
- export interface Ripple {
4
+ import type { Cleanup, ComputedOptions, Disposable, EffectHandle, EffectOptions, Readable, RippleEvent, RippleOptions, Scope, Signal, SignalOptions, Subscribable, Unsubscribe } from './types';
5
+ export interface Ripple extends Disposable {
5
6
  batch<T>(fn: () => T): T;
6
7
  computed<T>(derive: () => T, options?: ComputedOptions<T>): Readable<T>;
7
8
  createScope(name?: string): Scope;
8
- dispose(): void;
9
- readonly disposed: boolean;
10
9
  effect(callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle;
10
+ fromSubscribable<T>(source: Subscribable<T>, options?: FromSubscribableOptions): BridgedReadable<T>;
11
11
  resource<Source, Value>(source: () => Source, loader: (source: Source, context: {
12
12
  readonly signal: AbortSignal;
13
13
  }) => Promise<Value>, options?: ResourceOptions): Resource<Value>;
14
14
  signal<T>(initial: T, options?: SignalOptions<T>): Signal<T>;
15
+ tap(handler: (event: RippleEvent) => void, options?: {
16
+ signal?: AbortSignal;
17
+ }): Unsubscribe;
15
18
  untrack<T>(fn: () => T): T;
16
19
  watch<T>(source: Readable<T> | (() => T), callback: (value: T, previous: T | undefined) => void, options?: WatchOptions<T>): EffectHandle;
17
20
  }
18
- /** Creates one complete reactive graph. All factories on the object share its runtime. */
21
+ /**
22
+ * Creates one complete reactive graph with its own ownership boundary. All
23
+ * factories on the returned object share its runtime. Use this for tests, SSR
24
+ * requests, embedded applications, or independently disposable features.
25
+ * `dispose()` is terminal — create a new graph for a new lifetime.
26
+ */
19
27
  export declare const createRipple: (options?: RippleOptions) => Ripple;
20
28
  /**
21
- * The shared default reactive graph. Private — `signal`, `computed`, `effect`, `batch`,
22
- * `createScope`, `untrack`, `watch`, and `resource` are re-exported from the package root
23
- * as bound methods on this single graph instance.
29
+ * The shared default reactive graph — process-lifetime. Root helpers
30
+ * (`signal`, `computed`, `effect`, `batch`, `createScope`, `untrack`, `watch`, `resource`, `fromSubscribable`)
31
+ * are re-exported from the package root as bound methods on this single graph
32
+ * instance. Use these only when the application has one graph for its entire
33
+ * lifetime; they are never disposed. For isolated, disposable graphs (tests,
34
+ * SSR, embedded features) use `createRipple()` instead.
24
35
  */
25
36
  export declare const defaultRipple: Ripple;
26
37
  //# sourceMappingURL=_default.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"_default.d.ts","sourceRoot":"","sources":["../src/_default.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,MAAM,EACN,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACxE,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAClC,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,MAAM,CAAC,QAAQ,EAAE,MAAM,OAAO,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACnF,QAAQ,CAAC,MAAM,EAAE,KAAK,EACpB,MAAM,EAAE,MAAM,MAAM,EACpB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,KAAK,CAAC,EACrF,OAAO,CAAC,EAAE,eAAe,GACxB,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,KAAK,CAAC,CAAC,EACL,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,EACrD,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,GACxB,YAAY,CAAC;CACjB;AAED,0FAA0F;AAC1F,eAAO,MAAM,YAAY,GAAI,UAAU,aAAa,KAAG,MAkBtD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,QAAiB,CAAC"}
1
+ {"version":3,"file":"_default.d.ts","sourceRoot":"","sources":["../src/_default.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAE,KAAK,eAAe,EAA0B,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC7G,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,UAAU,EACV,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,WAAW,EACX,aAAa,EACb,KAAK,EACL,MAAM,EACN,aAAa,EACb,YAAY,EACZ,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,MAAO,SAAQ,UAAU;IACxC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACxE,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAClC,MAAM,CAAC,QAAQ,EAAE,MAAM,OAAO,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACnF,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IACpG,QAAQ,CAAC,MAAM,EAAE,KAAK,EACpB,MAAM,EAAE,MAAM,MAAM,EACpB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,KAAK,CAAC,EACrF,OAAO,CAAC,EAAE,eAAe,GACxB,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7D,GAAG,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,WAAW,CAAC;IAC5F,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,KAAK,CAAC,CAAC,EACL,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,EACrD,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,GACxB,YAAY,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,aAAa,KAAG,MAyBtD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,QAAiB,CAAC"}
package/dist/_default.js CHANGED
@@ -1,25 +1,32 @@
1
1
  import { ReactiveRuntime as e } from "./runtime.js";
2
2
  import { createResource as t } from "./_async.js";
3
- import { createWatch as n } from "./_watch.js";
3
+ import { createFromSubscribable as n } from "./_subscribable.js";
4
+ import { createWatch as r } from "./_watch.js";
4
5
  //#region src/_default.ts
5
- var r = (r) => {
6
- let i = new e(r), a = t(i);
6
+ var i = (i) => {
7
+ let a = new e(i), o = n(a), s = t(a);
7
8
  return {
8
- batch: i.batch,
9
- computed: i.computed,
10
- createScope: i.createScope,
11
- dispose: () => i.dispose(),
9
+ batch: a.batch,
10
+ computed: a.computed,
11
+ createScope: a.createScope,
12
+ get disposalSignal() {
13
+ return a.disposalSignal;
14
+ },
15
+ dispose: () => a.dispose(),
12
16
  get disposed() {
13
- return i.disposed;
17
+ return a.disposed;
14
18
  },
15
- effect: i.effect,
16
- resource: a,
17
- signal: i.signal,
18
- untrack: i.untrack,
19
- watch: n(i)
19
+ effect: a.effect,
20
+ fromSubscribable: o,
21
+ resource: s,
22
+ signal: a.signal,
23
+ tap: a.tap,
24
+ untrack: a.untrack,
25
+ watch: r(a),
26
+ [Symbol.dispose]: () => a.dispose()
20
27
  };
21
- }, i = r();
28
+ }, a = i();
22
29
  //#endregion
23
- export { r as createRipple, i as defaultRipple };
30
+ export { i as createRipple, a as defaultRipple };
24
31
 
25
32
  //# sourceMappingURL=_default.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_default.js","names":[],"sources":["../src/_default.ts"],"sourcesContent":["import { createResource, type Resource, type ResourceOptions } from './_async';\nimport { createWatch, type WatchOptions } from './_watch';\nimport { ReactiveRuntime } from './runtime';\nimport type {\n Cleanup,\n ComputedOptions,\n EffectHandle,\n EffectOptions,\n Readable,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n} from './types';\n\nexport interface Ripple {\n batch<T>(fn: () => T): T;\n computed<T>(derive: () => T, options?: ComputedOptions<T>): Readable<T>;\n createScope(name?: string): Scope;\n dispose(): void;\n readonly disposed: boolean;\n effect(callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle;\n resource<Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value>;\n signal<T>(initial: T, options?: SignalOptions<T>): Signal<T>;\n untrack<T>(fn: () => T): T;\n watch<T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle;\n}\n\n/** Creates one complete reactive graph. All factories on the object share its runtime. */\nexport const createRipple = (options?: RippleOptions): Ripple => {\n const runtime = new ReactiveRuntime(options);\n const resource = createResource(runtime);\n\n return {\n batch: runtime.batch,\n computed: runtime.computed,\n createScope: runtime.createScope,\n dispose: () => runtime.dispose(),\n get disposed() {\n return runtime.disposed;\n },\n effect: runtime.effect,\n resource,\n signal: runtime.signal,\n untrack: runtime.untrack,\n watch: createWatch(runtime),\n };\n};\n\n/**\n * The shared default reactive graph. Private — `signal`, `computed`, `effect`, `batch`,\n * `createScope`, `untrack`, `watch`, and `resource` are re-exported from the package root\n * as bound methods on this single graph instance.\n */\nexport const defaultRipple = createRipple();\n"],"mappings":";;;;AAqCA,IAAa,KAAgB,MAAoC;CAC/D,IAAM,IAAU,IAAI,EAAgB,CAAO,GACrC,IAAW,EAAe,CAAO;CAEvC,OAAO;EACL,OAAO,EAAQ;EACf,UAAU,EAAQ;EAClB,aAAa,EAAQ;EACrB,eAAe,EAAQ,QAAQ;EAC/B,IAAI,WAAW;GACb,OAAO,EAAQ;EACjB;EACA,QAAQ,EAAQ;EAChB;EACA,QAAQ,EAAQ;EAChB,SAAS,EAAQ;EACjB,OAAO,EAAY,CAAO;CAC5B;AACF,GAOa,IAAgB,EAAa"}
1
+ {"version":3,"file":"_default.js","names":[],"sources":["../src/_default.ts"],"sourcesContent":["import { createResource, type Resource, type ResourceOptions } from './_async';\nimport { type BridgedReadable, createFromSubscribable, type FromSubscribableOptions } from './_subscribable';\nimport { createWatch, type WatchOptions } from './_watch';\nimport { ReactiveRuntime } from './runtime';\nimport type {\n Cleanup,\n ComputedOptions,\n Disposable,\n EffectHandle,\n EffectOptions,\n Readable,\n RippleEvent,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n Subscribable,\n Unsubscribe,\n} from './types';\n\nexport interface Ripple extends Disposable {\n batch<T>(fn: () => T): T;\n computed<T>(derive: () => T, options?: ComputedOptions<T>): Readable<T>;\n createScope(name?: string): Scope;\n effect(callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle;\n fromSubscribable<T>(source: Subscribable<T>, options?: FromSubscribableOptions): BridgedReadable<T>;\n resource<Source, Value>(\n source: () => Source,\n loader: (source: Source, context: { readonly signal: AbortSignal }) => Promise<Value>,\n options?: ResourceOptions,\n ): Resource<Value>;\n signal<T>(initial: T, options?: SignalOptions<T>): Signal<T>;\n tap(handler: (event: RippleEvent) => void, options?: { signal?: AbortSignal }): Unsubscribe;\n untrack<T>(fn: () => T): T;\n watch<T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle;\n}\n\n/**\n * Creates one complete reactive graph with its own ownership boundary. All\n * factories on the returned object share its runtime. Use this for tests, SSR\n * requests, embedded applications, or independently disposable features.\n * `dispose()` is terminal — create a new graph for a new lifetime.\n */\nexport const createRipple = (options?: RippleOptions): Ripple => {\n const runtime = new ReactiveRuntime(options);\n const fromSubscribable = createFromSubscribable(runtime);\n const resource = createResource(runtime);\n\n return {\n batch: runtime.batch,\n computed: runtime.computed,\n createScope: runtime.createScope,\n get disposalSignal() {\n return runtime.disposalSignal;\n },\n dispose: () => runtime.dispose(),\n get disposed() {\n return runtime.disposed;\n },\n effect: runtime.effect,\n fromSubscribable,\n resource,\n signal: runtime.signal,\n tap: runtime.tap,\n untrack: runtime.untrack,\n watch: createWatch(runtime),\n [Symbol.dispose]: () => runtime.dispose(),\n };\n};\n\n/**\n * The shared default reactive graph — process-lifetime. Root helpers\n * (`signal`, `computed`, `effect`, `batch`, `createScope`, `untrack`, `watch`, `resource`, `fromSubscribable`)\n * are re-exported from the package root as bound methods on this single graph\n * instance. Use these only when the application has one graph for its entire\n * lifetime; they are never disposed. For isolated, disposable graphs (tests,\n * SSR, embedded features) use `createRipple()` instead.\n */\nexport const defaultRipple = createRipple();\n"],"mappings":";;;;;AA+CA,IAAa,KAAgB,MAAoC;CAC/D,IAAM,IAAU,IAAI,EAAgB,CAAO,GACrC,IAAmB,EAAuB,CAAO,GACjD,IAAW,EAAe,CAAO;CAEvC,OAAO;EACL,OAAO,EAAQ;EACf,UAAU,EAAQ;EAClB,aAAa,EAAQ;EACrB,IAAI,iBAAiB;GACnB,OAAO,EAAQ;EACjB;EACA,eAAe,EAAQ,QAAQ;EAC/B,IAAI,WAAW;GACb,OAAO,EAAQ;EACjB;EACA,QAAQ,EAAQ;EAChB;EACA;EACA,QAAQ,EAAQ;EAChB,KAAK,EAAQ;EACb,SAAS,EAAQ;EACjB,OAAO,EAAY,CAAO;GACzB,OAAO,gBAAgB,EAAQ,QAAQ;CAC1C;AACF,GAUa,IAAgB,EAAa"}
@@ -0,0 +1,2 @@
1
+ const e=require("./errors.cjs"),t=require("./runtime.cjs");var n=n=>(r,i)=>{let a=n.signal(r.getSnapshot(),{name:i?.name}),o=n.effect(()=>{let e=()=>{a.value=r.getSnapshot()},t;try{t=r.subscribe(e),e()}catch(e){throw t?.(),e}return t},{name:i?.name}),s=()=>o.dispose();i?.signal?.addEventListener(`abort`,s,{once:!0}),i?.signal?.aborted&&o.dispose();let c=()=>{if(o.disposed)throw new e.RippleError(`Cannot subscribe to a disposed bridge.`)},l=()=>{i?.signal?.removeEventListener(`abort`,s),o.dispose()},u={get disposalSignal(){return o.disposalSignal},dispose:l,get disposed(){return o.disposed},get name(){return a.name},peek:()=>a.peek(),subscribe(e){return c(),a.subscribe(e)},[Symbol.dispose]:l,get value(){return a.value}};return Object.defineProperty(u,t.REACTIVE,{value:!0}),u};exports.createFromSubscribable=n;
2
+ //# sourceMappingURL=_subscribable.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_subscribable.cjs","names":[],"sources":["../src/_subscribable.ts"],"sourcesContent":["import { RippleError } from './errors';\nimport { REACTIVE } from './runtime';\nimport type { Disposable, EffectHandle, Readable, Signal, Subscribable } from './types';\n\ntype BridgeRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n signal<T>(initial: T, options?: { name?: string }): Signal<T>;\n};\n\nexport type BridgedReadable<T> = Readable<T> & Disposable;\nexport type FromSubscribableOptions = { name?: string; signal?: AbortSignal };\n\nexport const createFromSubscribable =\n (runtime: BridgeRuntime) =>\n <T>(source: Subscribable<T>, options?: FromSubscribableOptions): BridgedReadable<T> => {\n const node = runtime.signal<T>(source.getSnapshot(), { name: options?.name });\n const stop = runtime.effect(\n () => {\n const sync = () => {\n node.value = source.getSnapshot();\n };\n let unsubscribe: (() => void) | undefined;\n\n try {\n unsubscribe = source.subscribe(sync);\n sync();\n } catch (error) {\n unsubscribe?.();\n throw error;\n }\n\n return unsubscribe;\n },\n { name: options?.name },\n );\n const abort = () => stop.dispose();\n\n options?.signal?.addEventListener('abort', abort, { once: true });\n if (options?.signal?.aborted) stop.dispose();\n\n const assertActive = (): void => {\n if (stop.disposed) throw new RippleError('Cannot subscribe to a disposed bridge.');\n };\n const dispose = (): void => {\n options?.signal?.removeEventListener('abort', abort);\n stop.dispose();\n };\n const readable: BridgedReadable<T> = {\n get disposalSignal() {\n return stop.disposalSignal;\n },\n dispose,\n get disposed() {\n return stop.disposed;\n },\n get name() {\n return node.name;\n },\n peek: () => node.peek(),\n subscribe(listener) {\n assertActive();\n return node.subscribe(listener);\n },\n [Symbol.dispose]: dispose,\n get value() {\n return node.value;\n },\n };\n\n Object.defineProperty(readable, REACTIVE, { value: true });\n return readable;\n };\n"],"mappings":"2DAYA,IAAa,EACV,IACG,EAAyB,IAA0D,CACrF,IAAM,EAAO,EAAQ,OAAU,EAAO,YAAY,EAAG,CAAE,KAAM,GAAS,IAAK,CAAC,EACtE,EAAO,EAAQ,WACb,CACJ,IAAM,MAAa,CACjB,EAAK,MAAQ,EAAO,YAAY,CAClC,EACI,EAEJ,GAAI,CACF,EAAc,EAAO,UAAU,CAAI,EACnC,EAAK,CACP,OAAS,EAAO,CAEd,MADA,IAAc,EACR,CACR,CAEA,OAAO,CACT,EACA,CAAE,KAAM,GAAS,IAAK,CACxB,EACM,MAAc,EAAK,QAAQ,EAEjC,GAAS,QAAQ,iBAAiB,QAAS,EAAO,CAAE,KAAM,EAAK,CAAC,EAC5D,GAAS,QAAQ,SAAS,EAAK,QAAQ,EAE3C,IAAM,MAA2B,CAC/B,GAAI,EAAK,SAAU,MAAM,IAAI,EAAA,YAAY,wCAAwC,CACnF,EACM,MAAsB,CAC1B,GAAS,QAAQ,oBAAoB,QAAS,CAAK,EACnD,EAAK,QAAQ,CACf,EACM,EAA+B,CACnC,IAAI,gBAAiB,CACnB,OAAO,EAAK,cACd,EACA,UACA,IAAI,UAAW,CACb,OAAO,EAAK,QACd,EACA,IAAI,MAAO,CACT,OAAO,EAAK,IACd,EACA,SAAY,EAAK,KAAK,EACtB,UAAU,EAAU,CAElB,OADA,EAAa,EACN,EAAK,UAAU,CAAQ,CAChC,GACC,OAAO,SAAU,EAClB,IAAI,OAAQ,CACV,OAAO,EAAK,KACd,CACF,EAGA,OADA,OAAO,eAAe,EAAU,EAAA,SAAU,CAAE,MAAO,EAAK,CAAC,EAClD,CACT"}
@@ -0,0 +1,17 @@
1
+ import type { Disposable, EffectHandle, Readable, Signal, Subscribable } from './types';
2
+ type BridgeRuntime = {
3
+ effect(callback: () => undefined | (() => void), options?: {
4
+ name?: string;
5
+ }): EffectHandle;
6
+ signal<T>(initial: T, options?: {
7
+ name?: string;
8
+ }): Signal<T>;
9
+ };
10
+ export type BridgedReadable<T> = Readable<T> & Disposable;
11
+ export type FromSubscribableOptions = {
12
+ name?: string;
13
+ signal?: AbortSignal;
14
+ };
15
+ export declare const createFromSubscribable: (runtime: BridgeRuntime) => <T>(source: Subscribable<T>, options?: FromSubscribableOptions) => BridgedReadable<T>;
16
+ export {};
17
+ //# sourceMappingURL=_subscribable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_subscribable.d.ts","sourceRoot":"","sources":["../src/_subscribable.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAExF,KAAK,aAAa,GAAG;IACnB,MAAM,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,CAAC;IAC5F,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;AAC1D,MAAM,MAAM,uBAAuB,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC;AAE9E,eAAO,MAAM,sBAAsB,GAChC,SAAS,aAAa,MACtB,CAAC,EAAE,QAAQ,YAAY,CAAC,CAAC,CAAC,EAAE,UAAU,uBAAuB,KAAG,eAAe,CAAC,CAAC,CAyDjF,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { RippleError as e } from "./errors.js";
2
+ import { REACTIVE as t } from "./runtime.js";
3
+ //#region src/_subscribable.ts
4
+ var n = (n) => (r, i) => {
5
+ let a = n.signal(r.getSnapshot(), { name: i?.name }), o = n.effect(() => {
6
+ let e = () => {
7
+ a.value = r.getSnapshot();
8
+ }, t;
9
+ try {
10
+ t = r.subscribe(e), e();
11
+ } catch (e) {
12
+ throw t?.(), e;
13
+ }
14
+ return t;
15
+ }, { name: i?.name }), s = () => o.dispose();
16
+ i?.signal?.addEventListener("abort", s, { once: !0 }), i?.signal?.aborted && o.dispose();
17
+ let c = () => {
18
+ if (o.disposed) throw new e("Cannot subscribe to a disposed bridge.");
19
+ }, l = () => {
20
+ i?.signal?.removeEventListener("abort", s), o.dispose();
21
+ }, u = {
22
+ get disposalSignal() {
23
+ return o.disposalSignal;
24
+ },
25
+ dispose: l,
26
+ get disposed() {
27
+ return o.disposed;
28
+ },
29
+ get name() {
30
+ return a.name;
31
+ },
32
+ peek: () => a.peek(),
33
+ subscribe(e) {
34
+ return c(), a.subscribe(e);
35
+ },
36
+ [Symbol.dispose]: l,
37
+ get value() {
38
+ return a.value;
39
+ }
40
+ };
41
+ return Object.defineProperty(u, t, { value: !0 }), u;
42
+ };
43
+ //#endregion
44
+ export { n as createFromSubscribable };
45
+
46
+ //# sourceMappingURL=_subscribable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_subscribable.js","names":[],"sources":["../src/_subscribable.ts"],"sourcesContent":["import { RippleError } from './errors';\nimport { REACTIVE } from './runtime';\nimport type { Disposable, EffectHandle, Readable, Signal, Subscribable } from './types';\n\ntype BridgeRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n signal<T>(initial: T, options?: { name?: string }): Signal<T>;\n};\n\nexport type BridgedReadable<T> = Readable<T> & Disposable;\nexport type FromSubscribableOptions = { name?: string; signal?: AbortSignal };\n\nexport const createFromSubscribable =\n (runtime: BridgeRuntime) =>\n <T>(source: Subscribable<T>, options?: FromSubscribableOptions): BridgedReadable<T> => {\n const node = runtime.signal<T>(source.getSnapshot(), { name: options?.name });\n const stop = runtime.effect(\n () => {\n const sync = () => {\n node.value = source.getSnapshot();\n };\n let unsubscribe: (() => void) | undefined;\n\n try {\n unsubscribe = source.subscribe(sync);\n sync();\n } catch (error) {\n unsubscribe?.();\n throw error;\n }\n\n return unsubscribe;\n },\n { name: options?.name },\n );\n const abort = () => stop.dispose();\n\n options?.signal?.addEventListener('abort', abort, { once: true });\n if (options?.signal?.aborted) stop.dispose();\n\n const assertActive = (): void => {\n if (stop.disposed) throw new RippleError('Cannot subscribe to a disposed bridge.');\n };\n const dispose = (): void => {\n options?.signal?.removeEventListener('abort', abort);\n stop.dispose();\n };\n const readable: BridgedReadable<T> = {\n get disposalSignal() {\n return stop.disposalSignal;\n },\n dispose,\n get disposed() {\n return stop.disposed;\n },\n get name() {\n return node.name;\n },\n peek: () => node.peek(),\n subscribe(listener) {\n assertActive();\n return node.subscribe(listener);\n },\n [Symbol.dispose]: dispose,\n get value() {\n return node.value;\n },\n };\n\n Object.defineProperty(readable, REACTIVE, { value: true });\n return readable;\n };\n"],"mappings":";;;AAYA,IAAa,KACV,OACG,GAAyB,MAA0D;CACrF,IAAM,IAAO,EAAQ,OAAU,EAAO,YAAY,GAAG,EAAE,MAAM,GAAS,KAAK,CAAC,GACtE,IAAO,EAAQ,aACb;EACJ,IAAM,UAAa;GACjB,EAAK,QAAQ,EAAO,YAAY;EAClC,GACI;EAEJ,IAAI;GAEF,AADA,IAAc,EAAO,UAAU,CAAI,GACnC,EAAK;EACP,SAAS,GAAO;GAEd,MADA,IAAc,GACR;EACR;EAEA,OAAO;CACT,GACA,EAAE,MAAM,GAAS,KAAK,CACxB,GACM,UAAc,EAAK,QAAQ;CAGjC,AADA,GAAS,QAAQ,iBAAiB,SAAS,GAAO,EAAE,MAAM,GAAK,CAAC,GAC5D,GAAS,QAAQ,WAAS,EAAK,QAAQ;CAE3C,IAAM,UAA2B;EAC/B,IAAI,EAAK,UAAU,MAAM,IAAI,EAAY,wCAAwC;CACnF,GACM,UAAsB;EAE1B,AADA,GAAS,QAAQ,oBAAoB,SAAS,CAAK,GACnD,EAAK,QAAQ;CACf,GACM,IAA+B;EACnC,IAAI,iBAAiB;GACnB,OAAO,EAAK;EACd;EACA;EACA,IAAI,WAAW;GACb,OAAO,EAAK;EACd;EACA,IAAI,OAAO;GACT,OAAO,EAAK;EACd;EACA,YAAY,EAAK,KAAK;EACtB,UAAU,GAAU;GAElB,OADA,EAAa,GACN,EAAK,UAAU,CAAQ;EAChC;GACC,OAAO,UAAU;EAClB,IAAI,QAAQ;GACV,OAAO,EAAK;EACd;CACF;CAGA,OADA,OAAO,eAAe,GAAU,GAAU,EAAE,OAAO,GAAK,CAAC,GAClD;AACT"}
package/dist/_watch.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=e=>(t,n,r)=>{let i=typeof t==`function`?t:()=>t.value,a=r?.equals??Object.is,o=!0,s,c=!1,l=e.effect(()=>{let e=i();if(o){o=!1,s=e,r?.immediate&&(n(e,void 0),r?.once&&(c=!0));return}if(a(s,e))return;let t=s;s=e,n(e,t),r?.once&&l.dispose()},{name:r?.name});return c&&l.dispose(),l};exports.createWatch=e;
1
+ var e=e=>(t,n,r)=>{let i=typeof t==`function`?t:()=>t.value,a=r?.equals??Object.is,o=!0,s,c=!1,l=e.effect(()=>{let t=i();if(o){if(o=!1,s=t,r?.immediate)try{e.untrack(()=>n(t,void 0))}finally{r?.once&&(c=!0)}return}if(a(s,t))return;let u=s;s=t;try{e.untrack(()=>n(t,u))}finally{r?.once&&l.dispose()}},{name:r?.name});return c&&l.dispose(),l};exports.createWatch=e;
2
2
  //# sourceMappingURL=_watch.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_watch.cjs","names":[],"sources":["../src/_watch.ts"],"sourcesContent":["import type { EffectHandle, Equality, Readable } from './types';\n\nexport type WatchOptions<T> = {\n equals?: Equality<T>;\n immediate?: boolean;\n name?: string;\n once?: boolean;\n};\n\ntype WatchRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n};\n\nexport const createWatch =\n (runtime: WatchRuntime) =>\n <T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle => {\n const read = typeof source === 'function' ? source : () => source.value;\n const equals = options?.equals ?? Object.is;\n let initial = true;\n let previous: T | undefined;\n // `handle` is in the temporal dead zone during the effect's initial synchronous run —\n // `runtime.effect()` calls `node.run()` before returning. Defer disposal until after\n // the constructor returns so `handle.dispose()` is reachable from inside the callback.\n let disposeAfterInit = false;\n\n const handle = runtime.effect(\n () => {\n const value = read();\n\n if (initial) {\n initial = false;\n previous = value;\n\n if (options?.immediate) {\n callback(value, undefined);\n if (options?.once) disposeAfterInit = true;\n }\n\n return;\n }\n\n if (equals(previous as T, value)) return;\n\n const oldValue = previous;\n\n previous = value;\n callback(value, oldValue);\n\n if (options?.once) handle.dispose();\n },\n { name: options?.name },\n );\n\n if (disposeAfterInit) handle.dispose();\n\n return handle;\n };\n"],"mappings":"AAaA,IAAa,EACV,IAEC,EACA,EACA,IACiB,CACjB,IAAM,EAAO,OAAO,GAAW,WAAa,MAAe,EAAO,MAC5D,EAAS,GAAS,QAAU,OAAO,GACrC,EAAU,GACV,EAIA,EAAmB,GAEjB,EAAS,EAAQ,WACf,CACJ,IAAM,EAAQ,EAAK,EAEnB,GAAI,EAAS,CACX,EAAU,GACV,EAAW,EAEP,GAAS,YACX,EAAS,EAAO,IAAA,EAAS,EACrB,GAAS,OAAM,EAAmB,KAGxC,MACF,CAEA,GAAI,EAAO,EAAe,CAAK,EAAG,OAElC,IAAM,EAAW,EAEjB,EAAW,EACX,EAAS,EAAO,CAAQ,EAEpB,GAAS,MAAM,EAAO,QAAQ,CACpC,EACA,CAAE,KAAM,GAAS,IAAK,CACxB,EAIA,OAFI,GAAkB,EAAO,QAAQ,EAE9B,CACT"}
1
+ {"version":3,"file":"_watch.cjs","names":[],"sources":["../src/_watch.ts"],"sourcesContent":["import type { EffectHandle, Equality, Readable } from './types';\n\nexport type WatchOptions<T> = {\n equals?: Equality<T>;\n immediate?: boolean;\n name?: string;\n once?: boolean;\n};\n\ntype WatchRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n untrack<T>(fn: () => T): T;\n};\n\nexport const createWatch =\n (runtime: WatchRuntime) =>\n <T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle => {\n const read = typeof source === 'function' ? source : () => source.value;\n const equals = options?.equals ?? Object.is;\n let initial = true;\n let previous: T | undefined;\n // `handle` is in the temporal dead zone during the effect's initial synchronous run —\n // `runtime.effect()` calls `node.run()` before returning. Defer disposal until after\n // the constructor returns so `handle.dispose()` is reachable from inside the callback.\n let disposeAfterInit = false;\n\n const handle = runtime.effect(\n () => {\n const value = read();\n\n if (initial) {\n initial = false;\n previous = value;\n\n if (options?.immediate) {\n try {\n runtime.untrack(() => callback(value, undefined));\n } finally {\n if (options?.once) disposeAfterInit = true;\n }\n }\n\n return;\n }\n\n if (equals(previous as T, value)) return;\n\n const oldValue = previous;\n\n previous = value;\n try {\n runtime.untrack(() => callback(value, oldValue));\n } finally {\n if (options?.once) handle.dispose();\n }\n },\n { name: options?.name },\n );\n\n if (disposeAfterInit) handle.dispose();\n\n return handle;\n };\n"],"mappings":"AAcA,IAAa,EACV,IAEC,EACA,EACA,IACiB,CACjB,IAAM,EAAO,OAAO,GAAW,WAAa,MAAe,EAAO,MAC5D,EAAS,GAAS,QAAU,OAAO,GACrC,EAAU,GACV,EAIA,EAAmB,GAEjB,EAAS,EAAQ,WACf,CACJ,IAAM,EAAQ,EAAK,EAEnB,GAAI,EAAS,CAIX,GAHA,EAAU,GACV,EAAW,EAEP,GAAS,UACX,GAAI,CACF,EAAQ,YAAc,EAAS,EAAO,IAAA,EAAS,CAAC,CAClD,QAAU,CACJ,GAAS,OAAM,EAAmB,GACxC,CAGF,MACF,CAEA,GAAI,EAAO,EAAe,CAAK,EAAG,OAElC,IAAM,EAAW,EAEjB,EAAW,EACX,GAAI,CACF,EAAQ,YAAc,EAAS,EAAO,CAAQ,CAAC,CACjD,QAAU,CACJ,GAAS,MAAM,EAAO,QAAQ,CACpC,CACF,EACA,CAAE,KAAM,GAAS,IAAK,CACxB,EAIA,OAFI,GAAkB,EAAO,QAAQ,EAE9B,CACT"}
package/dist/_watch.d.ts CHANGED
@@ -9,6 +9,7 @@ type WatchRuntime = {
9
9
  effect(callback: () => undefined | (() => void), options?: {
10
10
  name?: string;
11
11
  }): EffectHandle;
12
+ untrack<T>(fn: () => T): T;
12
13
  };
13
14
  export declare const createWatch: (runtime: WatchRuntime) => <T>(source: Readable<T> | (() => T), callback: (value: T, previous: T | undefined) => void, options?: WatchOptions<T>) => EffectHandle;
14
15
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"_watch.d.ts","sourceRoot":"","sources":["../src/_watch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEhE,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,MAAM,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,CAAC;CAC7F,CAAC;AAEF,eAAO,MAAM,WAAW,GACrB,SAAS,YAAY,MACrB,CAAC,EACA,QAAQ,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAC/B,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,EACrD,UAAU,YAAY,CAAC,CAAC,CAAC,KACxB,YAyCF,CAAC"}
1
+ {"version":3,"file":"_watch.d.ts","sourceRoot":"","sources":["../src/_watch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEhE,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,MAAM,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,CAAC;IAC5F,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,WAAW,GACrB,SAAS,YAAY,MACrB,CAAC,EACA,QAAQ,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAC/B,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,EACrD,UAAU,YAAY,CAAC,CAAC,CAAC,KACxB,YA8CF,CAAC"}
package/dist/_watch.js CHANGED
@@ -1,14 +1,23 @@
1
1
  //#region src/_watch.ts
2
2
  var e = (e) => (t, n, r) => {
3
3
  let i = typeof t == "function" ? t : () => t.value, a = r?.equals ?? Object.is, o = !0, s, c = !1, l = e.effect(() => {
4
- let e = i();
4
+ let t = i();
5
5
  if (o) {
6
- o = !1, s = e, r?.immediate && (n(e, void 0), r?.once && (c = !0));
6
+ if (o = !1, s = t, r?.immediate) try {
7
+ e.untrack(() => n(t, void 0));
8
+ } finally {
9
+ r?.once && (c = !0);
10
+ }
7
11
  return;
8
12
  }
9
- if (a(s, e)) return;
10
- let t = s;
11
- s = e, n(e, t), r?.once && l.dispose();
13
+ if (a(s, t)) return;
14
+ let u = s;
15
+ s = t;
16
+ try {
17
+ e.untrack(() => n(t, u));
18
+ } finally {
19
+ r?.once && l.dispose();
20
+ }
12
21
  }, { name: r?.name });
13
22
  return c && l.dispose(), l;
14
23
  };
@@ -1 +1 @@
1
- {"version":3,"file":"_watch.js","names":[],"sources":["../src/_watch.ts"],"sourcesContent":["import type { EffectHandle, Equality, Readable } from './types';\n\nexport type WatchOptions<T> = {\n equals?: Equality<T>;\n immediate?: boolean;\n name?: string;\n once?: boolean;\n};\n\ntype WatchRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n};\n\nexport const createWatch =\n (runtime: WatchRuntime) =>\n <T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle => {\n const read = typeof source === 'function' ? source : () => source.value;\n const equals = options?.equals ?? Object.is;\n let initial = true;\n let previous: T | undefined;\n // `handle` is in the temporal dead zone during the effect's initial synchronous run —\n // `runtime.effect()` calls `node.run()` before returning. Defer disposal until after\n // the constructor returns so `handle.dispose()` is reachable from inside the callback.\n let disposeAfterInit = false;\n\n const handle = runtime.effect(\n () => {\n const value = read();\n\n if (initial) {\n initial = false;\n previous = value;\n\n if (options?.immediate) {\n callback(value, undefined);\n if (options?.once) disposeAfterInit = true;\n }\n\n return;\n }\n\n if (equals(previous as T, value)) return;\n\n const oldValue = previous;\n\n previous = value;\n callback(value, oldValue);\n\n if (options?.once) handle.dispose();\n },\n { name: options?.name },\n );\n\n if (disposeAfterInit) handle.dispose();\n\n return handle;\n };\n"],"mappings":";AAaA,IAAa,KACV,OAEC,GACA,GACA,MACiB;CACjB,IAAM,IAAO,OAAO,KAAW,aAAa,UAAe,EAAO,OAC5D,IAAS,GAAS,UAAU,OAAO,IACrC,IAAU,IACV,GAIA,IAAmB,IAEjB,IAAS,EAAQ,aACf;EACJ,IAAM,IAAQ,EAAK;EAEnB,IAAI,GAAS;GAIX,AAHA,IAAU,IACV,IAAW,GAEP,GAAS,cACX,EAAS,GAAO,KAAA,CAAS,GACrB,GAAS,SAAM,IAAmB;GAGxC;EACF;EAEA,IAAI,EAAO,GAAe,CAAK,GAAG;EAElC,IAAM,IAAW;EAKjB,AAHA,IAAW,GACX,EAAS,GAAO,CAAQ,GAEpB,GAAS,QAAM,EAAO,QAAQ;CACpC,GACA,EAAE,MAAM,GAAS,KAAK,CACxB;CAIA,OAFI,KAAkB,EAAO,QAAQ,GAE9B;AACT"}
1
+ {"version":3,"file":"_watch.js","names":[],"sources":["../src/_watch.ts"],"sourcesContent":["import type { EffectHandle, Equality, Readable } from './types';\n\nexport type WatchOptions<T> = {\n equals?: Equality<T>;\n immediate?: boolean;\n name?: string;\n once?: boolean;\n};\n\ntype WatchRuntime = {\n effect(callback: () => undefined | (() => void), options?: { name?: string }): EffectHandle;\n untrack<T>(fn: () => T): T;\n};\n\nexport const createWatch =\n (runtime: WatchRuntime) =>\n <T>(\n source: Readable<T> | (() => T),\n callback: (value: T, previous: T | undefined) => void,\n options?: WatchOptions<T>,\n ): EffectHandle => {\n const read = typeof source === 'function' ? source : () => source.value;\n const equals = options?.equals ?? Object.is;\n let initial = true;\n let previous: T | undefined;\n // `handle` is in the temporal dead zone during the effect's initial synchronous run —\n // `runtime.effect()` calls `node.run()` before returning. Defer disposal until after\n // the constructor returns so `handle.dispose()` is reachable from inside the callback.\n let disposeAfterInit = false;\n\n const handle = runtime.effect(\n () => {\n const value = read();\n\n if (initial) {\n initial = false;\n previous = value;\n\n if (options?.immediate) {\n try {\n runtime.untrack(() => callback(value, undefined));\n } finally {\n if (options?.once) disposeAfterInit = true;\n }\n }\n\n return;\n }\n\n if (equals(previous as T, value)) return;\n\n const oldValue = previous;\n\n previous = value;\n try {\n runtime.untrack(() => callback(value, oldValue));\n } finally {\n if (options?.once) handle.dispose();\n }\n },\n { name: options?.name },\n );\n\n if (disposeAfterInit) handle.dispose();\n\n return handle;\n };\n"],"mappings":";AAcA,IAAa,KACV,OAEC,GACA,GACA,MACiB;CACjB,IAAM,IAAO,OAAO,KAAW,aAAa,UAAe,EAAO,OAC5D,IAAS,GAAS,UAAU,OAAO,IACrC,IAAU,IACV,GAIA,IAAmB,IAEjB,IAAS,EAAQ,aACf;EACJ,IAAM,IAAQ,EAAK;EAEnB,IAAI,GAAS;GAIX,IAHA,IAAU,IACV,IAAW,GAEP,GAAS,WACX,IAAI;IACF,EAAQ,cAAc,EAAS,GAAO,KAAA,CAAS,CAAC;GAClD,UAAU;IACR,AAAI,GAAS,SAAM,IAAmB;GACxC;GAGF;EACF;EAEA,IAAI,EAAO,GAAe,CAAK,GAAG;EAElC,IAAM,IAAW;EAEjB,IAAW;EACX,IAAI;GACF,EAAQ,cAAc,EAAS,GAAO,CAAQ,CAAC;EACjD,UAAU;GACR,AAAI,GAAS,QAAM,EAAO,QAAQ;EACpC;CACF,GACA,EAAE,MAAM,GAAS,KAAK,CACxB;CAIA,OAFI,KAAkB,EAAO,QAAQ,GAE9B;AACT"}
package/dist/errors.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{},n=class extends e{},r=class extends e{},i=class extends e{};exports.RippleComputedCycleError=t,exports.RippleDisposedRuntimeError=n,exports.RippleDisposedScopeError=r,exports.RippleError=e,exports.RippleInfiniteLoopError=i;
1
+ var e=class extends Error{static errorName=`RippleError`;constructor(e,t){super(e,t),this.name=new.target.errorName,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{static errorName=`RippleComputedCycleError`},n=class extends e{static errorName=`RippleDisposedResourceError`},r=class extends e{static errorName=`RippleDisposedRuntimeError`},i=class extends e{static errorName=`RippleDisposedScopeError`},a=class extends e{static errorName=`RippleInfiniteLoopError`};exports.RippleComputedCycleError=t,exports.RippleDisposedResourceError=n,exports.RippleDisposedRuntimeError=r,exports.RippleDisposedScopeError=i,exports.RippleError=e,exports.RippleInfiniteLoopError=a;
2
2
  //# sourceMappingURL=errors.cjs.map