@vielzeug/ripple 2.3.0 → 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 -30
  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 +18 -5
  10. package/dist/_default.d.ts.map +1 -1
  11. package/dist/_default.js +20 -17
  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 +18 -7
  46. package/dist/runtime.d.ts.map +1 -1
  47. package/dist/runtime.js +76 -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
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.cjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n RippleComputedCycleError,\n RippleDisposedRuntimeError,\n RippleDisposedScopeError,\n RippleInfiniteLoopError,\n} from './errors';\nimport type {\n Cleanup,\n ComputedOptions,\n EffectHandle,\n EffectOptions,\n ReactiveErrorContext,\n ReactiveObserver,\n Readable,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n Unsubscribe,\n} from './types';\n\nexport const REACTIVE = Symbol.for('@vielzeug/ripple/reactive');\nconst MAX_FLUSH_ITERATIONS = 100;\nconst UNSET = Symbol('ripple.unset');\n\ntype Dependency = ReactiveNode<unknown>;\n\ntype ObserverNode = {\n collecting?: Set<Dependency>;\n readonly dependencies: Set<Dependency>;\n onDependencyChanged(): void;\n};\n\ntype Owned = {\n dispose(): void;\n};\n\nabstract class ReactiveNode<T> {\n readonly [REACTIVE] = true;\n readonly dependents = new Set<ObserverNode>();\n readonly name: string | undefined;\n protected readonly runtime: ReactiveRuntime;\n\n protected constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n abstract peek(): T;\n abstract get value(): T;\n\n subscribe(listener: () => void): Unsubscribe {\n this.runtime.assertActive();\n this.peek();\n\n const observer: ObserverNode = {\n dependencies: new Set(),\n onDependencyChanged: () => this.runtime.enqueueListener(listener),\n };\n\n this.dependents.add(observer);\n\n return () => this.dependents.delete(observer);\n }\n\n protected notify(): void {\n for (const dependent of [...this.dependents]) dependent.onDependencyChanged();\n }\n}\n\nclass SignalNode<T> extends ReactiveNode<T> implements Signal<T> {\n private current: T;\n private readonly equals: (previous: T, next: T) => boolean;\n\n constructor(runtime: ReactiveRuntime, initial: T, options?: SignalOptions<T>) {\n super(runtime, options?.name);\n this.current = initial;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n this.runtime.track(this);\n\n return this.current;\n }\n\n set value(next: T) {\n this.runtime.assertActive();\n\n if (this.equals(this.current, next)) return;\n\n const previous = this.current;\n\n this.current = next;\n this.runtime.emit({ kind: 'write', name: this.name, next, previous });\n this.runtime.propagate(() => this.notify());\n }\n\n peek(): T {\n return this.current;\n }\n\n update(updater: (prev: T) => T): void {\n this.value = updater(this.current);\n }\n}\n\nclass ComputedNode<T> extends ReactiveNode<T> implements ObserverNode, Owned {\n readonly dependencies = new Set<Dependency>();\n private computing = false;\n private disposed = false;\n private dirty = true;\n private current: T | typeof UNSET = UNSET;\n private readonly derive: () => T;\n private readonly equals: (previous: T, next: T) => boolean;\n\n constructor(runtime: ReactiveRuntime, derive: () => T, options?: ComputedOptions<T>) {\n super(runtime, options?.name);\n this.derive = derive;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n // Track before refresh: if refresh throws, the consumer still depends on\n // this computed and must be notified when a dependency change might let it\n // succeed. Without this, a first-run failure permanently severs the\n // consumer from the computed.\n this.runtime.track(this);\n this.refresh();\n\n return this.current as T;\n }\n\n peek(): T {\n this.refresh();\n\n return this.current as T;\n }\n\n onDependencyChanged(): void {\n if (this.disposed) return;\n\n if (!this.dirty) this.dirty = true;\n\n if (this.dependents.size > 0 && this.refresh()) this.notify();\n }\n\n dispose(): void {\n if (this.disposed) return;\n\n this.disposed = true;\n this.runtime.clearDependencies(this);\n this.dependents.clear();\n }\n\n private refresh(): boolean {\n if (!this.dirty || this.disposed) return false;\n\n if (this.computing) {\n const label = this.name === undefined ? '' : ` \"${this.name}\"`;\n\n throw new RippleComputedCycleError(`computed cycle detected${label}`);\n }\n\n this.computing = true;\n this.runtime.emit({ kind: 'compute', name: this.name });\n\n try {\n const next = this.runtime.collect(this, this.derive);\n const changed = this.current === UNSET || !this.equals(this.current as T, next);\n\n this.current = next;\n this.dirty = false;\n\n return changed;\n } finally {\n this.computing = false;\n }\n }\n}\n\nclass ScopeNode implements Scope {\n readonly disposalController = new AbortController();\n readonly owned = new Set<Owned>();\n readonly name: string | undefined;\n private isDisposed = false;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n run<T>(fn: () => T): T {\n if (this.isDisposed) throw new RippleDisposedScopeError('Cannot run a disposed scope.');\n\n return this.runtime.withScope(this, fn);\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n for (const owned of [...this.owned].reverse()) owned.dispose();\n this.owned.clear();\n this.disposalController.abort();\n this.runtime.emit({ kind: 'dispose', name: this.name, node: 'scope' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n\nclass EffectNode implements ObserverNode, EffectHandle {\n readonly dependencies = new Set<Dependency>();\n readonly disposalController = new AbortController();\n private cleanup: Cleanup | undefined;\n private isDisposed = false;\n private owner: ScopeNode | undefined;\n private scheduled = false;\n private readonly callback: () => Cleanup | undefined;\n private readonly options: EffectOptions | undefined;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, callback: () => Cleanup | undefined, options?: EffectOptions) {\n this.runtime = runtime;\n this.callback = callback;\n this.options = options;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n onDependencyChanged(): void {\n if (this.isDisposed) return;\n\n if (this.options?.scheduler === 'microtask') {\n if (this.scheduled) return;\n\n this.scheduled = true;\n queueMicrotask(() => {\n this.scheduled = false;\n\n if (!this.isDisposed) this.runtime.enqueue(this);\n });\n\n return;\n }\n\n this.runtime.enqueue(this);\n }\n\n run(): void {\n if (this.isDisposed) return;\n\n this.owner?.dispose();\n this.owner = undefined;\n this.runCleanup();\n this.runtime.emit({ kind: 'effect', name: this.options?.name });\n\n const owner = new ScopeNode(this.runtime);\n\n try {\n const cleanup = this.runtime.withEffectScope(owner, () => this.runtime.collectEffect(this, this.callback));\n\n this.owner = owner;\n this.cleanup = typeof cleanup === 'function' ? cleanup : undefined;\n } catch (error) {\n owner.dispose();\n this.runtime.report(error, { kind: 'effect', name: this.options?.name });\n }\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.owner?.dispose();\n this.owner = undefined;\n this.runtime.clearDependencies(this);\n this.runCleanup();\n this.disposalController.abort();\n this.runtime.emit({ kind: 'dispose', name: this.options?.name, node: 'effect' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n private runCleanup(): void {\n const cleanup = this.cleanup;\n\n this.cleanup = undefined;\n\n if (cleanup === undefined) return;\n\n try {\n cleanup();\n } catch (error) {\n this.runtime.report(error, { kind: 'cleanup', name: this.options?.name });\n }\n }\n}\n\n/**\n * A runtime owns reactive graph state and lifetime. Separate instances isolate\n * applications and SSR requests without process-wide mutable hooks.\n */\nexport class ReactiveRuntime {\n private activeEffectScope: ScopeNode | undefined;\n private activeObserver: ObserverNode | undefined;\n private activeScope: ScopeNode;\n private isDisposed = false;\n private flushDepth = 0;\n private flushing = false;\n private readonly pending = new Set<EffectNode>();\n private readonly listeners = new Set<() => void>();\n private readonly rootScope: ScopeNode;\n private readonly observer: ReactiveObserver | undefined;\n private readonly onError: (error: unknown, context: ReactiveErrorContext) => void;\n\n constructor(options?: RippleOptions) {\n this.observer = options?.observer;\n this.onError =\n options?.onError ??\n ((error) => {\n queueMicrotask(() => {\n throw error;\n });\n });\n this.rootScope = new ScopeNode(this, 'runtime');\n this.activeScope = this.rootScope;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.rootScope.disposalSignal;\n }\n\n readonly signal = <T>(initial: T, options?: SignalOptions<T>): Signal<T> => {\n this.assertActive();\n\n return new SignalNode(this, initial, options);\n };\n\n readonly computed = <T>(derive: () => T, options?: ComputedOptions<T>): Readable<T> => {\n this.assertActive();\n\n const node = new ComputedNode(this, derive, options);\n\n (this.activeEffectScope ?? this.activeScope).owned.add(node);\n\n return node;\n };\n\n readonly effect = (callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle => {\n this.assertActive();\n\n const node = new EffectNode(this, callback, options);\n\n (this.activeEffectScope ?? this.activeScope).owned.add(node);\n node.run();\n\n return node;\n };\n\n readonly createScope = (name?: string): Scope => {\n this.assertActive();\n\n const scope = new ScopeNode(this, name);\n\n // Scopes model explicit, caller-owned lifetimes. Unlike effects/computeds created during an\n // effect run, they deliberately attach to the enclosing scope rather than the per-run owner:\n // keyed DOM directives retain item scopes across reconciliation runs and dispose them only\n // when the item itself leaves the collection.\n this.activeScope.owned.add(scope);\n\n return scope;\n };\n\n readonly batch = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.propagate(fn);\n };\n\n readonly untrack = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.withObserver(undefined, fn);\n };\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.rootScope.dispose();\n }\n\n /** Internal node guard: disposed runtimes allow inert reads but reject graph work and mutation. */\n assertActive(): void {\n if (this.isDisposed) throw new RippleDisposedRuntimeError('Cannot use a disposed Ripple runtime.');\n }\n\n track(node: Dependency): void {\n const observer = this.activeObserver;\n\n if (observer?.collecting === undefined) return;\n\n observer.collecting.add(node);\n }\n\n clearDependencies(observer: ObserverNode): void {\n for (const dependency of observer.dependencies) dependency.dependents.delete(observer);\n observer.dependencies.clear();\n }\n\n collect<T>(observer: ObserverNode, fn: () => T): T {\n // On first run (no prior dependencies), commit partial dependencies even if\n // derive throws — otherwise the computed would have zero dependencies and never\n // be notified when its source changes, permanently stuck until a manual read.\n // On subsequent runs, keep previous dependencies (tested behavior).\n return this.collectWith(observer, fn, observer.dependencies.size === 0);\n }\n\n collectEffect<T>(observer: ObserverNode, fn: () => T): T {\n return this.collectWith(observer, fn, true);\n }\n\n withEffectScope<T>(scope: ScopeNode, fn: () => T): T {\n const previous = this.activeEffectScope;\n\n this.activeEffectScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previous;\n }\n }\n\n withObserver<T>(observer: ObserverNode | undefined, fn: () => T): T {\n const previous = this.activeObserver;\n\n this.activeObserver = observer;\n\n try {\n return fn();\n } finally {\n this.activeObserver = previous;\n }\n }\n\n withScope<T>(scope: ScopeNode, fn: () => T): T {\n const previousEffectScope = this.activeEffectScope;\n const previousScope = this.activeScope;\n\n this.activeEffectScope = undefined;\n this.activeScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previousEffectScope;\n this.activeScope = previousScope;\n }\n }\n\n enqueue(effect: EffectNode): void {\n this.pending.add(effect);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n enqueueListener(listener: () => void): void {\n this.listeners.add(listener);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n propagate<T>(fn: () => T): T {\n this.flushDepth++;\n\n try {\n return fn();\n } finally {\n this.flushDepth--;\n\n if (this.flushDepth === 0) this.flush();\n }\n }\n\n emit(event: Parameters<ReactiveObserver>[0]): void {\n try {\n this.observer?.(event);\n } catch (error) {\n this.report(error, { kind: 'observer', name: event.name });\n }\n }\n\n report(error: unknown, context: ReactiveErrorContext): void {\n try {\n this.onError(error, context);\n } catch (reporterError) {\n queueMicrotask(() => {\n throw reporterError;\n });\n }\n }\n\n private collectWith<T>(observer: ObserverNode, fn: () => T, commitOnError: boolean): T {\n const previousObserver = this.activeObserver;\n const dependencies = new Set<Dependency>();\n\n observer.collecting = dependencies;\n this.activeObserver = observer;\n\n try {\n const result = fn();\n\n this.commitDependencies(observer, dependencies);\n\n return result;\n } catch (error) {\n if (commitOnError) this.commitDependencies(observer, dependencies);\n\n throw error;\n } finally {\n observer.collecting = undefined;\n this.activeObserver = previousObserver;\n }\n }\n\n private commitDependencies(observer: ObserverNode, next: Set<Dependency>): void {\n for (const dependency of observer.dependencies) {\n if (!next.has(dependency)) dependency.dependents.delete(observer);\n }\n\n for (const dependency of next) {\n if (!observer.dependencies.has(dependency)) dependency.dependents.add(observer);\n }\n\n observer.dependencies.clear();\n for (const dependency of next) observer.dependencies.add(dependency);\n }\n\n private flush(): void {\n if (this.flushing) return;\n\n this.flushing = true;\n\n let iterations = 0;\n\n try {\n while (this.pending.size > 0 || this.listeners.size > 0) {\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n throw new RippleInfiniteLoopError(`infinite reactive flush (>${MAX_FLUSH_ITERATIONS} iterations)`);\n }\n\n const effects = [...this.pending];\n const listeners = [...this.listeners];\n\n this.pending.clear();\n this.listeners.clear();\n\n for (const effect of effects) effect.run();\n\n for (const listener of listeners) {\n try {\n listener();\n } catch (error) {\n this.report(error, { kind: 'listener' });\n }\n }\n }\n } finally {\n this.flushing = false;\n }\n }\n}\n\nexport const isReactive = <T>(value: T | Readable<T>): value is Readable<T> => {\n if (typeof value !== 'object' || value === null || !(REACTIVE in value)) return false;\n\n const candidate = value as { peek?: unknown; subscribe?: unknown };\n\n return typeof candidate.peek === 'function' && typeof candidate.subscribe === 'function';\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime.cjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n RippleComputedCycleError,\n RippleDisposedRuntimeError,\n RippleDisposedScopeError,\n RippleInfiniteLoopError,\n} from './errors';\nimport type {\n Cleanup,\n ComputedOptions,\n EffectHandle,\n EffectOptions,\n Readable,\n RippleErrorContext,\n RippleErrorPolicy,\n RippleEvent,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n Unsubscribe,\n} from './types';\n\nexport const REACTIVE = Symbol.for('@vielzeug/ripple/reactive');\nconst MAX_FLUSH_ITERATIONS = 100;\nconst UNSET = Symbol('ripple.unset');\n\ntype Dependency = ReactiveNode<unknown>;\n\ntype ObserverNode = {\n collecting?: Set<Dependency>;\n readonly dependencies: Set<Dependency>;\n onDependencyChanged(): void;\n};\n\ntype Owned = {\n dispose(): void;\n setOwner(owner: ScopeNode | undefined): void;\n};\n\nabstract class ReactiveNode<T> {\n readonly [REACTIVE] = true;\n readonly dependents = new Set<ObserverNode>();\n readonly name: string | undefined;\n protected readonly runtime: ReactiveRuntime;\n\n protected constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n abstract peek(): T;\n abstract get value(): T;\n\n subscribe(listener: () => void): Unsubscribe {\n this.runtime.assertActive();\n this.peek();\n\n const observer: ObserverNode = {\n dependencies: new Set(),\n onDependencyChanged: () => this.runtime.enqueueListener(listener),\n };\n\n this.dependents.add(observer);\n\n return () => this.dependents.delete(observer);\n }\n\n protected notify(): void {\n for (const dependent of [...this.dependents]) dependent.onDependencyChanged();\n }\n}\n\nclass SignalNode<T> extends ReactiveNode<T> implements Signal<T> {\n private current: T;\n private readonly equals: (previous: T, next: T) => boolean;\n\n constructor(runtime: ReactiveRuntime, initial: T, options?: SignalOptions<T>) {\n super(runtime, options?.name);\n this.current = initial;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n this.runtime.track(this);\n\n return this.current;\n }\n\n set value(next: T) {\n this.runtime.assertActive();\n\n if (this.equals(this.current, next)) return;\n\n const previous = this.current;\n\n this.current = next;\n this.runtime.emit({ name: this.name, next, previous, type: 'write' });\n this.runtime.propagate(() => this.notify());\n }\n\n peek(): T {\n return this.current;\n }\n\n update(updater: (prev: T) => T): void {\n this.value = updater(this.current);\n }\n}\n\nclass ComputedNode<T> extends ReactiveNode<T> implements ObserverNode, Owned {\n readonly dependencies = new Set<Dependency>();\n private computing = false;\n private disposed = false;\n private dirty = true;\n private current: T | typeof UNSET = UNSET;\n private readonly derive: () => T;\n private readonly equals: (previous: T, next: T) => boolean;\n private owner: ScopeNode | undefined;\n\n constructor(runtime: ReactiveRuntime, derive: () => T, options?: ComputedOptions<T>) {\n super(runtime, options?.name);\n this.derive = derive;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n // Track before refresh: if refresh throws, the consumer still depends on\n // this computed and must be notified when a dependency change might let it\n // succeed. Without this, a first-run failure permanently severs the\n // consumer from the computed.\n this.runtime.track(this);\n this.refresh();\n\n return this.current as T;\n }\n\n peek(): T {\n this.refresh();\n\n return this.current as T;\n }\n\n onDependencyChanged(): void {\n if (this.disposed) return;\n\n if (!this.dirty) this.dirty = true;\n\n if (this.dependents.size > 0) {\n try {\n if (this.refresh()) this.notify();\n } catch (error) {\n this.runtime.report(error, { kind: 'computed', name: this.name });\n }\n }\n }\n\n setOwner(owner: ScopeNode | undefined): void {\n this.owner = owner;\n }\n\n dispose(): void {\n if (this.disposed) return;\n\n this.disposed = true;\n this.owner?.release(this);\n this.owner = undefined;\n this.runtime.clearDependencies(this);\n this.dependents.clear();\n }\n\n private refresh(): boolean {\n if (!this.dirty || this.disposed) return false;\n\n if (this.computing) {\n const label = this.name === undefined ? '' : ` \"${this.name}\"`;\n\n throw new RippleComputedCycleError(`computed cycle detected${label}`);\n }\n\n this.computing = true;\n this.runtime.emit({ name: this.name, type: 'compute' });\n\n try {\n const next = this.runtime.collect(this, this.derive);\n const changed = this.current === UNSET || !this.equals(this.current as T, next);\n\n this.current = next;\n this.dirty = false;\n\n return changed;\n } finally {\n this.computing = false;\n }\n }\n}\n\nclass ScopeNode implements Scope, Owned {\n readonly disposalController = new AbortController();\n readonly owned = new Set<Owned>();\n readonly name: string | undefined;\n private isDisposed = false;\n private owner: ScopeNode | undefined;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n own(value: Owned): void {\n value.setOwner(this);\n this.owned.add(value);\n }\n\n release(value: Owned): void {\n this.owned.delete(value);\n }\n\n setOwner(owner: ScopeNode | undefined): void {\n this.owner = owner;\n }\n\n run<T>(fn: () => T): T {\n if (this.isDisposed) throw new RippleDisposedScopeError('Cannot run a disposed scope.');\n\n return this.runtime.withScope(this, fn);\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.owner?.release(this);\n this.owner = undefined;\n for (const owned of [...this.owned].reverse()) owned.dispose();\n this.owned.clear();\n this.disposalController.abort();\n this.runtime.emit({ name: this.name, node: 'scope', type: 'dispose' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n\nclass EffectNode implements ObserverNode, EffectHandle {\n readonly dependencies = new Set<Dependency>();\n readonly disposalController = new AbortController();\n private cleanup: Cleanup | undefined;\n private isDisposed = false;\n private ownershipScope: ScopeNode | undefined;\n private runScope: ScopeNode | undefined;\n private scheduled = false;\n private readonly callback: () => Cleanup | undefined;\n private readonly options: EffectOptions | undefined;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, callback: () => Cleanup | undefined, options?: EffectOptions) {\n this.runtime = runtime;\n this.callback = callback;\n this.options = options;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n setOwner(owner: ScopeNode | undefined): void {\n this.ownershipScope = owner;\n }\n\n onDependencyChanged(): void {\n if (this.isDisposed) return;\n\n if (this.options?.scheduler === 'microtask') {\n if (this.scheduled) return;\n\n this.scheduled = true;\n queueMicrotask(() => {\n this.scheduled = false;\n\n if (!this.isDisposed) this.runtime.enqueue(this);\n });\n\n return;\n }\n\n this.runtime.enqueue(this);\n }\n\n run(): void {\n if (this.isDisposed) return;\n\n this.runScope?.dispose();\n this.runScope = undefined;\n this.runCleanup();\n this.runtime.emit({ name: this.options?.name, type: 'effect' });\n\n const owner = new ScopeNode(this.runtime);\n\n try {\n const cleanup = this.runtime.withEffectScope(owner, () => this.runtime.collectEffect(this, this.callback));\n\n this.runScope = owner;\n this.cleanup = typeof cleanup === 'function' ? cleanup : undefined;\n if (this.isDisposed) {\n this.runScope.dispose();\n this.runScope = undefined;\n this.runCleanup();\n }\n } catch (error) {\n owner.dispose();\n this.runtime.report(error, { kind: 'effect', name: this.options?.name });\n }\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.ownershipScope?.release(this);\n this.ownershipScope = undefined;\n this.runScope?.dispose();\n this.runScope = undefined;\n this.runtime.clearDependencies(this);\n this.runCleanup();\n this.disposalController.abort();\n this.runtime.emit({ name: this.options?.name, node: 'effect', type: 'dispose' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n private runCleanup(): void {\n const cleanup = this.cleanup;\n\n this.cleanup = undefined;\n\n if (cleanup === undefined) return;\n\n try {\n cleanup();\n } catch (error) {\n this.runtime.report(error, { kind: 'cleanup', name: this.options?.name });\n }\n }\n}\n\n/**\n * A runtime owns reactive graph state and lifetime. Separate instances isolate\n * applications and SSR requests without process-wide mutable hooks.\n */\nexport class ReactiveRuntime {\n private activeEffectScope: ScopeNode | undefined;\n private activeObserver: ObserverNode | undefined;\n private activeScope: ScopeNode;\n private isDisposed = false;\n private flushDepth = 0;\n private flushing = false;\n private readonly pending = new Set<EffectNode>();\n private readonly listeners = new Set<() => void>();\n private readonly rootScope: ScopeNode;\n private readonly tappers = new Set<(event: RippleEvent) => void>();\n private readonly errorPolicy: RippleErrorPolicy;\n\n constructor(options?: RippleOptions) {\n this.errorPolicy = options?.errorPolicy ?? 'throw';\n this.rootScope = new ScopeNode(this, 'runtime');\n this.activeScope = this.rootScope;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.rootScope.disposalSignal;\n }\n\n readonly signal = <T>(initial: T, options?: SignalOptions<T>): Signal<T> => {\n this.assertActive();\n\n return new SignalNode(this, initial, options);\n };\n\n readonly computed = <T>(derive: () => T, options?: ComputedOptions<T>): Readable<T> => {\n this.assertActive();\n\n const node = new ComputedNode(this, derive, options);\n\n (this.activeEffectScope ?? this.activeScope).own(node);\n\n return node;\n };\n\n readonly effect = (callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle => {\n this.assertActive();\n\n const node = new EffectNode(this, callback, options);\n\n (this.activeEffectScope ?? this.activeScope).own(node);\n node.run();\n\n return node;\n };\n\n readonly createScope = (name?: string): Scope => {\n this.assertActive();\n\n const scope = new ScopeNode(this, name);\n\n // Scopes model explicit, caller-owned lifetimes. Unlike effects/computeds created during an\n // effect run, they deliberately attach to the enclosing scope rather than the per-run owner:\n // keyed DOM directives retain item scopes across reconciliation runs and dispose them only\n // when the item itself leaves the collection.\n this.activeScope.own(scope);\n\n return scope;\n };\n\n readonly batch = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.propagate(fn);\n };\n\n readonly untrack = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.withObserver(undefined, fn);\n };\n\n /** Runtime observability — see `Ripple.tap()`. */\n readonly tap = (handler: (event: RippleEvent) => void, options?: { signal?: AbortSignal }): Unsubscribe => {\n if (this.isDisposed) return () => {};\n\n const signal = options?.signal;\n\n if (signal?.aborted) {\n this.tappers.delete(handler);\n return () => {};\n }\n\n this.tappers.add(handler);\n\n if (signal) {\n const onAbort = () => this.tappers.delete(handler);\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n this.tappers.delete(handler);\n signal.removeEventListener('abort', onAbort);\n };\n }\n\n return () => this.tappers.delete(handler);\n };\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.rootScope.dispose();\n this.emit({ node: 'graph', type: 'dispose' });\n this.tappers.clear();\n }\n\n /** Internal node guard: disposed runtimes allow inert reads but reject graph work and mutation. */\n assertActive(): void {\n if (this.isDisposed) throw new RippleDisposedRuntimeError('Cannot use a disposed Ripple runtime.');\n }\n\n track(node: Dependency): void {\n const observer = this.activeObserver;\n\n if (observer?.collecting === undefined) return;\n\n observer.collecting.add(node);\n }\n\n clearDependencies(observer: ObserverNode): void {\n for (const dependency of observer.dependencies) dependency.dependents.delete(observer);\n observer.dependencies.clear();\n }\n\n collect<T>(observer: ObserverNode, fn: () => T): T {\n // On first run (no prior dependencies), commit partial dependencies even if\n // derive throws — otherwise the computed would have zero dependencies and never\n // be notified when its source changes, permanently stuck until a manual read.\n // On subsequent runs, keep previous dependencies (tested behavior).\n return this.collectWith(observer, fn, observer.dependencies.size === 0);\n }\n\n collectEffect<T>(observer: ObserverNode, fn: () => T): T {\n return this.collectWith(observer, fn, true);\n }\n\n withEffectScope<T>(scope: ScopeNode, fn: () => T): T {\n const previous = this.activeEffectScope;\n\n this.activeEffectScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previous;\n }\n }\n\n withObserver<T>(observer: ObserverNode | undefined, fn: () => T): T {\n const previous = this.activeObserver;\n\n this.activeObserver = observer;\n\n try {\n return fn();\n } finally {\n this.activeObserver = previous;\n }\n }\n\n withScope<T>(scope: ScopeNode, fn: () => T): T {\n const previousEffectScope = this.activeEffectScope;\n const previousScope = this.activeScope;\n\n this.activeEffectScope = undefined;\n this.activeScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previousEffectScope;\n this.activeScope = previousScope;\n }\n }\n\n enqueue(effect: EffectNode): void {\n this.pending.add(effect);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n enqueueListener(listener: () => void): void {\n this.listeners.add(listener);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n propagate<T>(fn: () => T): T {\n this.flushDepth++;\n\n try {\n return fn();\n } finally {\n this.flushDepth--;\n\n if (this.flushDepth === 0) this.flush();\n }\n }\n\n emit(event: RippleEvent): void {\n if (this.tappers.size === 0) return;\n\n for (const tapper of this.tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect runtime behavior.\n }\n }\n }\n\n report(error: unknown, context: RippleErrorContext): void {\n this.emit({ context, error, type: 'error' });\n\n if (this.errorPolicy === 'throw') {\n queueMicrotask(() => {\n throw error;\n });\n }\n }\n\n private collectWith<T>(observer: ObserverNode, fn: () => T, commitOnError: boolean): T {\n const previousObserver = this.activeObserver;\n const dependencies = new Set<Dependency>();\n\n observer.collecting = dependencies;\n this.activeObserver = observer;\n\n try {\n const result = fn();\n\n this.commitDependencies(observer, dependencies);\n\n return result;\n } catch (error) {\n if (commitOnError) this.commitDependencies(observer, dependencies);\n\n throw error;\n } finally {\n observer.collecting = undefined;\n this.activeObserver = previousObserver;\n }\n }\n\n private commitDependencies(observer: ObserverNode, next: Set<Dependency>): void {\n for (const dependency of observer.dependencies) {\n if (!next.has(dependency)) dependency.dependents.delete(observer);\n }\n\n for (const dependency of next) {\n if (!observer.dependencies.has(dependency)) dependency.dependents.add(observer);\n }\n\n observer.dependencies.clear();\n for (const dependency of next) observer.dependencies.add(dependency);\n }\n\n private flush(): void {\n if (this.flushing) return;\n\n this.flushing = true;\n\n let iterations = 0;\n\n try {\n while (this.pending.size > 0 || this.listeners.size > 0) {\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n throw new RippleInfiniteLoopError(`infinite reactive flush (>${MAX_FLUSH_ITERATIONS} iterations)`);\n }\n\n const effects = [...this.pending];\n const listeners = [...this.listeners];\n\n this.pending.clear();\n this.listeners.clear();\n\n for (const effect of effects) effect.run();\n\n for (const listener of listeners) {\n try {\n listener();\n } catch (error) {\n this.report(error, { kind: 'listener' });\n }\n }\n }\n } finally {\n this.flushing = false;\n }\n }\n}\n\nexport const isReactive = <T>(value: T | Readable<T>): value is Readable<T> => {\n if (typeof value !== 'object' || value === null || (value as { [REACTIVE]?: unknown })[REACTIVE] !== true)\n return false;\n\n const candidate = value as { peek?: unknown; subscribe?: unknown; value?: unknown };\n\n return 'value' in candidate && typeof candidate.peek === 'function' && typeof candidate.subscribe === 'function';\n};\n"],"mappings":"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"}
package/dist/runtime.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Cleanup, ComputedOptions, EffectHandle, EffectOptions, ReactiveErrorContext, ReactiveObserver, Readable, RippleOptions, Scope, Signal, SignalOptions, Unsubscribe } from './types';
1
+ import type { Cleanup, ComputedOptions, EffectHandle, EffectOptions, Readable, RippleErrorContext, RippleEvent, RippleOptions, Scope, Signal, SignalOptions, Unsubscribe } from './types';
2
2
  export declare const REACTIVE: unique symbol;
3
3
  type Dependency = ReactiveNode<unknown>;
4
4
  type ObserverNode = {
@@ -8,6 +8,7 @@ type ObserverNode = {
8
8
  };
9
9
  type Owned = {
10
10
  dispose(): void;
11
+ setOwner(owner: ScopeNode | undefined): void;
11
12
  };
12
13
  declare abstract class ReactiveNode<T> {
13
14
  readonly [REACTIVE] = true;
@@ -20,15 +21,19 @@ declare abstract class ReactiveNode<T> {
20
21
  subscribe(listener: () => void): Unsubscribe;
21
22
  protected notify(): void;
22
23
  }
23
- declare class ScopeNode implements Scope {
24
+ declare class ScopeNode implements Scope, Owned {
24
25
  readonly disposalController: AbortController;
25
26
  readonly owned: Set<Owned>;
26
27
  readonly name: string | undefined;
27
28
  private isDisposed;
29
+ private owner;
28
30
  private readonly runtime;
29
31
  constructor(runtime: ReactiveRuntime, name?: string);
30
32
  get disposed(): boolean;
31
33
  get disposalSignal(): AbortSignal;
34
+ own(value: Owned): void;
35
+ release(value: Owned): void;
36
+ setOwner(owner: ScopeNode | undefined): void;
32
37
  run<T>(fn: () => T): T;
33
38
  dispose(): void;
34
39
  [Symbol.dispose](): void;
@@ -38,7 +43,8 @@ declare class EffectNode implements ObserverNode, EffectHandle {
38
43
  readonly disposalController: AbortController;
39
44
  private cleanup;
40
45
  private isDisposed;
41
- private owner;
46
+ private ownershipScope;
47
+ private runScope;
42
48
  private scheduled;
43
49
  private readonly callback;
44
50
  private readonly options;
@@ -46,6 +52,7 @@ declare class EffectNode implements ObserverNode, EffectHandle {
46
52
  constructor(runtime: ReactiveRuntime, callback: () => Cleanup | undefined, options?: EffectOptions);
47
53
  get disposed(): boolean;
48
54
  get disposalSignal(): AbortSignal;
55
+ setOwner(owner: ScopeNode | undefined): void;
49
56
  onDependencyChanged(): void;
50
57
  run(): void;
51
58
  dispose(): void;
@@ -66,8 +73,8 @@ export declare class ReactiveRuntime {
66
73
  private readonly pending;
67
74
  private readonly listeners;
68
75
  private readonly rootScope;
69
- private readonly observer;
70
- private readonly onError;
76
+ private readonly tappers;
77
+ private readonly errorPolicy;
71
78
  constructor(options?: RippleOptions);
72
79
  get disposed(): boolean;
73
80
  get disposalSignal(): AbortSignal;
@@ -77,6 +84,10 @@ export declare class ReactiveRuntime {
77
84
  readonly createScope: (name?: string) => Scope;
78
85
  readonly batch: <T>(fn: () => T) => T;
79
86
  readonly untrack: <T>(fn: () => T) => T;
87
+ /** Runtime observability — see `Ripple.tap()`. */
88
+ readonly tap: (handler: (event: RippleEvent) => void, options?: {
89
+ signal?: AbortSignal;
90
+ }) => Unsubscribe;
80
91
  dispose(): void;
81
92
  /** Internal node guard: disposed runtimes allow inert reads but reject graph work and mutation. */
82
93
  assertActive(): void;
@@ -90,8 +101,8 @@ export declare class ReactiveRuntime {
90
101
  enqueue(effect: EffectNode): void;
91
102
  enqueueListener(listener: () => void): void;
92
103
  propagate<T>(fn: () => T): T;
93
- emit(event: Parameters<ReactiveObserver>[0]): void;
94
- report(error: unknown, context: ReactiveErrorContext): void;
104
+ emit(event: RippleEvent): void;
105
+ report(error: unknown, context: RippleErrorContext): void;
95
106
  private collectWith;
96
107
  private commitDependencies;
97
108
  private flush;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
package/dist/runtime.js CHANGED
@@ -32,10 +32,10 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
32
32
  if (this.runtime.assertActive(), this.equals(this.current, e)) return;
33
33
  let t = this.current;
34
34
  this.current = e, this.runtime.emit({
35
- kind: "write",
36
35
  name: this.name,
37
36
  next: e,
38
- previous: t
37
+ previous: t,
38
+ type: "write"
39
39
  }), this.runtime.propagate(() => this.notify());
40
40
  }
41
41
  peek() {
@@ -52,6 +52,7 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
52
52
  current = o;
53
53
  derive;
54
54
  equals;
55
+ owner;
55
56
  constructor(e, t, n) {
56
57
  super(e, n?.name), this.derive = t, this.equals = n?.equals ?? Object.is;
57
58
  }
@@ -62,10 +63,20 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
62
63
  return this.refresh(), this.current;
63
64
  }
64
65
  onDependencyChanged() {
65
- this.disposed || (this.dirty ||= !0, this.dependents.size > 0 && this.refresh() && this.notify());
66
+ if (!this.disposed && (this.dirty ||= !0, this.dependents.size > 0)) try {
67
+ this.refresh() && this.notify();
68
+ } catch (e) {
69
+ this.runtime.report(e, {
70
+ kind: "computed",
71
+ name: this.name
72
+ });
73
+ }
74
+ }
75
+ setOwner(e) {
76
+ this.owner = e;
66
77
  }
67
78
  dispose() {
68
- this.disposed || (this.disposed = !0, this.runtime.clearDependencies(this), this.dependents.clear());
79
+ this.disposed || (this.disposed = !0, this.owner?.release(this), this.owner = void 0, this.runtime.clearDependencies(this), this.dependents.clear());
69
80
  }
70
81
  refresh() {
71
82
  if (!this.dirty || this.disposed) return !1;
@@ -74,8 +85,8 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
74
85
  throw new e(`computed cycle detected${t}`);
75
86
  }
76
87
  this.computing = !0, this.runtime.emit({
77
- kind: "compute",
78
- name: this.name
88
+ name: this.name,
89
+ type: "compute"
79
90
  });
80
91
  try {
81
92
  let e = this.runtime.collect(this, this.derive), t = this.current === o || !this.equals(this.current, e);
@@ -89,6 +100,7 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
89
100
  owned = /* @__PURE__ */ new Set();
90
101
  name;
91
102
  isDisposed = !1;
103
+ owner;
92
104
  runtime;
93
105
  constructor(e, t) {
94
106
  this.runtime = e, this.name = t;
@@ -99,18 +111,27 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
99
111
  get disposalSignal() {
100
112
  return this.disposalController.signal;
101
113
  }
114
+ own(e) {
115
+ e.setOwner(this), this.owned.add(e);
116
+ }
117
+ release(e) {
118
+ this.owned.delete(e);
119
+ }
120
+ setOwner(e) {
121
+ this.owner = e;
122
+ }
102
123
  run(e) {
103
124
  if (this.isDisposed) throw new n("Cannot run a disposed scope.");
104
125
  return this.runtime.withScope(this, e);
105
126
  }
106
127
  dispose() {
107
128
  if (!this.isDisposed) {
108
- this.isDisposed = !0;
129
+ this.isDisposed = !0, this.owner?.release(this), this.owner = void 0;
109
130
  for (let e of [...this.owned].reverse()) e.dispose();
110
131
  this.owned.clear(), this.disposalController.abort(), this.runtime.emit({
111
- kind: "dispose",
112
132
  name: this.name,
113
- node: "scope"
133
+ node: "scope",
134
+ type: "dispose"
114
135
  });
115
136
  }
116
137
  }
@@ -122,7 +143,8 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
122
143
  disposalController = new AbortController();
123
144
  cleanup;
124
145
  isDisposed = !1;
125
- owner;
146
+ ownershipScope;
147
+ runScope;
126
148
  scheduled = !1;
127
149
  callback;
128
150
  options;
@@ -136,6 +158,9 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
136
158
  get disposalSignal() {
137
159
  return this.disposalController.signal;
138
160
  }
161
+ setOwner(e) {
162
+ this.ownershipScope = e;
163
+ }
139
164
  onDependencyChanged() {
140
165
  if (!this.isDisposed) {
141
166
  if (this.options?.scheduler === "microtask") {
@@ -150,14 +175,14 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
150
175
  }
151
176
  run() {
152
177
  if (this.isDisposed) return;
153
- this.owner?.dispose(), this.owner = void 0, this.runCleanup(), this.runtime.emit({
154
- kind: "effect",
155
- name: this.options?.name
178
+ this.runScope?.dispose(), this.runScope = void 0, this.runCleanup(), this.runtime.emit({
179
+ name: this.options?.name,
180
+ type: "effect"
156
181
  });
157
182
  let e = new u(this.runtime);
158
183
  try {
159
184
  let t = this.runtime.withEffectScope(e, () => this.runtime.collectEffect(this, this.callback));
160
- this.owner = e, this.cleanup = typeof t == "function" ? t : void 0;
185
+ this.runScope = e, this.cleanup = typeof t == "function" ? t : void 0, this.isDisposed && (this.runScope.dispose(), this.runScope = void 0, this.runCleanup());
161
186
  } catch (t) {
162
187
  e.dispose(), this.runtime.report(t, {
163
188
  kind: "effect",
@@ -166,10 +191,10 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
166
191
  }
167
192
  }
168
193
  dispose() {
169
- this.isDisposed || (this.isDisposed = !0, this.owner?.dispose(), this.owner = void 0, this.runtime.clearDependencies(this), this.runCleanup(), this.disposalController.abort(), this.runtime.emit({
170
- kind: "dispose",
194
+ this.isDisposed || (this.isDisposed = !0, this.ownershipScope?.release(this), this.ownershipScope = void 0, this.runScope?.dispose(), this.runScope = void 0, this.runtime.clearDependencies(this), this.runCleanup(), this.disposalController.abort(), this.runtime.emit({
171
195
  name: this.options?.name,
172
- node: "effect"
196
+ node: "effect",
197
+ type: "dispose"
173
198
  }));
174
199
  }
175
200
  [Symbol.dispose]() {
@@ -196,14 +221,10 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
196
221
  pending = /* @__PURE__ */ new Set();
197
222
  listeners = /* @__PURE__ */ new Set();
198
223
  rootScope;
199
- observer;
200
- onError;
224
+ tappers = /* @__PURE__ */ new Set();
225
+ errorPolicy;
201
226
  constructor(e) {
202
- this.observer = e?.observer, this.onError = e?.onError ?? ((e) => {
203
- queueMicrotask(() => {
204
- throw e;
205
- });
206
- }), this.rootScope = new u(this, "runtime"), this.activeScope = this.rootScope;
227
+ this.errorPolicy = e?.errorPolicy ?? "throw", this.rootScope = new u(this, "runtime"), this.activeScope = this.rootScope;
207
228
  }
208
229
  get disposed() {
209
230
  return this.isDisposed;
@@ -215,22 +236,37 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
215
236
  computed = (e, t) => {
216
237
  this.assertActive();
217
238
  let n = new l(this, e, t);
218
- return (this.activeEffectScope ?? this.activeScope).owned.add(n), n;
239
+ return (this.activeEffectScope ?? this.activeScope).own(n), n;
219
240
  };
220
241
  effect = (e, t) => {
221
242
  this.assertActive();
222
243
  let n = new d(this, e, t);
223
- return (this.activeEffectScope ?? this.activeScope).owned.add(n), n.run(), n;
244
+ return (this.activeEffectScope ?? this.activeScope).own(n), n.run(), n;
224
245
  };
225
246
  createScope = (e) => {
226
247
  this.assertActive();
227
248
  let t = new u(this, e);
228
- return this.activeScope.owned.add(t), t;
249
+ return this.activeScope.own(t), t;
229
250
  };
230
251
  batch = (e) => (this.assertActive(), this.propagate(e));
231
252
  untrack = (e) => (this.assertActive(), this.withObserver(void 0, e));
253
+ tap = (e, t) => {
254
+ if (this.isDisposed) return () => {};
255
+ let n = t?.signal;
256
+ if (n?.aborted) return this.tappers.delete(e), () => {};
257
+ if (this.tappers.add(e), n) {
258
+ let t = () => this.tappers.delete(e);
259
+ return n.addEventListener("abort", t, { once: !0 }), () => {
260
+ this.tappers.delete(e), n.removeEventListener("abort", t);
261
+ };
262
+ }
263
+ return () => this.tappers.delete(e);
264
+ };
232
265
  dispose() {
233
- this.isDisposed || (this.isDisposed = !0, this.rootScope.dispose());
266
+ this.isDisposed || (this.isDisposed = !0, this.rootScope.dispose(), this.emit({
267
+ node: "graph",
268
+ type: "dispose"
269
+ }), this.tappers.clear());
234
270
  }
235
271
  assertActive() {
236
272
  if (this.isDisposed) throw new t("Cannot use a disposed Ripple runtime.");
@@ -291,23 +327,18 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
291
327
  }
292
328
  }
293
329
  emit(e) {
294
- try {
295
- this.observer?.(e);
296
- } catch (t) {
297
- this.report(t, {
298
- kind: "observer",
299
- name: e.name
300
- });
301
- }
330
+ if (this.tappers.size !== 0) for (let t of this.tappers) try {
331
+ t(e);
332
+ } catch {}
302
333
  }
303
334
  report(e, t) {
304
- try {
305
- this.onError(e, t);
306
- } catch (e) {
307
- queueMicrotask(() => {
308
- throw e;
309
- });
310
- }
335
+ this.emit({
336
+ context: t,
337
+ error: e,
338
+ type: "error"
339
+ }), this.errorPolicy === "throw" && queueMicrotask(() => {
340
+ throw e;
341
+ });
311
342
  }
312
343
  collectWith(e, t, n) {
313
344
  let r = this.activeObserver, i = /* @__PURE__ */ new Set();
@@ -348,9 +379,9 @@ var i = Symbol.for("@vielzeug/ripple/reactive"), a = 100, o = Symbol("ripple.uns
348
379
  }
349
380
  }
350
381
  }, p = (e) => {
351
- if (typeof e != "object" || !e || !(i in e)) return !1;
382
+ if (typeof e != "object" || !e || e[i] !== !0) return !1;
352
383
  let t = e;
353
- return typeof t.peek == "function" && typeof t.subscribe == "function";
384
+ return "value" in t && typeof t.peek == "function" && typeof t.subscribe == "function";
354
385
  };
355
386
  //#endregion
356
387
  export { i as REACTIVE, f as ReactiveRuntime, p as isReactive };
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n RippleComputedCycleError,\n RippleDisposedRuntimeError,\n RippleDisposedScopeError,\n RippleInfiniteLoopError,\n} from './errors';\nimport type {\n Cleanup,\n ComputedOptions,\n EffectHandle,\n EffectOptions,\n ReactiveErrorContext,\n ReactiveObserver,\n Readable,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n Unsubscribe,\n} from './types';\n\nexport const REACTIVE = Symbol.for('@vielzeug/ripple/reactive');\nconst MAX_FLUSH_ITERATIONS = 100;\nconst UNSET = Symbol('ripple.unset');\n\ntype Dependency = ReactiveNode<unknown>;\n\ntype ObserverNode = {\n collecting?: Set<Dependency>;\n readonly dependencies: Set<Dependency>;\n onDependencyChanged(): void;\n};\n\ntype Owned = {\n dispose(): void;\n};\n\nabstract class ReactiveNode<T> {\n readonly [REACTIVE] = true;\n readonly dependents = new Set<ObserverNode>();\n readonly name: string | undefined;\n protected readonly runtime: ReactiveRuntime;\n\n protected constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n abstract peek(): T;\n abstract get value(): T;\n\n subscribe(listener: () => void): Unsubscribe {\n this.runtime.assertActive();\n this.peek();\n\n const observer: ObserverNode = {\n dependencies: new Set(),\n onDependencyChanged: () => this.runtime.enqueueListener(listener),\n };\n\n this.dependents.add(observer);\n\n return () => this.dependents.delete(observer);\n }\n\n protected notify(): void {\n for (const dependent of [...this.dependents]) dependent.onDependencyChanged();\n }\n}\n\nclass SignalNode<T> extends ReactiveNode<T> implements Signal<T> {\n private current: T;\n private readonly equals: (previous: T, next: T) => boolean;\n\n constructor(runtime: ReactiveRuntime, initial: T, options?: SignalOptions<T>) {\n super(runtime, options?.name);\n this.current = initial;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n this.runtime.track(this);\n\n return this.current;\n }\n\n set value(next: T) {\n this.runtime.assertActive();\n\n if (this.equals(this.current, next)) return;\n\n const previous = this.current;\n\n this.current = next;\n this.runtime.emit({ kind: 'write', name: this.name, next, previous });\n this.runtime.propagate(() => this.notify());\n }\n\n peek(): T {\n return this.current;\n }\n\n update(updater: (prev: T) => T): void {\n this.value = updater(this.current);\n }\n}\n\nclass ComputedNode<T> extends ReactiveNode<T> implements ObserverNode, Owned {\n readonly dependencies = new Set<Dependency>();\n private computing = false;\n private disposed = false;\n private dirty = true;\n private current: T | typeof UNSET = UNSET;\n private readonly derive: () => T;\n private readonly equals: (previous: T, next: T) => boolean;\n\n constructor(runtime: ReactiveRuntime, derive: () => T, options?: ComputedOptions<T>) {\n super(runtime, options?.name);\n this.derive = derive;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n // Track before refresh: if refresh throws, the consumer still depends on\n // this computed and must be notified when a dependency change might let it\n // succeed. Without this, a first-run failure permanently severs the\n // consumer from the computed.\n this.runtime.track(this);\n this.refresh();\n\n return this.current as T;\n }\n\n peek(): T {\n this.refresh();\n\n return this.current as T;\n }\n\n onDependencyChanged(): void {\n if (this.disposed) return;\n\n if (!this.dirty) this.dirty = true;\n\n if (this.dependents.size > 0 && this.refresh()) this.notify();\n }\n\n dispose(): void {\n if (this.disposed) return;\n\n this.disposed = true;\n this.runtime.clearDependencies(this);\n this.dependents.clear();\n }\n\n private refresh(): boolean {\n if (!this.dirty || this.disposed) return false;\n\n if (this.computing) {\n const label = this.name === undefined ? '' : ` \"${this.name}\"`;\n\n throw new RippleComputedCycleError(`computed cycle detected${label}`);\n }\n\n this.computing = true;\n this.runtime.emit({ kind: 'compute', name: this.name });\n\n try {\n const next = this.runtime.collect(this, this.derive);\n const changed = this.current === UNSET || !this.equals(this.current as T, next);\n\n this.current = next;\n this.dirty = false;\n\n return changed;\n } finally {\n this.computing = false;\n }\n }\n}\n\nclass ScopeNode implements Scope {\n readonly disposalController = new AbortController();\n readonly owned = new Set<Owned>();\n readonly name: string | undefined;\n private isDisposed = false;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n run<T>(fn: () => T): T {\n if (this.isDisposed) throw new RippleDisposedScopeError('Cannot run a disposed scope.');\n\n return this.runtime.withScope(this, fn);\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n for (const owned of [...this.owned].reverse()) owned.dispose();\n this.owned.clear();\n this.disposalController.abort();\n this.runtime.emit({ kind: 'dispose', name: this.name, node: 'scope' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n\nclass EffectNode implements ObserverNode, EffectHandle {\n readonly dependencies = new Set<Dependency>();\n readonly disposalController = new AbortController();\n private cleanup: Cleanup | undefined;\n private isDisposed = false;\n private owner: ScopeNode | undefined;\n private scheduled = false;\n private readonly callback: () => Cleanup | undefined;\n private readonly options: EffectOptions | undefined;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, callback: () => Cleanup | undefined, options?: EffectOptions) {\n this.runtime = runtime;\n this.callback = callback;\n this.options = options;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n onDependencyChanged(): void {\n if (this.isDisposed) return;\n\n if (this.options?.scheduler === 'microtask') {\n if (this.scheduled) return;\n\n this.scheduled = true;\n queueMicrotask(() => {\n this.scheduled = false;\n\n if (!this.isDisposed) this.runtime.enqueue(this);\n });\n\n return;\n }\n\n this.runtime.enqueue(this);\n }\n\n run(): void {\n if (this.isDisposed) return;\n\n this.owner?.dispose();\n this.owner = undefined;\n this.runCleanup();\n this.runtime.emit({ kind: 'effect', name: this.options?.name });\n\n const owner = new ScopeNode(this.runtime);\n\n try {\n const cleanup = this.runtime.withEffectScope(owner, () => this.runtime.collectEffect(this, this.callback));\n\n this.owner = owner;\n this.cleanup = typeof cleanup === 'function' ? cleanup : undefined;\n } catch (error) {\n owner.dispose();\n this.runtime.report(error, { kind: 'effect', name: this.options?.name });\n }\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.owner?.dispose();\n this.owner = undefined;\n this.runtime.clearDependencies(this);\n this.runCleanup();\n this.disposalController.abort();\n this.runtime.emit({ kind: 'dispose', name: this.options?.name, node: 'effect' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n private runCleanup(): void {\n const cleanup = this.cleanup;\n\n this.cleanup = undefined;\n\n if (cleanup === undefined) return;\n\n try {\n cleanup();\n } catch (error) {\n this.runtime.report(error, { kind: 'cleanup', name: this.options?.name });\n }\n }\n}\n\n/**\n * A runtime owns reactive graph state and lifetime. Separate instances isolate\n * applications and SSR requests without process-wide mutable hooks.\n */\nexport class ReactiveRuntime {\n private activeEffectScope: ScopeNode | undefined;\n private activeObserver: ObserverNode | undefined;\n private activeScope: ScopeNode;\n private isDisposed = false;\n private flushDepth = 0;\n private flushing = false;\n private readonly pending = new Set<EffectNode>();\n private readonly listeners = new Set<() => void>();\n private readonly rootScope: ScopeNode;\n private readonly observer: ReactiveObserver | undefined;\n private readonly onError: (error: unknown, context: ReactiveErrorContext) => void;\n\n constructor(options?: RippleOptions) {\n this.observer = options?.observer;\n this.onError =\n options?.onError ??\n ((error) => {\n queueMicrotask(() => {\n throw error;\n });\n });\n this.rootScope = new ScopeNode(this, 'runtime');\n this.activeScope = this.rootScope;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.rootScope.disposalSignal;\n }\n\n readonly signal = <T>(initial: T, options?: SignalOptions<T>): Signal<T> => {\n this.assertActive();\n\n return new SignalNode(this, initial, options);\n };\n\n readonly computed = <T>(derive: () => T, options?: ComputedOptions<T>): Readable<T> => {\n this.assertActive();\n\n const node = new ComputedNode(this, derive, options);\n\n (this.activeEffectScope ?? this.activeScope).owned.add(node);\n\n return node;\n };\n\n readonly effect = (callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle => {\n this.assertActive();\n\n const node = new EffectNode(this, callback, options);\n\n (this.activeEffectScope ?? this.activeScope).owned.add(node);\n node.run();\n\n return node;\n };\n\n readonly createScope = (name?: string): Scope => {\n this.assertActive();\n\n const scope = new ScopeNode(this, name);\n\n // Scopes model explicit, caller-owned lifetimes. Unlike effects/computeds created during an\n // effect run, they deliberately attach to the enclosing scope rather than the per-run owner:\n // keyed DOM directives retain item scopes across reconciliation runs and dispose them only\n // when the item itself leaves the collection.\n this.activeScope.owned.add(scope);\n\n return scope;\n };\n\n readonly batch = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.propagate(fn);\n };\n\n readonly untrack = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.withObserver(undefined, fn);\n };\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.rootScope.dispose();\n }\n\n /** Internal node guard: disposed runtimes allow inert reads but reject graph work and mutation. */\n assertActive(): void {\n if (this.isDisposed) throw new RippleDisposedRuntimeError('Cannot use a disposed Ripple runtime.');\n }\n\n track(node: Dependency): void {\n const observer = this.activeObserver;\n\n if (observer?.collecting === undefined) return;\n\n observer.collecting.add(node);\n }\n\n clearDependencies(observer: ObserverNode): void {\n for (const dependency of observer.dependencies) dependency.dependents.delete(observer);\n observer.dependencies.clear();\n }\n\n collect<T>(observer: ObserverNode, fn: () => T): T {\n // On first run (no prior dependencies), commit partial dependencies even if\n // derive throws — otherwise the computed would have zero dependencies and never\n // be notified when its source changes, permanently stuck until a manual read.\n // On subsequent runs, keep previous dependencies (tested behavior).\n return this.collectWith(observer, fn, observer.dependencies.size === 0);\n }\n\n collectEffect<T>(observer: ObserverNode, fn: () => T): T {\n return this.collectWith(observer, fn, true);\n }\n\n withEffectScope<T>(scope: ScopeNode, fn: () => T): T {\n const previous = this.activeEffectScope;\n\n this.activeEffectScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previous;\n }\n }\n\n withObserver<T>(observer: ObserverNode | undefined, fn: () => T): T {\n const previous = this.activeObserver;\n\n this.activeObserver = observer;\n\n try {\n return fn();\n } finally {\n this.activeObserver = previous;\n }\n }\n\n withScope<T>(scope: ScopeNode, fn: () => T): T {\n const previousEffectScope = this.activeEffectScope;\n const previousScope = this.activeScope;\n\n this.activeEffectScope = undefined;\n this.activeScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previousEffectScope;\n this.activeScope = previousScope;\n }\n }\n\n enqueue(effect: EffectNode): void {\n this.pending.add(effect);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n enqueueListener(listener: () => void): void {\n this.listeners.add(listener);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n propagate<T>(fn: () => T): T {\n this.flushDepth++;\n\n try {\n return fn();\n } finally {\n this.flushDepth--;\n\n if (this.flushDepth === 0) this.flush();\n }\n }\n\n emit(event: Parameters<ReactiveObserver>[0]): void {\n try {\n this.observer?.(event);\n } catch (error) {\n this.report(error, { kind: 'observer', name: event.name });\n }\n }\n\n report(error: unknown, context: ReactiveErrorContext): void {\n try {\n this.onError(error, context);\n } catch (reporterError) {\n queueMicrotask(() => {\n throw reporterError;\n });\n }\n }\n\n private collectWith<T>(observer: ObserverNode, fn: () => T, commitOnError: boolean): T {\n const previousObserver = this.activeObserver;\n const dependencies = new Set<Dependency>();\n\n observer.collecting = dependencies;\n this.activeObserver = observer;\n\n try {\n const result = fn();\n\n this.commitDependencies(observer, dependencies);\n\n return result;\n } catch (error) {\n if (commitOnError) this.commitDependencies(observer, dependencies);\n\n throw error;\n } finally {\n observer.collecting = undefined;\n this.activeObserver = previousObserver;\n }\n }\n\n private commitDependencies(observer: ObserverNode, next: Set<Dependency>): void {\n for (const dependency of observer.dependencies) {\n if (!next.has(dependency)) dependency.dependents.delete(observer);\n }\n\n for (const dependency of next) {\n if (!observer.dependencies.has(dependency)) dependency.dependents.add(observer);\n }\n\n observer.dependencies.clear();\n for (const dependency of next) observer.dependencies.add(dependency);\n }\n\n private flush(): void {\n if (this.flushing) return;\n\n this.flushing = true;\n\n let iterations = 0;\n\n try {\n while (this.pending.size > 0 || this.listeners.size > 0) {\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n throw new RippleInfiniteLoopError(`infinite reactive flush (>${MAX_FLUSH_ITERATIONS} iterations)`);\n }\n\n const effects = [...this.pending];\n const listeners = [...this.listeners];\n\n this.pending.clear();\n this.listeners.clear();\n\n for (const effect of effects) effect.run();\n\n for (const listener of listeners) {\n try {\n listener();\n } catch (error) {\n this.report(error, { kind: 'listener' });\n }\n }\n }\n } finally {\n this.flushing = false;\n }\n }\n}\n\nexport const isReactive = <T>(value: T | Readable<T>): value is Readable<T> => {\n if (typeof value !== 'object' || value === null || !(REACTIVE in value)) return false;\n\n const candidate = value as { peek?: unknown; subscribe?: unknown };\n\n return typeof candidate.peek === 'function' && typeof candidate.subscribe === 'function';\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n RippleComputedCycleError,\n RippleDisposedRuntimeError,\n RippleDisposedScopeError,\n RippleInfiniteLoopError,\n} from './errors';\nimport type {\n Cleanup,\n ComputedOptions,\n EffectHandle,\n EffectOptions,\n Readable,\n RippleErrorContext,\n RippleErrorPolicy,\n RippleEvent,\n RippleOptions,\n Scope,\n Signal,\n SignalOptions,\n Unsubscribe,\n} from './types';\n\nexport const REACTIVE = Symbol.for('@vielzeug/ripple/reactive');\nconst MAX_FLUSH_ITERATIONS = 100;\nconst UNSET = Symbol('ripple.unset');\n\ntype Dependency = ReactiveNode<unknown>;\n\ntype ObserverNode = {\n collecting?: Set<Dependency>;\n readonly dependencies: Set<Dependency>;\n onDependencyChanged(): void;\n};\n\ntype Owned = {\n dispose(): void;\n setOwner(owner: ScopeNode | undefined): void;\n};\n\nabstract class ReactiveNode<T> {\n readonly [REACTIVE] = true;\n readonly dependents = new Set<ObserverNode>();\n readonly name: string | undefined;\n protected readonly runtime: ReactiveRuntime;\n\n protected constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n abstract peek(): T;\n abstract get value(): T;\n\n subscribe(listener: () => void): Unsubscribe {\n this.runtime.assertActive();\n this.peek();\n\n const observer: ObserverNode = {\n dependencies: new Set(),\n onDependencyChanged: () => this.runtime.enqueueListener(listener),\n };\n\n this.dependents.add(observer);\n\n return () => this.dependents.delete(observer);\n }\n\n protected notify(): void {\n for (const dependent of [...this.dependents]) dependent.onDependencyChanged();\n }\n}\n\nclass SignalNode<T> extends ReactiveNode<T> implements Signal<T> {\n private current: T;\n private readonly equals: (previous: T, next: T) => boolean;\n\n constructor(runtime: ReactiveRuntime, initial: T, options?: SignalOptions<T>) {\n super(runtime, options?.name);\n this.current = initial;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n this.runtime.track(this);\n\n return this.current;\n }\n\n set value(next: T) {\n this.runtime.assertActive();\n\n if (this.equals(this.current, next)) return;\n\n const previous = this.current;\n\n this.current = next;\n this.runtime.emit({ name: this.name, next, previous, type: 'write' });\n this.runtime.propagate(() => this.notify());\n }\n\n peek(): T {\n return this.current;\n }\n\n update(updater: (prev: T) => T): void {\n this.value = updater(this.current);\n }\n}\n\nclass ComputedNode<T> extends ReactiveNode<T> implements ObserverNode, Owned {\n readonly dependencies = new Set<Dependency>();\n private computing = false;\n private disposed = false;\n private dirty = true;\n private current: T | typeof UNSET = UNSET;\n private readonly derive: () => T;\n private readonly equals: (previous: T, next: T) => boolean;\n private owner: ScopeNode | undefined;\n\n constructor(runtime: ReactiveRuntime, derive: () => T, options?: ComputedOptions<T>) {\n super(runtime, options?.name);\n this.derive = derive;\n this.equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n // Track before refresh: if refresh throws, the consumer still depends on\n // this computed and must be notified when a dependency change might let it\n // succeed. Without this, a first-run failure permanently severs the\n // consumer from the computed.\n this.runtime.track(this);\n this.refresh();\n\n return this.current as T;\n }\n\n peek(): T {\n this.refresh();\n\n return this.current as T;\n }\n\n onDependencyChanged(): void {\n if (this.disposed) return;\n\n if (!this.dirty) this.dirty = true;\n\n if (this.dependents.size > 0) {\n try {\n if (this.refresh()) this.notify();\n } catch (error) {\n this.runtime.report(error, { kind: 'computed', name: this.name });\n }\n }\n }\n\n setOwner(owner: ScopeNode | undefined): void {\n this.owner = owner;\n }\n\n dispose(): void {\n if (this.disposed) return;\n\n this.disposed = true;\n this.owner?.release(this);\n this.owner = undefined;\n this.runtime.clearDependencies(this);\n this.dependents.clear();\n }\n\n private refresh(): boolean {\n if (!this.dirty || this.disposed) return false;\n\n if (this.computing) {\n const label = this.name === undefined ? '' : ` \"${this.name}\"`;\n\n throw new RippleComputedCycleError(`computed cycle detected${label}`);\n }\n\n this.computing = true;\n this.runtime.emit({ name: this.name, type: 'compute' });\n\n try {\n const next = this.runtime.collect(this, this.derive);\n const changed = this.current === UNSET || !this.equals(this.current as T, next);\n\n this.current = next;\n this.dirty = false;\n\n return changed;\n } finally {\n this.computing = false;\n }\n }\n}\n\nclass ScopeNode implements Scope, Owned {\n readonly disposalController = new AbortController();\n readonly owned = new Set<Owned>();\n readonly name: string | undefined;\n private isDisposed = false;\n private owner: ScopeNode | undefined;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, name?: string) {\n this.runtime = runtime;\n this.name = name;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n own(value: Owned): void {\n value.setOwner(this);\n this.owned.add(value);\n }\n\n release(value: Owned): void {\n this.owned.delete(value);\n }\n\n setOwner(owner: ScopeNode | undefined): void {\n this.owner = owner;\n }\n\n run<T>(fn: () => T): T {\n if (this.isDisposed) throw new RippleDisposedScopeError('Cannot run a disposed scope.');\n\n return this.runtime.withScope(this, fn);\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.owner?.release(this);\n this.owner = undefined;\n for (const owned of [...this.owned].reverse()) owned.dispose();\n this.owned.clear();\n this.disposalController.abort();\n this.runtime.emit({ name: this.name, node: 'scope', type: 'dispose' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n\nclass EffectNode implements ObserverNode, EffectHandle {\n readonly dependencies = new Set<Dependency>();\n readonly disposalController = new AbortController();\n private cleanup: Cleanup | undefined;\n private isDisposed = false;\n private ownershipScope: ScopeNode | undefined;\n private runScope: ScopeNode | undefined;\n private scheduled = false;\n private readonly callback: () => Cleanup | undefined;\n private readonly options: EffectOptions | undefined;\n private readonly runtime: ReactiveRuntime;\n\n constructor(runtime: ReactiveRuntime, callback: () => Cleanup | undefined, options?: EffectOptions) {\n this.runtime = runtime;\n this.callback = callback;\n this.options = options;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.disposalController.signal;\n }\n\n setOwner(owner: ScopeNode | undefined): void {\n this.ownershipScope = owner;\n }\n\n onDependencyChanged(): void {\n if (this.isDisposed) return;\n\n if (this.options?.scheduler === 'microtask') {\n if (this.scheduled) return;\n\n this.scheduled = true;\n queueMicrotask(() => {\n this.scheduled = false;\n\n if (!this.isDisposed) this.runtime.enqueue(this);\n });\n\n return;\n }\n\n this.runtime.enqueue(this);\n }\n\n run(): void {\n if (this.isDisposed) return;\n\n this.runScope?.dispose();\n this.runScope = undefined;\n this.runCleanup();\n this.runtime.emit({ name: this.options?.name, type: 'effect' });\n\n const owner = new ScopeNode(this.runtime);\n\n try {\n const cleanup = this.runtime.withEffectScope(owner, () => this.runtime.collectEffect(this, this.callback));\n\n this.runScope = owner;\n this.cleanup = typeof cleanup === 'function' ? cleanup : undefined;\n if (this.isDisposed) {\n this.runScope.dispose();\n this.runScope = undefined;\n this.runCleanup();\n }\n } catch (error) {\n owner.dispose();\n this.runtime.report(error, { kind: 'effect', name: this.options?.name });\n }\n }\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.ownershipScope?.release(this);\n this.ownershipScope = undefined;\n this.runScope?.dispose();\n this.runScope = undefined;\n this.runtime.clearDependencies(this);\n this.runCleanup();\n this.disposalController.abort();\n this.runtime.emit({ name: this.options?.name, node: 'effect', type: 'dispose' });\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n private runCleanup(): void {\n const cleanup = this.cleanup;\n\n this.cleanup = undefined;\n\n if (cleanup === undefined) return;\n\n try {\n cleanup();\n } catch (error) {\n this.runtime.report(error, { kind: 'cleanup', name: this.options?.name });\n }\n }\n}\n\n/**\n * A runtime owns reactive graph state and lifetime. Separate instances isolate\n * applications and SSR requests without process-wide mutable hooks.\n */\nexport class ReactiveRuntime {\n private activeEffectScope: ScopeNode | undefined;\n private activeObserver: ObserverNode | undefined;\n private activeScope: ScopeNode;\n private isDisposed = false;\n private flushDepth = 0;\n private flushing = false;\n private readonly pending = new Set<EffectNode>();\n private readonly listeners = new Set<() => void>();\n private readonly rootScope: ScopeNode;\n private readonly tappers = new Set<(event: RippleEvent) => void>();\n private readonly errorPolicy: RippleErrorPolicy;\n\n constructor(options?: RippleOptions) {\n this.errorPolicy = options?.errorPolicy ?? 'throw';\n this.rootScope = new ScopeNode(this, 'runtime');\n this.activeScope = this.rootScope;\n }\n\n get disposed(): boolean {\n return this.isDisposed;\n }\n\n get disposalSignal(): AbortSignal {\n return this.rootScope.disposalSignal;\n }\n\n readonly signal = <T>(initial: T, options?: SignalOptions<T>): Signal<T> => {\n this.assertActive();\n\n return new SignalNode(this, initial, options);\n };\n\n readonly computed = <T>(derive: () => T, options?: ComputedOptions<T>): Readable<T> => {\n this.assertActive();\n\n const node = new ComputedNode(this, derive, options);\n\n (this.activeEffectScope ?? this.activeScope).own(node);\n\n return node;\n };\n\n readonly effect = (callback: () => Cleanup | undefined, options?: EffectOptions): EffectHandle => {\n this.assertActive();\n\n const node = new EffectNode(this, callback, options);\n\n (this.activeEffectScope ?? this.activeScope).own(node);\n node.run();\n\n return node;\n };\n\n readonly createScope = (name?: string): Scope => {\n this.assertActive();\n\n const scope = new ScopeNode(this, name);\n\n // Scopes model explicit, caller-owned lifetimes. Unlike effects/computeds created during an\n // effect run, they deliberately attach to the enclosing scope rather than the per-run owner:\n // keyed DOM directives retain item scopes across reconciliation runs and dispose them only\n // when the item itself leaves the collection.\n this.activeScope.own(scope);\n\n return scope;\n };\n\n readonly batch = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.propagate(fn);\n };\n\n readonly untrack = <T>(fn: () => T): T => {\n this.assertActive();\n\n return this.withObserver(undefined, fn);\n };\n\n /** Runtime observability — see `Ripple.tap()`. */\n readonly tap = (handler: (event: RippleEvent) => void, options?: { signal?: AbortSignal }): Unsubscribe => {\n if (this.isDisposed) return () => {};\n\n const signal = options?.signal;\n\n if (signal?.aborted) {\n this.tappers.delete(handler);\n return () => {};\n }\n\n this.tappers.add(handler);\n\n if (signal) {\n const onAbort = () => this.tappers.delete(handler);\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n return () => {\n this.tappers.delete(handler);\n signal.removeEventListener('abort', onAbort);\n };\n }\n\n return () => this.tappers.delete(handler);\n };\n\n dispose(): void {\n if (this.isDisposed) return;\n\n this.isDisposed = true;\n this.rootScope.dispose();\n this.emit({ node: 'graph', type: 'dispose' });\n this.tappers.clear();\n }\n\n /** Internal node guard: disposed runtimes allow inert reads but reject graph work and mutation. */\n assertActive(): void {\n if (this.isDisposed) throw new RippleDisposedRuntimeError('Cannot use a disposed Ripple runtime.');\n }\n\n track(node: Dependency): void {\n const observer = this.activeObserver;\n\n if (observer?.collecting === undefined) return;\n\n observer.collecting.add(node);\n }\n\n clearDependencies(observer: ObserverNode): void {\n for (const dependency of observer.dependencies) dependency.dependents.delete(observer);\n observer.dependencies.clear();\n }\n\n collect<T>(observer: ObserverNode, fn: () => T): T {\n // On first run (no prior dependencies), commit partial dependencies even if\n // derive throws — otherwise the computed would have zero dependencies and never\n // be notified when its source changes, permanently stuck until a manual read.\n // On subsequent runs, keep previous dependencies (tested behavior).\n return this.collectWith(observer, fn, observer.dependencies.size === 0);\n }\n\n collectEffect<T>(observer: ObserverNode, fn: () => T): T {\n return this.collectWith(observer, fn, true);\n }\n\n withEffectScope<T>(scope: ScopeNode, fn: () => T): T {\n const previous = this.activeEffectScope;\n\n this.activeEffectScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previous;\n }\n }\n\n withObserver<T>(observer: ObserverNode | undefined, fn: () => T): T {\n const previous = this.activeObserver;\n\n this.activeObserver = observer;\n\n try {\n return fn();\n } finally {\n this.activeObserver = previous;\n }\n }\n\n withScope<T>(scope: ScopeNode, fn: () => T): T {\n const previousEffectScope = this.activeEffectScope;\n const previousScope = this.activeScope;\n\n this.activeEffectScope = undefined;\n this.activeScope = scope;\n\n try {\n return fn();\n } finally {\n this.activeEffectScope = previousEffectScope;\n this.activeScope = previousScope;\n }\n }\n\n enqueue(effect: EffectNode): void {\n this.pending.add(effect);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n enqueueListener(listener: () => void): void {\n this.listeners.add(listener);\n\n if (this.flushDepth === 0) this.flush();\n }\n\n propagate<T>(fn: () => T): T {\n this.flushDepth++;\n\n try {\n return fn();\n } finally {\n this.flushDepth--;\n\n if (this.flushDepth === 0) this.flush();\n }\n }\n\n emit(event: RippleEvent): void {\n if (this.tappers.size === 0) return;\n\n for (const tapper of this.tappers) {\n try {\n tapper(event);\n } catch {\n // Observability must not affect runtime behavior.\n }\n }\n }\n\n report(error: unknown, context: RippleErrorContext): void {\n this.emit({ context, error, type: 'error' });\n\n if (this.errorPolicy === 'throw') {\n queueMicrotask(() => {\n throw error;\n });\n }\n }\n\n private collectWith<T>(observer: ObserverNode, fn: () => T, commitOnError: boolean): T {\n const previousObserver = this.activeObserver;\n const dependencies = new Set<Dependency>();\n\n observer.collecting = dependencies;\n this.activeObserver = observer;\n\n try {\n const result = fn();\n\n this.commitDependencies(observer, dependencies);\n\n return result;\n } catch (error) {\n if (commitOnError) this.commitDependencies(observer, dependencies);\n\n throw error;\n } finally {\n observer.collecting = undefined;\n this.activeObserver = previousObserver;\n }\n }\n\n private commitDependencies(observer: ObserverNode, next: Set<Dependency>): void {\n for (const dependency of observer.dependencies) {\n if (!next.has(dependency)) dependency.dependents.delete(observer);\n }\n\n for (const dependency of next) {\n if (!observer.dependencies.has(dependency)) dependency.dependents.add(observer);\n }\n\n observer.dependencies.clear();\n for (const dependency of next) observer.dependencies.add(dependency);\n }\n\n private flush(): void {\n if (this.flushing) return;\n\n this.flushing = true;\n\n let iterations = 0;\n\n try {\n while (this.pending.size > 0 || this.listeners.size > 0) {\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n throw new RippleInfiniteLoopError(`infinite reactive flush (>${MAX_FLUSH_ITERATIONS} iterations)`);\n }\n\n const effects = [...this.pending];\n const listeners = [...this.listeners];\n\n this.pending.clear();\n this.listeners.clear();\n\n for (const effect of effects) effect.run();\n\n for (const listener of listeners) {\n try {\n listener();\n } catch (error) {\n this.report(error, { kind: 'listener' });\n }\n }\n }\n } finally {\n this.flushing = false;\n }\n }\n}\n\nexport const isReactive = <T>(value: T | Readable<T>): value is Readable<T> => {\n if (typeof value !== 'object' || value === null || (value as { [REACTIVE]?: unknown })[REACTIVE] !== true)\n return false;\n\n const candidate = value as { peek?: unknown; subscribe?: unknown; value?: unknown };\n\n return 'value' in candidate && typeof candidate.peek === 'function' && typeof candidate.subscribe === 'function';\n};\n"],"mappings":"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"}