aeon-dom 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/internal.ts","../src/events.ts","../src/animationFrames.ts","../../core/dist/index.js","../src/behaviors.ts"],"sourcesContent":["/**\n * Internal helpers for aeon-dom.\n *\n * At runtime, Event<A, E> IS Source<A, E> — the opaque type brand is\n * purely type-level. This mirrors the zero-cost identity cast in aeon-core.\n */\n\nimport type { Event, Source } from \"aeon-types\";\n\n/** Create an opaque Event from a Source. Zero-cost identity cast. */\nexport const createEvent = <A, E = never>(source: Source<A, E>): Event<A, E> =>\n source as unknown as Event<A, E>;\n","/**\n * DOM Event sources.\n *\n * Creates pulse Event streams from DOM EventTarget events.\n */\n\nimport type { Disposable, Event as PulseEvent, Scheduler, Sink, Source } from \"aeon-types\";\nimport { createEvent } from \"./internal.js\";\n\nclass DOMEventSource<E extends Event> implements Source<E, never> {\n declare readonly type: string;\n declare readonly target: EventTarget;\n declare readonly options: AddEventListenerOptions | undefined;\n\n constructor(type: string, target: EventTarget, options?: AddEventListenerOptions) {\n this.type = type;\n this.target = target;\n this.options = options;\n }\n\n run(sink: Sink<E, never>, scheduler: Scheduler): Disposable {\n const handler = (e: Event) => {\n sink.event(scheduler.currentTime(), e as E);\n };\n this.target.addEventListener(this.type, handler, this.options);\n return {\n dispose: () => {\n this.target.removeEventListener(this.type, handler, this.options);\n },\n };\n }\n}\n\n/**\n * Create a pulse Event from a DOM event.\n *\n * Denotation: `[(t, domEvent) | domEvent fires on target at time t]`\n *\n * Automatically removes the event listener when disposed.\n */\nexport function fromDOMEvent<K extends keyof HTMLElementEventMap>(\n type: K,\n target: HTMLElement,\n options?: AddEventListenerOptions,\n): PulseEvent<HTMLElementEventMap[K], never>;\nexport function fromDOMEvent<K extends keyof WindowEventMap>(\n type: K,\n target: Window,\n options?: AddEventListenerOptions,\n): PulseEvent<WindowEventMap[K], never>;\nexport function fromDOMEvent<K extends keyof DocumentEventMap>(\n type: K,\n target: Document,\n options?: AddEventListenerOptions,\n): PulseEvent<DocumentEventMap[K], never>;\nexport function fromDOMEvent(\n type: string,\n target: EventTarget,\n options?: AddEventListenerOptions,\n): PulseEvent<Event, never>;\nexport function fromDOMEvent(\n type: string,\n target: EventTarget,\n options?: AddEventListenerOptions,\n): PulseEvent<Event, never> {\n return createEvent(new DOMEventSource(type, target, options));\n}\n","/**\n * Animation frame Event source.\n *\n * Emits a DOMHighResTimeStamp on each requestAnimationFrame callback.\n */\n\nimport type { Disposable, Event as PulseEvent, Scheduler, Sink, Source } from \"aeon-types\";\nimport { createEvent } from \"./internal.js\";\n\nclass AnimationFrameSource implements Source<DOMHighResTimeStamp, never> {\n run(sink: Sink<DOMHighResTimeStamp, never>, scheduler: Scheduler): Disposable {\n let id = 0;\n let disposed = false;\n\n const tick = (timestamp: DOMHighResTimeStamp) => {\n if (disposed) return;\n sink.event(scheduler.currentTime(), timestamp);\n id = requestAnimationFrame(tick);\n };\n\n id = requestAnimationFrame(tick);\n\n return {\n dispose() {\n disposed = true;\n cancelAnimationFrame(id);\n },\n };\n }\n}\n\nconst ANIMATION_FRAME_SOURCE = new AnimationFrameSource();\n\n/**\n * An Event that emits a DOMHighResTimeStamp on each animation frame.\n *\n * Denotation: `[(t, timestamp) | each requestAnimationFrame callback]`\n *\n * Cancels the animation frame loop when disposed.\n */\nexport const animationFrames: PulseEvent<DOMHighResTimeStamp, never> =\n createEvent(ANIMATION_FRAME_SOURCE);\n","/** A no-op disposable. */ const disposeNone = {\n dispose () {}\n};\n/** Dispose all disposables in an array. */ const disposeAll = (disposables)=>({\n dispose () {\n for(let i = disposables.length - 1; i >= 0; i--){\n disposables[i].dispose();\n }\n }\n });\n/** A settable disposable — allows replacing the inner disposable. */ class SettableDisposable {\n constructor(){\n this.inner = undefined;\n this.disposed = false;\n }\n set(d) {\n if (this.disposed) {\n d.dispose();\n } else {\n this.inner = d;\n }\n }\n dispose() {\n if (!this.disposed) {\n this.disposed = true;\n if (this.inner !== undefined) {\n this.inner.dispose();\n }\n }\n }\n}\n\n/**\n * Internal Event representation.\n *\n * At runtime, an Event<A, E> IS the Source<A, E> object — no wrapper,\n * no Symbol-keyed indirection. The type-level brand (EventBrand) keeps\n * them distinct in TypeScript's type system while _createEvent and\n * _getSource compile to identity casts with zero runtime cost.\n *\n * This matches @most/core's approach where Stream = Source at runtime.\n */ /** Type guard: does this source support sync iteration? */ const isSyncSource = (source)=>source._sync === true;\n/** Create an opaque Event from a Source. Zero-cost identity cast. */ const _createEvent = (source)=>source;\n/** Extract the Source from an opaque Event. Zero-cost identity cast. */ const _getSource = (event)=>event;\n\n// --- Source classes for V8 hidden class stability ---\nlet EmptySource = class EmptySource {\n constructor(){\n this._sync = true;\n }\n run(sink, scheduler) {\n sink.end(scheduler.currentTime());\n return disposeNone;\n }\n syncIterate(_emit) {}\n};\nlet NeverSource = class NeverSource {\n run() {\n return disposeNone;\n }\n};\nlet NowSource = class NowSource {\n constructor(value){\n this.value = value;\n this._sync = true;\n }\n run(sink, scheduler) {\n const t = scheduler.currentTime();\n sink.event(t, this.value);\n sink.end(t);\n return disposeNone;\n }\n syncIterate(emit) {\n emit(this.value);\n }\n};\nlet ArraySource = class ArraySource {\n constructor(values){\n this.values = values;\n this._sync = true;\n }\n run(sink, scheduler) {\n const t = scheduler.currentTime();\n const values = this.values;\n for(let i = 0; i < values.length; i++){\n sink.event(t, values[i]);\n }\n sink.end(t);\n return disposeNone;\n }\n syncIterate(emit) {\n const values = this.values;\n for(let i = 0; i < values.length; i++){\n if (!emit(values[i])) return;\n }\n }\n};\n// --- Singletons for empty/never ---\nconst EMPTY_SOURCE = new EmptySource();\nconst NEVER_SOURCE = new NeverSource();\n// --- Public API ---\n/**\n * An Event that ends immediately without emitting any values.\n *\n * Denotation: `[]` — the empty sequence.\n */ const empty = ()=>_createEvent(EMPTY_SOURCE);\n/**\n * An Event that never emits and never ends.\n *\n * Denotation: `_|_` — bottom / divergent.\n */ const never = ()=>_createEvent(NEVER_SOURCE);\n/**\n * An Event that emits a single value at time 0, then ends.\n *\n * Denotation: `[(0, value)]`\n */ const now = (value)=>_createEvent(new NowSource(value));\nlet AtSource = class AtSource {\n constructor(time, value){\n this.time = time;\n this.value = value;\n }\n run(sink, scheduler) {\n const val = this.value;\n const delay = this.time - scheduler.currentTime();\n return scheduler.scheduleTask(delay, {\n run (t) {\n sink.event(t, val);\n sink.end(t);\n },\n error (t, err) {\n sink.error(t, err);\n },\n dispose () {}\n });\n }\n};\n/**\n * An Event that emits a single value at a specific time, then ends.\n *\n * Denotation: `[(time, value)]`\n */ const at = (time, value)=>_createEvent(new AtSource(time, value));\n/**\n * An Event that emits all values from an array synchronously, then ends.\n *\n * Denotation: `[(t, values[0]), (t, values[1]), ...]` all at the same time.\n */ const fromArray = (values)=>_createEvent(new ArraySource(values));\nlet PeriodicSource = class PeriodicSource {\n constructor(period){\n this.period = period;\n }\n run(sink, scheduler) {\n const period = this.period;\n let disposed = false;\n const task = {\n run (t) {\n if (!disposed) {\n sink.event(t, undefined);\n scheduler.scheduleTask(period, task);\n }\n },\n error (t, err) {\n sink.error(t, err);\n },\n dispose () {\n disposed = true;\n }\n };\n const st = scheduler.scheduleTask(period, task);\n return {\n dispose () {\n disposed = true;\n st.dispose();\n }\n };\n }\n};\n/**\n * An Event that emits undefined at regular intervals.\n *\n * Denotation: `[(period, undefined), (2*period, undefined), ...]`\n */ const periodic = (period)=>_createEvent(new PeriodicSource(period));\nlet RangeSource = class RangeSource {\n constructor(start, count){\n this.start = start;\n this.count = count;\n this._sync = true;\n }\n run(sink, scheduler) {\n const t = scheduler.currentTime();\n const end = this.start + this.count;\n for(let i = this.start; i < end; i++){\n sink.event(t, i);\n }\n sink.end(t);\n return disposeNone;\n }\n syncIterate(emit) {\n const end = this.start + this.count;\n for(let i = this.start; i < end; i++){\n if (!emit(i)) return;\n }\n }\n};\n/**\n * An Event that emits a sequence of numbers synchronously, then ends.\n *\n * Denotation: `[(t, start), (t, start+1), ..., (t, start+count-1)]`\n */ const range = (start, count)=>_createEvent(new RangeSource(start, Math.max(0, count)));\nlet IterableSource = class IterableSource {\n constructor(iterable){\n this.iterable = iterable;\n this._sync = true;\n }\n run(sink, scheduler) {\n const t = scheduler.currentTime();\n for (const value of this.iterable){\n sink.event(t, value);\n }\n sink.end(t);\n return disposeNone;\n }\n syncIterate(emit) {\n for (const value of this.iterable){\n if (!emit(value)) return;\n }\n }\n};\n/**\n * Create an Event from an iterable, emitting all values synchronously.\n *\n * Denotation: `[(t, v) for v in iterable]` all at the same time.\n */ const fromIterable = (iterable)=>_createEvent(new IterableSource(iterable));\n\n/**\n * Pipe base class for sinks that forward error/end unchanged.\n *\n * With ES2022 target, `extends Pipe` compiles to native `class extends` —\n * zero helpers, zero overhead. V8 devirtualizes the shared error/end\n * methods across all sink subtypes.\n */ class Pipe {\n constructor(sink){\n this.sink = sink;\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.sink.end(time);\n }\n}\n\n// --- Sink classes ---\n/** Map sink: applies f to each value. */ let MapSink = class MapSink extends Pipe {\n constructor(f, sink){\n super(sink);\n this.f = f;\n }\n event(time, value) {\n const f = this.f;\n this.sink.event(time, f(value));\n }\n};\n/** Filter sink: only forwards values that pass the predicate. */ let FilterSink = class FilterSink extends Pipe {\n constructor(predicate, sink){\n super(sink);\n this.predicate = predicate;\n }\n event(time, value) {\n const p = this.predicate;\n if (p(value)) {\n this.sink.event(time, value);\n }\n }\n};\n/** Combined filter+map sink: filter then map in one node. */ let FilterMapSink = class FilterMapSink extends Pipe {\n constructor(predicate, f, sink){\n super(sink);\n this.predicate = predicate;\n this.f = f;\n }\n event(time, value) {\n const p = this.predicate;\n if (p(value)) {\n const f = this.f;\n this.sink.event(time, f(value));\n }\n }\n};\n/** Combined map+filter sink: map then filter in one node. */ let MapFilterSink = class MapFilterSink extends Pipe {\n constructor(f, predicate, sink){\n super(sink);\n this.f = f;\n this.predicate = predicate;\n }\n event(time, value) {\n const f = this.f;\n const mapped = f(value);\n const p = this.predicate;\n if (p(mapped)) {\n this.sink.event(time, mapped);\n }\n }\n};\n// --- Source classes (for instanceof fusion detection) ---\n/** A map source, tagged for fusion detection via instanceof. */ let MapSource = class MapSource {\n constructor(f, source){\n this.f = f;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new MapSink(this.f, sink), scheduler);\n }\n /** Factory with fusion and algebraic simplification. */ static create(f, source) {\n // map(f, empty()) → empty()\n if (source instanceof EmptySource) {\n return EMPTY_SOURCE;\n }\n // map(f, now(x)) → now(f(x)) — constant folding\n if (source instanceof NowSource) {\n return new NowSource(f(source.value));\n }\n // map(f, map(g, s)) → map(f∘g, s)\n if (source instanceof MapSource) {\n const inner = source;\n return new MapSource((x)=>f(inner.f(x)), inner.source);\n }\n // map(f, filter(p, s)) → filterMap(p, f, s)\n if (source instanceof FilterSource) {\n const inner = source;\n return new FilterMapSource(inner.predicate, f, inner.source);\n }\n return new MapSource(f, source);\n }\n};\n/** A filter source, tagged for fusion detection via instanceof. */ let FilterSource = class FilterSource {\n constructor(predicate, source){\n this.predicate = predicate;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new FilterSink(this.predicate, sink), scheduler);\n }\n /** Factory with fusion and algebraic simplification. */ static create(predicate, source) {\n // filter(p, empty()) → empty()\n if (source instanceof EmptySource) {\n return EMPTY_SOURCE;\n }\n // filter(p, now(x)) → p(x) ? now(x) : empty() — constant folding\n if (source instanceof NowSource) {\n const val = source.value;\n return predicate(val) ? source : EMPTY_SOURCE;\n }\n // filter(p, filter(q, s)) → filter(x => q(x) && p(x), s)\n if (source instanceof FilterSource) {\n const inner = source;\n return new FilterSource((x)=>inner.predicate(x) && predicate(x), inner.source);\n }\n // filter(p, map(f, s)) → mapFilter(f, p, s)\n if (source instanceof MapSource) {\n const inner = source;\n return new MapFilterSource(inner.f, predicate, inner.source);\n }\n return new FilterSource(predicate, source);\n }\n};\n/** Fused filter-then-map source. */ let FilterMapSource = class FilterMapSource {\n constructor(predicate, f, source){\n this.predicate = predicate;\n this.f = f;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new FilterMapSink(this.predicate, this.f, sink), scheduler);\n }\n};\n/** Fused map-then-filter source. */ let MapFilterSource = class MapFilterSource {\n constructor(f, predicate, source){\n this.f = f;\n this.predicate = predicate;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new MapFilterSink(this.f, this.predicate, sink), scheduler);\n }\n};\n// --- Public API ---\n/**\n * Create a fusible map Event. Detects map∘map and composes functions.\n */ const fusedMap = (f, event)=>{\n const source = _getSource(event);\n return _createEvent(MapSource.create(f, source));\n};\n/**\n * Create a fusible filter Event. Detects filter∘filter and conjoins predicates.\n */ const fusedFilter = (predicate, event)=>{\n const source = _getSource(event);\n return _createEvent(FilterSource.create(predicate, source));\n};\n\n/**\n * Transform each value in an Event stream.\n *\n * Denotation: `map(f, e) = [(t, f(v)) | (t, v) ∈ e]`\n */ const map$1 = (f, event)=>fusedMap(f, event);\n\n/**\n * Keep only values that satisfy the predicate.\n *\n * Denotation: `filter(p, e) = [(t, v) | (t, v) ∈ e, p(v)]`\n */ const filter$1 = (predicate, event)=>fusedFilter(predicate, event);\n\nlet TapSink = class TapSink extends Pipe {\n constructor(f, sink){\n super(sink);\n this.f = f;\n }\n event(time, value) {\n const f = this.f;\n f(value);\n this.sink.event(time, value);\n }\n};\nlet TapSource = class TapSource {\n constructor(f, source){\n this.f = f;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new TapSink(this.f, sink), scheduler);\n }\n};\n/**\n * Run a side-effect for each event value, passing values through unchanged.\n */ const tap$1 = (f, event)=>_createEvent(new TapSource(f, _getSource(event)));\n\n/**\n * Replace every value in the stream with a constant.\n *\n * Denotation: `constant(b, e) = map(_ => b, e)`\n */ const constant$1 = (value, event)=>map$1(()=>value, event);\n\nlet ScanSink = class ScanSink extends Pipe {\n constructor(f, seed, sink){\n super(sink);\n this.f = f;\n this.acc = seed;\n }\n event(time, value) {\n const f = this.f;\n const acc = f(this.acc, value);\n this.acc = acc;\n this.sink.event(time, acc);\n }\n};\nlet ScanSource = class ScanSource {\n constructor(f, seed, source){\n this.f = f;\n this.seed = seed;\n this.source = source;\n this._sync = source._sync === true;\n }\n run(sink, scheduler) {\n return this.source.run(new ScanSink(this.f, this.seed, sink), scheduler);\n }\n syncIterate(emit) {\n const f = this.f;\n let acc = this.seed;\n this.source.syncIterate((v)=>{\n acc = f(acc, v);\n return emit(acc);\n });\n }\n};\n/**\n * Incrementally accumulate values, emitting each intermediate result.\n *\n * Denotation: produces a running fold of the event sequence.\n */ const scan$1 = (f, seed, event)=>{\n const source = _getSource(event);\n // scan(f, seed, empty()) → empty()\n if (source instanceof EmptySource) {\n return _createEvent(EMPTY_SOURCE);\n }\n // scan(f, seed, map(g, s)) → scan((acc, x) => f(acc, g(x)), seed, s)\n if (source instanceof MapSource) {\n const inner = source;\n const g = inner.f;\n return _createEvent(new ScanSource((acc, x)=>f(acc, g(x)), seed, inner.source));\n }\n return _createEvent(new ScanSource(f, seed, source));\n};\n\n// --- Sink classes for V8 monomorphism ---\nlet ReduceSink = class ReduceSink {\n constructor(f, seed, resolve, reject){\n this.f = f;\n this.acc = seed;\n this.resolve = resolve;\n this.reject = reject;\n }\n event(_time, value) {\n const f = this.f;\n this.acc = f(this.acc, value);\n }\n error(_time, err) {\n this.reject(err);\n }\n end(_time) {\n this.resolve(this.acc);\n }\n};\nlet ObserveSink = class ObserveSink {\n constructor(f, resolve, reject){\n this.f = f;\n this.resolve = resolve;\n this.reject = reject;\n }\n event(_time, value) {\n const f = this.f;\n f(value);\n }\n error(_time, err) {\n this.reject(err);\n }\n end(_time) {\n this.resolve();\n }\n};\nlet DrainSink = class DrainSink {\n constructor(resolve, reject){\n this.resolve = resolve;\n this.reject = reject;\n }\n event() {}\n error(_time, err) {\n this.reject(err);\n }\n end(_time) {\n this.resolve();\n }\n};\n// --- Public API ---\n/**\n * Fold all values into a single result. Activates the stream.\n *\n * Denotation: `reduce(f, seed, e) = foldl f seed (map snd e)`\n *\n * Uses sync loop compilation when the source chain is fully synchronous,\n * bypassing the Sink protocol for a tight for-loop.\n */ const reduce$1 = (f, seed, event, scheduler)=>{\n const source = _getSource(event);\n if (isSyncSource(source)) {\n try {\n let acc = seed;\n source.syncIterate((value)=>{\n acc = f(acc, value);\n return true;\n });\n return Promise.resolve(acc);\n } catch (err) {\n return Promise.reject(err);\n }\n }\n return new Promise((resolve, reject)=>{\n source.run(new ReduceSink(f, seed, resolve, reject), scheduler);\n });\n};\n/**\n * Run a side-effect for each value. Activates the stream.\n *\n * Denotation: executes the effect for each `(t, v)` in the event sequence.\n */ const observe$1 = (f, event, scheduler)=>{\n const source = _getSource(event);\n if (isSyncSource(source)) {\n try {\n source.syncIterate((value)=>{\n f(value);\n return true;\n });\n return Promise.resolve();\n } catch (err) {\n return Promise.reject(err);\n }\n }\n return new Promise((resolve, reject)=>{\n source.run(new ObserveSink(f, resolve, reject), scheduler);\n });\n};\n/**\n * Activate the stream, discarding all values. Returns when the stream ends.\n *\n * Denotation: activates the event sequence purely for its effects.\n */ const drain$1 = (event, scheduler)=>{\n const source = _getSource(event);\n if (isSyncSource(source)) {\n try {\n source.syncIterate(()=>true);\n return Promise.resolve();\n } catch (err) {\n return Promise.reject(err);\n }\n }\n return new Promise((resolve, reject)=>{\n source.run(new DrainSink(resolve, reject), scheduler);\n });\n};\n\n// --- take ---\nlet TakeSink = class TakeSink extends Pipe {\n constructor(n, sink, disposable){\n super(sink);\n this.remaining = n;\n this.disposable = disposable;\n }\n event(time, value) {\n if (this.remaining <= 0) return;\n this.remaining--;\n this.sink.event(time, value);\n if (this.remaining === 0) {\n this.disposable.dispose();\n this.sink.end(time);\n }\n }\n};\nlet TakeSource = class TakeSource {\n constructor(n, source){\n this.n = n;\n this.source = source;\n this._sync = source._sync === true;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n sd.set(this.source.run(new TakeSink(this.n, sink, sd), scheduler));\n return sd;\n }\n syncIterate(emit) {\n let remaining = this.n;\n this.source.syncIterate((v)=>{\n if (remaining <= 0) return false;\n remaining--;\n return emit(v) && remaining > 0;\n });\n }\n};\nlet EmptySliceSource = class EmptySliceSource {\n constructor(){\n this._sync = true;\n }\n run(sink, scheduler) {\n sink.end(scheduler.currentTime());\n return disposeNone;\n }\n syncIterate(_emit) {}\n};\nconst EMPTY_SLICE = new EmptySliceSource();\n/** Take the first n values from the stream, then end. */ const take$1 = (n, event)=>{\n if (n <= 0) {\n return _createEvent(EMPTY_SLICE);\n }\n const source = _getSource(event);\n // take(n, empty()) → empty()\n if (source instanceof EmptySource) {\n return _createEvent(EMPTY_SOURCE);\n }\n // take(n, take(m, s)) → take(min(n, m), s)\n if (source instanceof TakeSource) {\n return _createEvent(new TakeSource(Math.min(n, source.n), source.source));\n }\n return _createEvent(new TakeSource(n, source));\n};\n// --- drop ---\nlet DropSink = class DropSink extends Pipe {\n constructor(n, sink){\n super(sink);\n this.remaining = n;\n }\n event(time, value) {\n if (this.remaining > 0) {\n this.remaining--;\n } else {\n this.sink.event(time, value);\n }\n }\n};\nlet DropSource = class DropSource {\n constructor(n, source){\n this.n = n;\n this.source = source;\n this._sync = source._sync === true;\n }\n run(sink, scheduler) {\n return this.source.run(new DropSink(this.n, sink), scheduler);\n }\n syncIterate(emit) {\n let remaining = this.n;\n this.source.syncIterate((v)=>{\n if (remaining > 0) {\n remaining--;\n return true;\n }\n return emit(v);\n });\n }\n};\n/** Drop the first n values, then pass through the rest. */ const drop$1 = (n, event)=>{\n if (n <= 0) return event;\n const source = _getSource(event);\n // drop(n, empty()) → empty()\n if (source instanceof EmptySource) {\n return _createEvent(EMPTY_SOURCE);\n }\n // drop(n, drop(m, s)) → drop(n + m, s)\n if (source instanceof DropSource) {\n return _createEvent(new DropSource(n + source.n, source.source));\n }\n return _createEvent(new DropSource(n, source));\n};\n// --- takeWhile ---\nlet TakeWhileSink = class TakeWhileSink extends Pipe {\n constructor(predicate, sink, disposable){\n super(sink);\n this.predicate = predicate;\n this.disposable = disposable;\n this.active = true;\n }\n event(time, value) {\n if (!this.active) return;\n const p = this.predicate;\n if (p(value)) {\n this.sink.event(time, value);\n } else {\n this.active = false;\n this.disposable.dispose();\n this.sink.end(time);\n }\n }\n};\nlet TakeWhileSource = class TakeWhileSource {\n constructor(predicate, source){\n this.predicate = predicate;\n this.source = source;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n sd.set(this.source.run(new TakeWhileSink(this.predicate, sink, sd), scheduler));\n return sd;\n }\n};\n/** Take values while the predicate holds, then end. */ const takeWhile$1 = (predicate, event)=>_createEvent(new TakeWhileSource(predicate, _getSource(event)));\n// --- dropWhile ---\nlet DropWhileSink = class DropWhileSink extends Pipe {\n constructor(predicate, sink){\n super(sink);\n this.predicate = predicate;\n this.skipping = true;\n }\n event(time, value) {\n if (this.skipping) {\n const p = this.predicate;\n if (p(value)) return;\n this.skipping = false;\n }\n this.sink.event(time, value);\n }\n};\nlet DropWhileSource = class DropWhileSource {\n constructor(predicate, source){\n this.predicate = predicate;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new DropWhileSink(this.predicate, sink), scheduler);\n }\n};\n/** Drop values while the predicate holds, then pass through the rest. */ const dropWhile$1 = (predicate, event)=>_createEvent(new DropWhileSource(predicate, _getSource(event)));\n// --- slice ---\n/**\n * Take a contiguous slice: drop `start` values, then take `end - start`.\n *\n * Denotation: `slice(s, e, stream) = take(e - s, drop(s, stream))`\n */ const slice$1 = (start, end, event)=>take$1(end - start, drop$1(start, event));\n// --- until ---\nlet UntilSink = class UntilSink extends Pipe {\n constructor(sink, disposable){\n super(sink);\n this.disposable = disposable;\n this.active = true;\n }\n event(time, value) {\n if (this.active) {\n this.sink.event(time, value);\n }\n }\n};\nlet UntilSignalSink = class UntilSignalSink {\n constructor(mainSink, disposable){\n this.mainSink = mainSink;\n this.disposable = disposable;\n }\n event(time, _value) {\n if (this.mainSink.active) {\n this.mainSink.active = false;\n this.disposable.dispose();\n this.mainSink.sink.end(time);\n }\n }\n error(time, err) {\n this.mainSink.sink.error(time, err);\n }\n end(_time) {\n // Signal ending without firing means: keep going until main ends naturally\n }\n};\nlet UntilSource = class UntilSource {\n constructor(signal, source){\n this.signal = signal;\n this.source = source;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n const mainSink = new UntilSink(sink, sd);\n const signalDisposable = this.signal.run(new UntilSignalSink(mainSink, sd), scheduler);\n const mainDisposable = this.source.run(mainSink, scheduler);\n sd.set(disposeAll([\n mainDisposable,\n signalDisposable\n ]));\n return sd;\n }\n};\n/**\n * Take values from the event until the signal fires, then end.\n *\n * Denotation: `until(signal, e) = [(t, v) | (t, v) ∈ e, t < t_signal]`\n * where `t_signal` is the time of the first occurrence in `signal`.\n */ const until$1 = (signal, event)=>_createEvent(new UntilSource(_getSource(signal), _getSource(event)));\n// --- since ---\nlet SinceSink = class SinceSink extends Pipe {\n constructor(sink){\n super(sink);\n this.open = false;\n }\n event(time, value) {\n if (this.open) {\n this.sink.event(time, value);\n }\n }\n};\nlet SinceSignalSink = class SinceSignalSink {\n constructor(mainSink){\n this.mainSink = mainSink;\n }\n event(_time, _value) {\n this.mainSink.open = true;\n }\n error(time, err) {\n this.mainSink.sink.error(time, err);\n }\n end(_time) {\n // Signal ending without firing means: never open\n }\n};\nlet SinceSource = class SinceSource {\n constructor(signal, source){\n this.signal = signal;\n this.source = source;\n }\n run(sink, scheduler) {\n const mainSink = new SinceSink(sink);\n const signalDisposable = this.signal.run(new SinceSignalSink(mainSink), scheduler);\n const mainDisposable = this.source.run(mainSink, scheduler);\n return disposeAll([\n mainDisposable,\n signalDisposable\n ]);\n }\n};\n/**\n * Drop values from the event until the signal fires, then pass through the rest.\n *\n * Denotation: `since(signal, e) = [(t, v) | (t, v) ∈ e, t >= t_signal]`\n * where `t_signal` is the time of the first occurrence in `signal`.\n */ const since$1 = (signal, event)=>_createEvent(new SinceSource(_getSource(signal), _getSource(event)));\n\nlet MergeSink = class MergeSink {\n constructor(sink, count){\n this.sink = sink;\n this.remaining = count;\n }\n event(time, value) {\n this.sink.event(time, value);\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.remaining--;\n if (this.remaining === 0) {\n this.sink.end(time);\n }\n }\n};\nlet MergeSource = class MergeSource {\n constructor(sources){\n this.sources = sources;\n let sync = true;\n for(let i = 0; i < sources.length; i++){\n if (sources[i]._sync !== true) {\n sync = false;\n break;\n }\n }\n this._sync = sync;\n }\n run(sink, scheduler) {\n const sources = this.sources;\n const mergeSink = new MergeSink(sink, sources.length);\n const disposables = new Array(sources.length);\n for(let i = 0; i < sources.length; i++){\n disposables[i] = sources[i].run(mergeSink, scheduler);\n }\n return disposeAll(disposables);\n }\n syncIterate(emit) {\n const sources = this.sources;\n let active = true;\n const wrappedEmit = (v)=>{\n active = emit(v);\n return active;\n };\n for(let i = 0; i < sources.length && active; i++){\n sources[i].syncIterate(wrappedEmit);\n }\n }\n};\nlet EmptyMergeSource = class EmptyMergeSource {\n constructor(){\n this._sync = true;\n }\n run(sink, scheduler) {\n sink.end(scheduler.currentTime());\n return disposeNone;\n }\n syncIterate(_emit) {}\n};\nconst EMPTY_MERGE = new EmptyMergeSource();\n/**\n * Merge multiple Event streams into one, interleaving values by time.\n * Ends when all input streams have ended.\n *\n * Flattens nested merges: merge(a, merge(b, c)) → merge(a, b, c)\n */ const merge = (...events)=>{\n if (events.length === 0) {\n return _createEvent(EMPTY_MERGE);\n }\n if (events.length === 1) return events[0];\n // Flatten nested merges and collect sources\n const sources = [];\n for(let i = 0; i < events.length; i++){\n const source = _getSource(events[i]);\n if (source instanceof MergeSource) {\n // Flatten: merge(a, merge(b, c)) → merge(a, b, c)\n const inner = source.sources;\n for(let j = 0; j < inner.length; j++){\n sources.push(inner[j]);\n }\n } else {\n sources.push(source);\n }\n }\n if (sources.length === 1) {\n return _createEvent(sources[0]);\n }\n return _createEvent(new MergeSource(sources));\n};\n\n// --- combine ---\nlet CombineState = class CombineState {\n constructor(f, sink){\n this.latestA = undefined;\n this.latestB = undefined;\n this.hasA = false;\n this.hasB = false;\n this.endCount = 0;\n this.sink = sink;\n this.f = f;\n }\n emit(time) {\n if (this.hasA && this.hasB) {\n const f = this.f;\n this.sink.event(time, f(this.latestA, this.latestB));\n }\n }\n tryEnd(time) {\n this.endCount++;\n if (this.endCount === 2) this.sink.end(time);\n }\n};\nlet CombineSinkA = class CombineSinkA {\n constructor(state){\n this.state = state;\n }\n event(time, value) {\n this.state.latestA = value;\n this.state.hasA = true;\n this.state.emit(time);\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(time) {\n this.state.tryEnd(time);\n }\n};\nlet CombineSinkB = class CombineSinkB {\n constructor(state){\n this.state = state;\n }\n event(time, value) {\n this.state.latestB = value;\n this.state.hasB = true;\n this.state.emit(time);\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(time) {\n this.state.tryEnd(time);\n }\n};\nlet CombineSource = class CombineSource {\n constructor(f, sourceA, sourceB){\n this.f = f;\n this.sourceA = sourceA;\n this.sourceB = sourceB;\n }\n run(sink, scheduler) {\n const state = new CombineState(this.f, sink);\n return disposeAll([\n this.sourceA.run(new CombineSinkA(state), scheduler),\n this.sourceB.run(new CombineSinkB(state), scheduler)\n ]);\n }\n};\n/**\n * Combine two event streams using a function, emitting whenever either source emits.\n *\n * Denotation: emits f(latestA, latestB) at each time where either A or B fires,\n * once both have produced at least one value.\n */ const combine = (f, ea, eb)=>_createEvent(new CombineSource(f, _getSource(ea), _getSource(eb)));\n// --- zip ---\nlet ZipState = class ZipState {\n constructor(sink){\n this.bufferA = [];\n this.bufferB = [];\n this.endCount = 0;\n this.sink = sink;\n }\n tryEmit(time) {\n const bufA = this.bufferA;\n const bufB = this.bufferB;\n while(bufA.length > 0 && bufB.length > 0){\n this.sink.event(time, [\n bufA.shift(),\n bufB.shift()\n ]);\n }\n }\n tryEnd(time) {\n this.endCount++;\n if (this.endCount === 2) {\n this.sink.end(time);\n }\n }\n};\nlet ZipSinkA = class ZipSinkA {\n constructor(state){\n this.state = state;\n }\n event(time, value) {\n this.state.bufferA.push(value);\n this.state.tryEmit(time);\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(time) {\n this.state.tryEnd(time);\n }\n};\nlet ZipSinkB = class ZipSinkB {\n constructor(state){\n this.state = state;\n }\n event(time, value) {\n this.state.bufferB.push(value);\n this.state.tryEmit(time);\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(time) {\n this.state.tryEnd(time);\n }\n};\nlet ZipSource = class ZipSource {\n constructor(sourceA, sourceB){\n this.sourceA = sourceA;\n this.sourceB = sourceB;\n }\n run(sink, scheduler) {\n const state = new ZipState(sink);\n return disposeAll([\n this.sourceA.run(new ZipSinkA(state), scheduler),\n this.sourceB.run(new ZipSinkB(state), scheduler)\n ]);\n }\n};\n/**\n * Zip two event streams pairwise.\n *\n * Denotation: `zip(ea, eb) = [(t, [a, b]) | (ta, a) ∈ ea, (tb, b) ∈ eb]`\n * where pairs are consumed in order, t = max(ta, tb).\n */ const zip = (ea, eb)=>_createEvent(new ZipSource(_getSource(ea), _getSource(eb)));\n\nlet SwitchInnerSink = class SwitchInnerSink {\n constructor(outer){\n this.outer = outer;\n }\n event(time, value) {\n this.outer.sink.event(time, value);\n }\n error(time, err) {\n this.outer.sink.error(time, err);\n }\n end(time) {\n this.outer.innerEnded = true;\n if (this.outer.outerEnded) {\n this.outer.sink.end(time);\n }\n }\n};\nlet SwitchSink = class SwitchSink {\n constructor(sink, scheduler, outerDisposable){\n this.sink = sink;\n this.scheduler = scheduler;\n this.outerDisposable = outerDisposable;\n this.innerDisposable = undefined;\n this.outerEnded = false;\n this.innerEnded = true;\n }\n event(_time, innerEvent) {\n if (this.innerDisposable !== undefined) {\n this.innerDisposable.dispose();\n }\n this.innerEnded = false;\n this.innerDisposable = _getSource(innerEvent).run(new SwitchInnerSink(this), this.scheduler);\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.outerEnded = true;\n if (this.innerEnded) {\n this.sink.end(time);\n }\n }\n};\nlet SwitchSource = class SwitchSource {\n constructor(source){\n this.source = source;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n const switchSink = new SwitchSink(sink, scheduler, sd);\n sd.set(this.source.run(switchSink, scheduler));\n return {\n dispose () {\n sd.dispose();\n if (switchSink.innerDisposable !== undefined) {\n switchSink.innerDisposable.dispose();\n }\n }\n };\n }\n};\n/**\n * Switch to the latest inner Event, disposing the previous.\n *\n * Denotation: flatten an Event<Event<A, E>, E> by always following\n * the most recently emitted inner event.\n */ const switchLatest$1 = (event)=>_createEvent(new SwitchSource(_getSource(event)));\n\nlet MergeMapInnerSink = class MergeMapInnerSink {\n constructor(state){\n this.state = state;\n }\n event(time, value) {\n if (!this.state.disposed) this.state.sink.event(time, value);\n }\n error(time, err) {\n if (!this.state.disposed) this.state.sink.error(time, err);\n }\n end(time) {\n this.state.active--;\n if (this.state.buffer.length > 0) {\n this.state.tryStart();\n } else if (this.state.outerEnded && this.state.active === 0) {\n this.state.sink.end(time);\n }\n }\n};\nlet MergeMapOuterSink = class MergeMapOuterSink {\n constructor(state){\n this.state = state;\n }\n event(_time, value) {\n this.state.buffer.push(value);\n this.state.tryStart();\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(time) {\n this.state.outerEnded = true;\n if (this.state.active === 0 && this.state.buffer.length === 0) {\n this.state.sink.end(time);\n }\n }\n};\nlet MergeMapState = class MergeMapState {\n constructor(f, concurrency, sink, scheduler){\n this.f = f;\n this.concurrency = concurrency;\n this.sink = sink;\n this.scheduler = scheduler;\n this.buffer = [];\n this.innerDisposables = [];\n this.active = 0;\n this.outerEnded = false;\n this.disposed = false;\n }\n tryStart() {\n while(this.active < this.concurrency && this.buffer.length > 0){\n const value = this.buffer.shift();\n this.active++;\n const innerSource = _getSource(this.f(value));\n this.innerDisposables.push(innerSource.run(new MergeMapInnerSink(this), this.scheduler));\n }\n }\n};\nlet MergeMapSource = class MergeMapSource {\n constructor(f, concurrency, source){\n this.f = f;\n this.concurrency = concurrency;\n this.source = source;\n }\n run(sink, scheduler) {\n const state = new MergeMapState(this.f, this.concurrency, sink, scheduler);\n const outerDisposable = this.source.run(new MergeMapOuterSink(state), scheduler);\n return {\n dispose () {\n state.disposed = true;\n outerDisposable.dispose();\n for (const d of state.innerDisposables){\n d.dispose();\n }\n }\n };\n }\n};\n/**\n * Map each value to an Event and merge the results with bounded concurrency.\n *\n * Denotation: `mergeMap(f, c, e) = merge(map(f, e))` with\n * at most `c` inner streams active at any time. Values from finished\n * inner streams are replaced by newly spawned ones from the buffer.\n */ const mergeMap$1 = (f, concurrency, event)=>_createEvent(new MergeMapSource(f, concurrency, _getSource(event)));\n\n// --- catchError ---\nlet CatchSink = class CatchSink {\n constructor(handler, sink, scheduler, disposable){\n this.handler = handler;\n this.sink = sink;\n this.scheduler = scheduler;\n this.disposable = disposable;\n }\n event(time, value) {\n this.sink.event(time, value);\n }\n error(_time, err) {\n const handler = this.handler;\n const recovery = handler(err);\n this.disposable.set(_getSource(recovery).run(this.sink, this.scheduler));\n }\n end(time) {\n this.sink.end(time);\n }\n};\nlet CatchSource = class CatchSource {\n constructor(handler, source){\n this.handler = handler;\n this.source = source;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n sd.set(this.source.run(new CatchSink(this.handler, sink, scheduler, sd), scheduler));\n return sd;\n }\n};\n/**\n * Recover from errors by switching to a new Event stream.\n * The error type CHANGES from E1 to E2.\n *\n * Denotation: if the stream errors with `e`, continue with `handler(e)`.\n */ const catchError$1 = (handler, event)=>_createEvent(new CatchSource(handler, _getSource(event)));\n// --- mapError ---\nlet MapErrorSink = class MapErrorSink {\n constructor(f, sink){\n this.f = f;\n this.sink = sink;\n }\n event(time, value) {\n this.sink.event(time, value);\n }\n error(time, err) {\n const f = this.f;\n this.sink.error(time, f(err));\n }\n end(time) {\n this.sink.end(time);\n }\n};\nlet MapErrorSource = class MapErrorSource {\n constructor(f, source){\n this.f = f;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new MapErrorSink(this.f, sink), scheduler);\n }\n};\n/**\n * Transform the error value without changing the stream structure.\n *\n * Denotation: `mapError(f, e)` — the error, if any, is replaced by `f(err)`.\n */ const mapError$1 = (f, event)=>_createEvent(new MapErrorSource(f, _getSource(event)));\n// --- throwError ---\nlet ThrowErrorSource = class ThrowErrorSource {\n constructor(err){\n this.err = err;\n }\n run(sink, scheduler) {\n sink.error(scheduler.currentTime(), this.err);\n return disposeNone;\n }\n};\n/**\n * An Event that immediately errors with the given value.\n *\n * Denotation: `Error(err)` — a failed event sequence.\n */ const throwError = (err)=>_createEvent(new ThrowErrorSource(err));\n\nlet ChainInnerSink = class ChainInnerSink {\n constructor(outer){\n this.outer = outer;\n }\n event(time, value) {\n this.outer.sink.event(time, value);\n }\n error(time, err) {\n this.outer.sink.error(time, err);\n }\n end(time) {\n this.outer.innerActive = false;\n if (this.outer.queue.length > 0) {\n this.outer.startInner(this.outer.queue.shift());\n } else if (this.outer.outerEnded) {\n this.outer.sink.end(time);\n }\n }\n};\nlet ChainSink = class ChainSink {\n constructor(f, sink, scheduler, outerDisposable){\n this.f = f;\n this.sink = sink;\n this.scheduler = scheduler;\n this.outerDisposable = outerDisposable;\n this.innerDisposable = undefined;\n this.outerEnded = false;\n this.queue = [];\n this.innerActive = false;\n }\n event(_time, value) {\n const f = this.f;\n const inner = f(value);\n if (this.innerActive) {\n this.queue.push(inner);\n } else {\n this.startInner(inner);\n }\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.outerEnded = true;\n if (!this.innerActive) {\n this.sink.end(time);\n }\n }\n startInner(inner) {\n this.innerActive = true;\n if (this.innerDisposable !== undefined) {\n this.innerDisposable.dispose();\n }\n this.innerDisposable = _getSource(inner).run(new ChainInnerSink(this), this.scheduler);\n }\n};\nlet ChainSource = class ChainSource {\n constructor(f, source){\n this.f = f;\n this.source = source;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n const chainSink = new ChainSink(this.f, sink, scheduler, sd);\n sd.set(this.source.run(chainSink, scheduler));\n return {\n dispose () {\n sd.dispose();\n if (chainSink.innerDisposable !== undefined) {\n chainSink.innerDisposable.dispose();\n }\n }\n };\n }\n};\n/**\n * Sequentially flatMap: for each value, create an inner Event and\n * concatenate the results.\n *\n * Denotation: `chain(f, e) = concat [f(v) | (t, v) ∈ e]`\n */ const chain$1 = (f, event)=>_createEvent(new ChainSource(f, _getSource(event)));\n\n// --- debounce ---\nlet DebounceSink = class DebounceSink {\n constructor(duration, sink, scheduler){\n this.duration = duration;\n this.sink = sink;\n this.scheduler = scheduler;\n this.pending = undefined;\n this.latestValue = undefined;\n this.hasValue = false;\n }\n event(_time, value) {\n this.latestValue = value;\n this.hasValue = true;\n if (this.pending !== undefined) {\n this.pending.dispose();\n }\n this.pending = this.scheduler.scheduleTask(this.duration, {\n run: (t)=>{\n if (this.hasValue) {\n this.hasValue = false;\n this.sink.event(t, this.latestValue);\n }\n },\n error: (t, err)=>{\n this.sink.error(t, err);\n },\n dispose: ()=>{}\n });\n }\n error(time, err) {\n this.clearPending();\n this.sink.error(time, err);\n }\n end(time) {\n this.clearPending();\n if (this.hasValue) {\n this.sink.event(time, this.latestValue);\n }\n this.sink.end(time);\n }\n clearPending() {\n if (this.pending !== undefined) {\n this.pending.dispose();\n this.pending = undefined;\n }\n }\n};\nlet DebounceSource = class DebounceSource {\n constructor(duration, source){\n this.duration = duration;\n this.source = source;\n }\n run(sink, scheduler) {\n const debounceSink = new DebounceSink(this.duration, sink, scheduler);\n const d = this.source.run(debounceSink, scheduler);\n return {\n dispose () {\n debounceSink.clearPending();\n d.dispose();\n }\n };\n }\n};\n/**\n * Wait for a quiet period before emitting the latest value.\n * Each new value resets the timer.\n *\n * Denotation: emits the last value in each burst, after `duration` of silence.\n */ const debounce$1 = (duration, event)=>_createEvent(new DebounceSource(duration, _getSource(event)));\n// --- throttle ---\nlet ThrottleSink = class ThrottleSink extends Pipe {\n constructor(duration, sink, scheduler){\n super(sink);\n this.duration = duration;\n this.scheduler = scheduler;\n this.lastEmitTime = Number.NEGATIVE_INFINITY;\n }\n event(time, value) {\n const now = time;\n if (now - this.lastEmitTime >= this.duration) {\n this.lastEmitTime = now;\n this.sink.event(time, value);\n }\n }\n};\nlet ThrottleSource = class ThrottleSource {\n constructor(duration, source){\n this.duration = duration;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new ThrottleSink(this.duration, sink, scheduler), scheduler);\n }\n};\n/**\n * Emit at most one value per duration window.\n * Takes the first value in each window, ignores the rest.\n *\n * Denotation: rate-limits the event sequence.\n */ const throttle$1 = (duration, event)=>_createEvent(new ThrottleSource(duration, _getSource(event)));\n// --- delay ---\nlet DelaySink = class DelaySink {\n constructor(duration, sink, scheduler){\n this.duration = duration;\n this.sink = sink;\n this.scheduler = scheduler;\n this.pendingTasks = [];\n }\n event(_time, value) {\n const st = this.scheduler.scheduleTask(this.duration, {\n run: (t)=>{\n this.sink.event(t, value);\n },\n error: (t, err)=>{\n this.sink.error(t, err);\n },\n dispose: ()=>{}\n });\n this.pendingTasks.push(st);\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(_time) {\n const st = this.scheduler.scheduleTask(this.duration, {\n run: (t)=>{\n this.sink.end(t);\n },\n error: ()=>{},\n dispose: ()=>{}\n });\n this.pendingTasks.push(st);\n }\n};\nlet DelaySource = class DelaySource {\n constructor(duration, source){\n this.duration = duration;\n this.source = source;\n }\n run(sink, scheduler) {\n const delaySink = new DelaySink(this.duration, sink, scheduler);\n const d = this.source.run(delaySink, scheduler);\n return {\n dispose () {\n for (const st of delaySink.pendingTasks){\n st.dispose();\n }\n d.dispose();\n }\n };\n }\n};\n/**\n * Delay each event by a fixed duration.\n *\n * Denotation: `delay(d, e) = [(t + d, v) | (t, v) ∈ e]`\n */ const delay$1 = (duration, event)=>_createEvent(new DelaySource(duration, _getSource(event)));\n// --- bufferCount ---\nlet BufferCountSink = class BufferCountSink {\n constructor(count, sink){\n this.count = count;\n this.sink = sink;\n this.buffer = [];\n }\n event(time, value) {\n this.buffer.push(value);\n if (this.buffer.length >= this.count) {\n const batch = this.buffer;\n this.buffer = [];\n this.sink.event(time, batch);\n }\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n if (this.buffer.length > 0) {\n this.sink.event(time, this.buffer);\n this.buffer = [];\n }\n this.sink.end(time);\n }\n};\nlet BufferCountSource = class BufferCountSource {\n constructor(count, source){\n this.count = count;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new BufferCountSink(this.count, sink), scheduler);\n }\n};\n/**\n * Buffer values into arrays of a fixed size.\n * Emits when the buffer reaches `count`. Flushes remaining on end.\n */ const bufferCount$1 = (count, event)=>_createEvent(new BufferCountSource(count, _getSource(event)));\n// --- bufferTime ---\nlet BufferTimeSink = class BufferTimeSink {\n constructor(sink){\n this.sink = sink;\n this.buffer = [];\n this.ended = false;\n }\n event(_time, value) {\n this.buffer.push(value);\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.ended = true;\n if (this.buffer.length > 0) {\n this.sink.event(time, this.buffer);\n this.buffer = [];\n }\n this.sink.end(time);\n }\n};\nlet BufferTimeSource = class BufferTimeSource {\n constructor(duration, source){\n this.duration = duration;\n this.source = source;\n }\n run(sink, scheduler) {\n const btSink = new BufferTimeSink(sink);\n const flush = ()=>{\n if (btSink.buffer.length > 0) {\n const batch = btSink.buffer;\n btSink.buffer = [];\n sink.event(scheduler.currentTime(), batch);\n }\n if (!btSink.ended) {\n scheduler.scheduleTask(this.duration, {\n run: ()=>flush(),\n error: ()=>{},\n dispose: ()=>{}\n });\n }\n };\n scheduler.scheduleTask(this.duration, {\n run: ()=>flush(),\n error: ()=>{},\n dispose: ()=>{}\n });\n return this.source.run(btSink, scheduler);\n }\n};\n/**\n * Buffer values over a time window.\n * Emits the buffer contents at the end of each window.\n */ const bufferTime$1 = (duration, event)=>_createEvent(new BufferTimeSource(duration, _getSource(event)));\n\nlet TraverseState = class TraverseState {\n constructor(f, concurrency, sink, time){\n this.f = f;\n this.concurrency = concurrency;\n this.sink = sink;\n this.buffer = [];\n this.active = 0;\n this.outerEnded = false;\n this.disposed = false;\n this.lastTime = time;\n }\n tryDrain() {\n while(this.active < this.concurrency && this.buffer.length > 0){\n const { time, value } = this.buffer.shift();\n this.startOne(time, value);\n }\n }\n startOne(time, value) {\n this.active++;\n const f = this.f;\n f(value).then((result)=>{\n if (this.disposed) return;\n this.sink.event(time, result);\n this.active--;\n if (this.buffer.length > 0) {\n this.tryDrain();\n } else if (this.outerEnded && this.active === 0) {\n this.sink.end(this.lastTime);\n }\n }, (err)=>{\n if (this.disposed) return;\n this.sink.error(time, err);\n });\n }\n};\nlet TraverseSink = class TraverseSink {\n constructor(state){\n this.state = state;\n }\n event(time, value) {\n this.state.lastTime = time;\n if (this.state.active < this.state.concurrency) {\n this.state.startOne(time, value);\n } else {\n this.state.buffer.push({\n time,\n value\n });\n }\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(time) {\n this.state.lastTime = time;\n this.state.outerEnded = true;\n if (this.state.active === 0 && this.state.buffer.length === 0) {\n this.state.sink.end(time);\n }\n }\n};\nlet TraverseSource = class TraverseSource {\n constructor(f, concurrency, source){\n this.f = f;\n this.concurrency = concurrency;\n this.source = source;\n }\n run(sink, scheduler) {\n const state = new TraverseState(this.f, this.concurrency, sink, scheduler.currentTime());\n const outerDisposable = this.source.run(new TraverseSink(state), scheduler);\n return {\n dispose () {\n state.disposed = true;\n outerDisposable.dispose();\n }\n };\n }\n};\n/**\n * Apply an async function to each event value with bounded concurrency.\n *\n * Denotation: `traverse(f, c, e) = [(t, await f(v)) | (t, v) ∈ e]`\n * with at most `c` pending promises at any time. When all slots are\n * occupied, incoming values are buffered until a slot frees up.\n *\n * Results are emitted as promises resolve, so output order may differ\n * from input order when concurrency > 1.\n */ const traverse$1 = (f, concurrency, event)=>_createEvent(new TraverseSource(f, concurrency, _getSource(event)));\n\nlet FromPromiseSource = class FromPromiseSource {\n constructor(promise){\n this.promise = promise;\n }\n run(sink, scheduler) {\n let disposed = false;\n this.promise.then((value)=>{\n if (!disposed) {\n const t = scheduler.currentTime();\n sink.event(t, value);\n sink.end(t);\n }\n }, (err)=>{\n if (!disposed) {\n sink.error(scheduler.currentTime(), err);\n }\n });\n return {\n dispose () {\n disposed = true;\n }\n };\n }\n};\n/**\n * Create an Event from a Promise.\n *\n * The event emits the resolved value at the time the promise settles,\n * then ends. If the promise rejects, the event errors.\n *\n * Denotation: `[(t_resolve, value)]` or `Error(rejection)`\n */ const fromPromise = (promise)=>_createEvent(new FromPromiseSource(promise));\n\nlet RetrySink = class RetrySink {\n constructor(sink, source, scheduler, disposable, maxRetries, delayDuration){\n this.sink = sink;\n this.source = source;\n this.scheduler = scheduler;\n this.disposable = disposable;\n this.maxRetries = maxRetries;\n this.delayDuration = delayDuration;\n this.attempt = 0;\n }\n event(time, value) {\n this.sink.event(time, value);\n }\n error(time, err) {\n this.attempt++;\n if (this.attempt > this.maxRetries) {\n this.sink.error(time, err);\n return;\n }\n if (this.delayDuration !== undefined) {\n const self = this;\n const st = this.scheduler.scheduleTask(this.delayDuration, {\n run () {\n self.disposable.set(self.source.run(self, self.scheduler));\n },\n error (t, e) {\n self.sink.error(t, e);\n },\n dispose () {}\n });\n this.disposable.set(st);\n } else {\n this.disposable.set(this.source.run(this, this.scheduler));\n }\n }\n end(time) {\n this.sink.end(time);\n }\n};\nlet RetrySource = class RetrySource {\n constructor(source, maxRetries, delayDuration){\n this.source = source;\n this.maxRetries = maxRetries;\n this.delayDuration = delayDuration;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n const retrySink = new RetrySink(sink, this.source, scheduler, sd, this.maxRetries, this.delayDuration);\n sd.set(this.source.run(retrySink, scheduler));\n return sd;\n }\n};\n/**\n * Retry a failing event stream up to `maxRetries` times.\n *\n * On error, re-subscribes to the source. If `delay` is provided,\n * waits that duration before each retry. If all retries are exhausted,\n * the error propagates downstream.\n */ const retry$1 = (maxRetries, event, delay)=>_createEvent(new RetrySource(_getSource(event), maxRetries, delay));\n\nlet ReplayState = class ReplayState {\n constructor(bufferSize){\n this.sinks = new Set();\n this.buffer = [];\n this.bufferSize = bufferSize;\n this.sourceDisposable = undefined;\n this.ended = false;\n this.endTime = undefined;\n this.errored = false;\n this.errorTime = undefined;\n this.errorValue = undefined;\n }\n push(time, value) {\n this.buffer.push({\n time,\n value\n });\n if (this.buffer.length > this.bufferSize) {\n this.buffer.shift();\n }\n }\n};\nlet ShareSource = class ShareSource {\n constructor(source, bufferSize){\n this.source = source;\n this.state = new ReplayState(bufferSize);\n }\n run(sink, scheduler) {\n const state = this.state;\n // Replay buffered values to new subscriber\n for(let i = 0; i < state.buffer.length; i++){\n const entry = state.buffer[i];\n sink.event(entry.time, entry.value);\n }\n // If source already errored, propagate immediately\n if (state.errored) {\n sink.error(state.errorTime, state.errorValue);\n return {\n dispose () {}\n };\n }\n // If source already ended, end immediately\n if (state.ended) {\n sink.end(state.endTime);\n return {\n dispose () {}\n };\n }\n state.sinks.add(sink);\n if (state.sinks.size === 1) {\n // First subscriber — connect to source\n state.sourceDisposable = this.source.run({\n event (time, value) {\n state.push(time, value);\n for (const s of state.sinks){\n s.event(time, value);\n }\n },\n error (time, err) {\n state.errored = true;\n state.errorTime = time;\n state.errorValue = err;\n for (const s of state.sinks){\n s.error(time, err);\n }\n },\n end (time) {\n state.ended = true;\n state.endTime = time;\n for (const s of state.sinks){\n s.end(time);\n }\n }\n }, scheduler);\n }\n return {\n dispose () {\n state.sinks.delete(sink);\n if (state.sinks.size === 0 && state.sourceDisposable !== undefined) {\n state.sourceDisposable.dispose();\n state.sourceDisposable = undefined;\n // Reset state so source can be re-subscribed\n state.ended = false;\n state.endTime = undefined;\n state.errored = false;\n state.errorTime = undefined;\n state.errorValue = undefined;\n state.buffer.length = 0;\n }\n }\n };\n }\n};\n/**\n * Share a single subscription with replay for late subscribers.\n *\n * Buffers the last `bufferSize` values and replays them to new subscribers.\n * Like `multicast`, the source is subscribed lazily and disposed when\n * the last subscriber leaves.\n *\n * - `share(1, event)` — replay latest value (like RxJS `shareReplay(1)`)\n * - `share(0, event)` — equivalent to `multicast` (no replay)\n */ const share$1 = (bufferSize, event)=>_createEvent(new ShareSource(_getSource(event), bufferSize));\n\nlet AttachState = class AttachState {\n constructor(f, sink){\n this.latestA = undefined;\n this.hasA = false;\n this.sink = sink;\n this.f = f;\n }\n};\nlet AttachSampledSink = class AttachSampledSink {\n constructor(state){\n this.state = state;\n }\n event(_time, value) {\n this.state.latestA = value;\n this.state.hasA = true;\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(_time) {\n // sampled ending doesn't end the output — sampler controls timing\n }\n};\nlet AttachSamplerSink = class AttachSamplerSink {\n constructor(state){\n this.state = state;\n }\n event(time, value) {\n if (this.state.hasA) {\n const f = this.state.f;\n this.state.sink.event(time, f(this.state.latestA, value));\n }\n }\n error(time, err) {\n this.state.sink.error(time, err);\n }\n end(time) {\n this.state.sink.end(time);\n }\n};\nlet AttachSource = class AttachSource {\n constructor(f, sampled, sampler){\n this.f = f;\n this.sampled = sampled;\n this.sampler = sampler;\n }\n run(sink, scheduler) {\n const state = new AttachState(this.f, sink);\n return disposeAll([\n this.sampled.run(new AttachSampledSink(state), scheduler),\n this.sampler.run(new AttachSamplerSink(state), scheduler)\n ]);\n }\n};\n/**\n * Combine the latest value from one stream with each emission of another.\n *\n * Emits `f(latestA, b)` each time `sampler` fires, using the most recent\n * value from `sampled`. Only emits after `sampled` has produced at least one value.\n *\n * The output ends when `sampler` ends. Errors from either source propagate.\n */ const attach$1 = (f, sampled, sampler)=>_createEvent(new AttachSource(f, _getSource(sampled), _getSource(sampler)));\n\nlet DedupeSink = class DedupeSink extends Pipe {\n constructor(eq, sink){\n super(sink);\n this.eq = eq;\n this.prev = UNSET$3;\n }\n event(time, value) {\n if (this.prev === UNSET$3 || !this.eq(this.prev, value)) {\n this.prev = value;\n this.sink.event(time, value);\n }\n }\n};\nconst UNSET$3 = Symbol(\"unset\");\nlet DedupeSource = class DedupeSource {\n constructor(eq, source){\n this.eq = eq;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new DedupeSink(this.eq, sink), scheduler);\n }\n};\nconst defaultEq = (a, b)=>a === b;\n/**\n * Suppress consecutive duplicate values.\n *\n * Denotation: emits a value only when it differs from the previous\n * emission, according to the provided equality function (defaults to `===`).\n */ const dedupe$1 = (event, eq = defaultEq)=>_createEvent(new DedupeSource(eq, _getSource(event)));\n\nlet ConsSource = class ConsSource {\n constructor(value, source){\n this.value = value;\n this.source = source;\n }\n run(sink, scheduler) {\n sink.event(scheduler.currentTime(), this.value);\n return this.source.run(sink, scheduler);\n }\n};\n/**\n * Prepend an initial value before the first event.\n *\n * Denotation: `cons(value, e) = [(t₀, value)] ++ e`\n */ const cons$1 = (value, event)=>_createEvent(new ConsSource(value, _getSource(event)));\n\n// --- first ---\nlet FirstSink = class FirstSink extends Pipe {\n constructor(predicate, sink, disposable){\n super(sink);\n this.predicate = predicate;\n this.disposable = disposable;\n this.found = false;\n }\n event(time, value) {\n if (this.found) return;\n if (this.predicate !== undefined && !this.predicate(value)) return;\n this.found = true;\n this.sink.event(time, value);\n this.disposable.dispose();\n this.sink.end(time);\n }\n end(time) {\n if (!this.found) {\n this.sink.end(time);\n }\n }\n};\nlet FirstSource = class FirstSource {\n constructor(predicate, source){\n this.predicate = predicate;\n this.source = source;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n sd.set(this.source.run(new FirstSink(this.predicate, sink, sd), scheduler));\n return sd;\n }\n};\n/**\n * Emit only the first value, then end.\n * With a predicate: emit the first value matching the predicate.\n *\n * Denotation: `first(e) = take(1, e)`\n * `first(p, e) = take(1, filter(p, e))`\n */ const first$1 = (event, predicate)=>_createEvent(new FirstSource(predicate, _getSource(event)));\n// --- last ---\nlet LastSink = class LastSink extends Pipe {\n constructor(predicate, sink){\n super(sink);\n this.predicate = predicate;\n this.latest = UNSET$2;\n }\n event(_time, value) {\n if (this.predicate !== undefined && !this.predicate(value)) return;\n this.latest = value;\n }\n end(time) {\n if (this.latest !== UNSET$2) {\n this.sink.event(time, this.latest);\n }\n this.sink.end(time);\n }\n};\nconst UNSET$2 = Symbol(\"unset\");\nlet LastSource = class LastSource {\n constructor(predicate, source){\n this.predicate = predicate;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new LastSink(this.predicate, sink), scheduler);\n }\n};\n/**\n * Emit only the final value when the stream ends.\n * With a predicate: emit the last value matching the predicate.\n *\n * Denotation: `last(e) = let vs = values(e) in [vs[|vs|-1]]`\n */ const last$1 = (event, predicate)=>_createEvent(new LastSource(predicate, _getSource(event)));\n\nlet PairwiseSink = class PairwiseSink {\n constructor(sink){\n this.sink = sink;\n this.prev = UNSET$1;\n }\n event(time, value) {\n if (this.prev !== UNSET$1) {\n this.sink.event(time, [\n this.prev,\n value\n ]);\n }\n this.prev = value;\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.sink.end(time);\n }\n};\nconst UNSET$1 = Symbol(\"unset\");\nlet PairwiseSource = class PairwiseSource {\n constructor(source){\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new PairwiseSink(sink), scheduler);\n }\n};\n/**\n * Emit [previous, current] pairs, starting from the second event.\n *\n * Denotation: `pairwise(e) = [(tₙ, [vₙ₋₁, vₙ]) | n >= 2]`\n */ const pairwise$1 = (event)=>_createEvent(new PairwiseSource(_getSource(event)));\n\nlet TimeoutError = class TimeoutError extends Error {\n constructor(duration){\n super(`Timeout: no event within ${duration}ms`);\n this.name = \"TimeoutError\";\n }\n};\nlet TimeoutSink = class TimeoutSink {\n constructor(duration, sink, scheduler){\n this.duration = duration;\n this.sink = sink;\n this.scheduler = scheduler;\n this.active = true;\n this.pending = undefined;\n this.scheduleTimeout();\n }\n event(time, value) {\n if (!this.active) return;\n this.clearPending();\n this.sink.event(time, value);\n this.scheduleTimeout();\n }\n error(time, err) {\n if (!this.active) return;\n this.active = false;\n this.clearPending();\n this.sink.error(time, err);\n }\n end(time) {\n if (!this.active) return;\n this.active = false;\n this.clearPending();\n this.sink.end(time);\n }\n scheduleTimeout() {\n this.pending = this.scheduler.scheduleTask(this.duration, {\n run: (t)=>{\n if (this.active) {\n this.active = false;\n this.sink.error(t, new TimeoutError(this.duration));\n }\n },\n error: ()=>{},\n dispose: ()=>{}\n });\n }\n clearPending() {\n if (this.pending !== undefined) {\n this.pending.dispose();\n this.pending = undefined;\n }\n }\n};\nlet TimeoutSource = class TimeoutSource {\n constructor(duration, source){\n this.duration = duration;\n this.source = source;\n }\n run(sink, scheduler) {\n const timeoutSink = new TimeoutSink(this.duration, sink, scheduler);\n const d = this.source.run(timeoutSink, scheduler);\n return {\n dispose () {\n timeoutSink.active = false;\n timeoutSink.clearPending();\n d.dispose();\n }\n };\n }\n};\n/**\n * Error if no event is emitted within `duration`.\n * The timer starts immediately and resets after each event.\n *\n * Emits a TimeoutError via the error channel.\n */ const timeout$1 = (duration, event)=>_createEvent(new TimeoutSource(duration, _getSource(event)));\n\nlet ExhaustMapInnerSink = class ExhaustMapInnerSink {\n constructor(outer){\n this.outer = outer;\n }\n event(time, value) {\n this.outer.sink.event(time, value);\n }\n error(time, err) {\n this.outer.sink.error(time, err);\n }\n end(time) {\n this.outer.innerActive = false;\n this.outer.innerDisposable = undefined;\n if (this.outer.outerEnded) {\n this.outer.sink.end(time);\n }\n }\n};\nlet ExhaustMapSink = class ExhaustMapSink {\n constructor(f, sink, scheduler){\n this.f = f;\n this.sink = sink;\n this.scheduler = scheduler;\n this.innerActive = false;\n this.innerDisposable = undefined;\n this.outerEnded = false;\n }\n event(_time, value) {\n if (this.innerActive) return; // Ignore while inner is active\n this.innerActive = true;\n const f = this.f;\n const inner = f(value);\n this.innerDisposable = _getSource(inner).run(new ExhaustMapInnerSink(this), this.scheduler);\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.outerEnded = true;\n if (!this.innerActive) {\n this.sink.end(time);\n }\n }\n};\nlet ExhaustMapSource = class ExhaustMapSource {\n constructor(f, source){\n this.f = f;\n this.source = source;\n }\n run(sink, scheduler) {\n const exhaustSink = new ExhaustMapSink(this.f, sink, scheduler);\n const d = this.source.run(exhaustSink, scheduler);\n return {\n dispose () {\n if (exhaustSink.innerDisposable !== undefined) {\n exhaustSink.innerDisposable.dispose();\n }\n d.dispose();\n }\n };\n }\n};\n/**\n * Map each outer value to an inner Event, ignoring new outer values\n * while the current inner is still active.\n *\n * Denotation: projects outer values to inner streams, but drops\n * projections that arrive while an inner stream is running.\n */ const exhaustMap$1 = (f, event)=>_createEvent(new ExhaustMapSource(f, _getSource(event)));\n\nconst UNSET = Symbol(\"unset\");\nlet ForkJoinSink = class ForkJoinSink {\n constructor(sink, index, state){\n this.sink = sink;\n this.index = index;\n this.state = state;\n }\n event(_time, value) {\n this.state.latestValues[this.index] = value;\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.state.remaining--;\n if (this.state.remaining === 0) {\n // Check all have emitted at least once\n const values = this.state.latestValues;\n for(let i = 0; i < values.length; i++){\n if (values[i] === UNSET) {\n this.sink.end(time);\n return;\n }\n }\n this.sink.event(time, values);\n this.sink.end(time);\n }\n }\n};\nlet ForkJoinState = class ForkJoinState {\n constructor(count){\n this.latestValues = new Array(count).fill(UNSET);\n this.remaining = count;\n }\n};\nlet ForkJoinSource = class ForkJoinSource {\n constructor(sources){\n this.sources = sources;\n }\n run(sink, scheduler) {\n const count = this.sources.length;\n if (count === 0) {\n sink.end(scheduler.currentTime());\n return {\n dispose () {}\n };\n }\n const state = new ForkJoinState(count);\n const disposables = [];\n for(let i = 0; i < count; i++){\n disposables.push(this.sources[i].run(new ForkJoinSink(sink, i, state), scheduler));\n }\n return disposeAll(disposables);\n }\n};\n/**\n * Wait for all streams to complete, then emit an array of their final values.\n * If any stream completes without emitting, the result completes empty.\n */ const forkJoin = (...events)=>_createEvent(new ForkJoinSource(events.map(_getSource)));\n\nlet OrElseSink = class OrElseSink extends Pipe {\n constructor(defaultValue, sink){\n super(sink);\n this.defaultValue = defaultValue;\n this.hasValue = false;\n }\n event(time, value) {\n this.hasValue = true;\n this.sink.event(time, value);\n }\n end(time) {\n if (!this.hasValue) {\n this.sink.event(time, this.defaultValue);\n }\n this.sink.end(time);\n }\n};\nlet OrElseSource = class OrElseSource {\n constructor(defaultValue, source){\n this.defaultValue = defaultValue;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new OrElseSink(this.defaultValue, sink), scheduler);\n }\n};\n/**\n * Emit a default value if the stream completes without producing any values.\n *\n * Denotation: `orElse(d, e) = isEmpty(e) ? [(t_end, d)] : e`\n */ const orElse$1 = (defaultValue, event)=>_createEvent(new OrElseSource(defaultValue, _getSource(event)));\n\nlet EnsureSink = class EnsureSink extends Pipe {\n constructor(cleanup, sink){\n super(sink);\n this.cleanup = cleanup;\n this.called = false;\n }\n event(time, value) {\n this.sink.event(time, value);\n }\n error(time, err) {\n this.runCleanup();\n this.sink.error(time, err);\n }\n end(time) {\n this.runCleanup();\n this.sink.end(time);\n }\n runCleanup() {\n if (!this.called) {\n this.called = true;\n this.cleanup();\n }\n }\n};\nlet EnsureSource = class EnsureSource {\n constructor(cleanup, source){\n this.cleanup = cleanup;\n this.source = source;\n }\n run(sink, scheduler) {\n const ensureSink = new EnsureSink(this.cleanup, sink);\n const d = this.source.run(ensureSink, scheduler);\n return {\n dispose () {\n ensureSink.runCleanup();\n d.dispose();\n }\n };\n }\n};\n/**\n * Run a cleanup function when the stream ends, errors, or is disposed.\n * The cleanup runs exactly once regardless of which termination path fires.\n */ const ensure$1 = (cleanup, event)=>_createEvent(new EnsureSource(cleanup, _getSource(event)));\n\nlet RaceSink = class RaceSink {\n constructor(sink, index, state){\n this.sink = sink;\n this.index = index;\n this.state = state;\n }\n event(time, value) {\n if (this.state.winner === -1) {\n this.state.winner = this.index;\n // Dispose all losers\n for(let i = 0; i < this.state.disposables.length; i++){\n if (i !== this.index) {\n this.state.disposables[i]?.dispose();\n }\n }\n }\n if (this.state.winner === this.index) {\n this.sink.event(time, value);\n }\n }\n error(time, err) {\n if (this.state.winner === -1 || this.state.winner === this.index) {\n this.sink.error(time, err);\n }\n }\n end(time) {\n if (this.state.winner === this.index) {\n this.sink.end(time);\n } else if (this.state.winner === -1) {\n // A source ended without emitting — count it out\n this.state.endedCount++;\n if (this.state.endedCount === this.state.disposables.length) {\n this.sink.end(time);\n }\n }\n }\n};\nlet RaceState = class RaceState {\n constructor(count){\n this.winner = -1;\n this.endedCount = 0;\n this.disposables = new Array(count).fill(undefined);\n }\n};\nlet RaceSource = class RaceSource {\n constructor(sources){\n this.sources = sources;\n }\n run(sink, scheduler) {\n const count = this.sources.length;\n if (count === 0) {\n sink.end(scheduler.currentTime());\n return {\n dispose () {}\n };\n }\n const state = new RaceState(count);\n for(let i = 0; i < count; i++){\n state.disposables[i] = this.sources[i].run(new RaceSink(sink, i, state), scheduler);\n }\n return {\n dispose () {\n for (const d of state.disposables){\n d?.dispose();\n }\n }\n };\n }\n};\n/**\n * Race multiple streams: the first to emit wins, others are disposed.\n * Subsequent events come only from the winner.\n */ const race = (...events)=>_createEvent(new RaceSource(events.map(_getSource)));\n\n// --- count ---\nlet CountSink = class CountSink {\n constructor(sink){\n this.sink = sink;\n this.n = 0;\n }\n event(_time, _value) {\n this.n++;\n }\n error(time, err) {\n this.sink.error(time, err);\n }\n end(time) {\n this.sink.event(time, this.n);\n this.sink.end(time);\n }\n};\nlet CountSource = class CountSource {\n constructor(source){\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new CountSink(sink), scheduler);\n }\n};\n/**\n * Emit the total number of values when the stream ends.\n *\n * Denotation: `count(e) = [(t_end, |e|)]`\n */ const count$1 = (event)=>_createEvent(new CountSource(_getSource(event)));\n// --- all ---\nlet AllSink = class AllSink extends Pipe {\n constructor(predicate, sink){\n super(sink);\n this.predicate = predicate;\n this.result = true;\n }\n event(time, value) {\n if (!this.result) return;\n if (!this.predicate(value)) {\n this.result = false;\n this.sink.event(time, false);\n this.sink.end(time);\n }\n }\n end(time) {\n if (this.result) {\n this.sink.event(time, true);\n }\n this.sink.end(time);\n }\n};\nlet AllSource = class AllSource {\n constructor(predicate, source){\n this.predicate = predicate;\n this.source = source;\n }\n run(sink, scheduler) {\n return this.source.run(new AllSink(this.predicate, sink), scheduler);\n }\n};\n/**\n * Emit `true` when the stream ends if all values matched the predicate,\n * or `false` as soon as one fails.\n *\n * Denotation: `all(p, e) = [(t, ∀v ∈ e. p(v))]`\n */ const all$1 = (predicate, event)=>_createEvent(new AllSource(predicate, _getSource(event)));\n// --- elementAt ---\nlet ElementAtSink = class ElementAtSink extends Pipe {\n constructor(n, sink, disposable){\n super(sink);\n this.n = n;\n this.disposable = disposable;\n this.index = 0;\n this.found = false;\n }\n event(time, value) {\n if (this.found) return;\n if (this.index === this.n) {\n this.found = true;\n this.sink.event(time, value);\n this.disposable.dispose();\n this.sink.end(time);\n }\n this.index++;\n }\n end(time) {\n if (!this.found) {\n this.sink.end(time);\n }\n }\n};\nlet ElementAtSource = class ElementAtSource {\n constructor(n, source){\n this.n = n;\n this.source = source;\n }\n run(sink, scheduler) {\n const sd = new SettableDisposable();\n sd.set(this.source.run(new ElementAtSink(this.n, sink, sd), scheduler));\n return sd;\n }\n};\n/**\n * Emit only the nth value (0-indexed), then end.\n *\n * Denotation: `elementAt(n, e) = [e[n]]` if it exists, empty otherwise.\n */ const elementAt$1 = (n, event)=>_createEvent(new ElementAtSource(n, _getSource(event)));\n\n// --- Internal tag ---\nconst BEHAVIOR_KEY = Symbol(\"pulse/behavior\");\n/** Create an opaque Behavior from a BehaviorImpl. Internal use only. */ const _createBehavior = (impl)=>({\n [BEHAVIOR_KEY]: impl\n });\n/** Extract the BehaviorImpl from an opaque Behavior. Internal use only. */ const _getBehaviorImpl = (behavior)=>behavior[BEHAVIOR_KEY];\n// --- Generation tracking ---\n/**\n * Compute the current generation of a behavior tree. This is the sum\n * of all stepper generations in the tree. If any stepper's generation\n * changed since the last cache, the cached value is stale.\n *\n * Function-based and switcher behaviors return -1 (never cacheable).\n */ const currentGeneration = (impl)=>{\n switch(impl.tag){\n case \"constant\":\n return 0;\n case \"function\":\n case \"switcher\":\n return -1; // Never cacheable\n case \"stepper\":\n return impl.generation;\n case \"map\":\n return currentGeneration(impl.source);\n case \"lift2\":\n {\n const ga = currentGeneration(impl.a);\n const gb = currentGeneration(impl.b);\n if (ga < 0 || gb < 0) return -1;\n return ga + gb;\n }\n }\n};\n// --- Sampling ---\n/**\n * Sample a behavior at a point in time.\n *\n * Denotation: evaluates `behavior(time)`.\n */ const sampleImpl = (impl, time)=>{\n switch(impl.tag){\n case \"constant\":\n return impl.value;\n case \"function\":\n return impl.f(time);\n case \"stepper\":\n return impl.value;\n case \"map\":\n {\n const gen = currentGeneration(impl);\n if (gen >= 0 && impl.cached !== undefined && impl.cachedGeneration === gen) {\n return impl.cached;\n }\n const result = impl.f(sampleImpl(impl.source, time));\n impl.cached = result;\n impl.cachedGeneration = gen;\n return result;\n }\n case \"lift2\":\n {\n const gen = currentGeneration(impl);\n if (gen >= 0 && impl.cached !== undefined && impl.cachedGeneration === gen) {\n return impl.cached;\n }\n const result = impl.f(sampleImpl(impl.a, time), sampleImpl(impl.b, time));\n impl.cached = result;\n impl.cachedGeneration = gen;\n return result;\n }\n case \"switcher\":\n return sampleImpl(impl.current, time);\n }\n};\n/**\n * Sample a Behavior at a time.\n */ const sampleBehavior = (behavior, time)=>sampleImpl(_getBehaviorImpl(behavior), time);\n// --- Stepper subscription ---\n/**\n * Subscribe a stepper behavior to an event stream.\n * Returns a Disposable to unsubscribe.\n */ const subscribeStepperToEvent = (stepperImpl, event, scheduler)=>{\n const source = _getSource(event);\n const sink = {\n event (time, value) {\n stepperImpl.value = value;\n stepperImpl.time = time;\n stepperImpl.generation++;\n },\n error () {},\n end () {}\n };\n return source.run(sink, scheduler);\n};\n\n// --- Constructors ---\n/**\n * A Behavior that always holds the same value.\n *\n * Denotation: `t => value`\n */ const constantB = (value)=>_createBehavior({\n tag: \"constant\",\n value\n });\n/**\n * A Behavior defined by an arbitrary function of time.\n *\n * Denotation: `f` itself.\n */ const fromFunction = (f)=>_createBehavior({\n tag: \"function\",\n f\n });\n/**\n * The identity Behavior — its value is the current time.\n *\n * Denotation: `t => t`\n */ const time = fromFunction((t)=>t);\n/**\n * Alias for constantB — the pure/of for Behavior's Applicative.\n */ const pureB = constantB;\n// --- Functor ---\n/**\n * Transform the value of a Behavior.\n *\n * Denotation: `mapB(f, b) = t => f(b(t))`\n */ const mapB$1 = (f, behavior)=>{\n const source = _getBehaviorImpl(behavior);\n // Optimization: map of constant is a constant\n if (source.tag === \"constant\") {\n return _createBehavior({\n tag: \"constant\",\n value: f(source.value)\n });\n }\n // Optimization: map of function is a composed function\n if (source.tag === \"function\") {\n return _createBehavior({\n tag: \"function\",\n f: (t)=>f(source.f(t))\n });\n }\n return _createBehavior({\n tag: \"map\",\n f: f,\n source: source,\n cachedGeneration: -1,\n cached: undefined\n });\n};\n// --- Applicative ---\n/**\n * Lift a binary function over two Behaviors.\n *\n * Denotation: `liftA2B(f, ba, bb) = t => f(ba(t), bb(t))`\n */ const liftA2B = (f, ba, bb)=>{\n const implA = _getBehaviorImpl(ba);\n const implB = _getBehaviorImpl(bb);\n // Optimization: both constant → constant\n if (implA.tag === \"constant\" && implB.tag === \"constant\") {\n return _createBehavior({\n tag: \"constant\",\n value: f(implA.value, implB.value)\n });\n }\n return _createBehavior({\n tag: \"lift2\",\n f: f,\n a: implA,\n b: implB,\n cachedGeneration: -1,\n cached: undefined\n });\n};\n/**\n * Lift a ternary function over three Behaviors.\n *\n * Denotation: `liftA3B(f, ba, bb, bc) = t => f(ba(t), bb(t), bc(t))`\n */ const liftA3B = (f, ba, bb, bc)=>liftA2B((ab, c)=>ab(c), liftA2B((a, b)=>(c)=>f(a, b, c), ba, bb), bc);\n/**\n * Lift a quaternary function over four Behaviors.\n *\n * Denotation: `liftA4B(f, ba, bb, bc, bd) = t => f(ba(t), bb(t), bc(t), bd(t))`\n */ const liftA4B = (f, ba, bb, bc, bd)=>liftA2B((abc, d)=>abc(d), liftA3B((a, b, c)=>(d)=>f(a, b, c, d), ba, bb, bc), bd);\n/**\n * Lift a quinary function over five Behaviors.\n *\n * Denotation: `liftA5B(f, ba, bb, bc, bd, be) = t => f(ba(t), bb(t), bc(t), bd(t), be(t))`\n */ const liftA5B = (f, ba, bb, bc, bd, be)=>liftA2B((abcd, e)=>abcd(e), liftA4B((a, b, c, d)=>(e)=>f(a, b, c, d, e), ba, bb, bc, bd), be);\n// --- Event ↔ Behavior Bridge ---\n/**\n * Create a Behavior that holds the latest value from an Event.\n *\n * Denotation: `stepper(init, e) = t => latestValue(e, t) ?? init`\n *\n * This is the primary push→pull bridge. The returned behavior is\n * push-updated when the event fires, and pull-sampled when read.\n *\n * IMPORTANT: The caller must provide a scheduler to subscribe to the event.\n * Returns [Behavior, Disposable] — the disposable unsubscribes from the event.\n */ const stepper = (initial, event, scheduler)=>{\n const impl = {\n tag: \"stepper\",\n initial,\n value: initial,\n time: scheduler.currentTime(),\n generation: 0\n };\n const disposable = subscribeStepperToEvent(impl, event, scheduler);\n return [\n _createBehavior(impl),\n disposable\n ];\n};\n/**\n * Create a Behavior that accumulates event values with a fold function.\n *\n * Denotation: `accumB(f, init, e) = t => foldl f init [v | (t', v) ∈ e, t' <= t]`\n *\n * Like `stepper` but applies a reducer to each event instead of replacing\n * the held value. Equivalent to `stepper(init, scan(f, init, e))` but\n * without an intermediate Event allocation.\n */ const accumB = (f, initial, event, scheduler)=>{\n const impl = {\n tag: \"stepper\",\n initial,\n value: initial,\n time: scheduler.currentTime(),\n generation: 0\n };\n const source = _getSource(event);\n const disposable = source.run({\n event (time, value) {\n impl.value = f(impl.value, value);\n impl.time = time;\n impl.generation++;\n },\n error () {},\n end () {}\n }, scheduler);\n return [\n _createBehavior(impl),\n disposable\n ];\n};\n/**\n * Sample a Behavior whenever a sampler Event fires.\n *\n * Denotation: `sample(b, sampler) = [(t, b(t)) | (t, _) ∈ sampler]`\n */ const sample$1 = (behavior, sampler)=>{\n const source = _getSource(sampler);\n return _createEvent({\n run (sink, scheduler) {\n return source.run({\n event (t, _value) {\n const v = sampleBehavior(behavior, t);\n sink.event(t, v);\n },\n error (t, err) {\n sink.error(t, err);\n },\n end (t) {\n sink.end(t);\n }\n }, scheduler);\n }\n });\n};\n/**\n * Snapshot: sample a Behavior and combine with the Event value.\n *\n * Denotation: `snapshot(f, b, e) = [(t, f(b(t), v)) | (t, v) ∈ e]`\n */ const snapshot$1 = (f, behavior, event)=>{\n const source = _getSource(event);\n return _createEvent({\n run (sink, scheduler) {\n return source.run({\n event (t, value) {\n const bValue = sampleBehavior(behavior, t);\n sink.event(t, f(bValue, value));\n },\n error (t, err) {\n sink.error(t, err);\n },\n end (t) {\n sink.end(t);\n }\n }, scheduler);\n }\n });\n};\n/**\n * Dynamic Behavior switching.\n *\n * Holds `initial` until the event fires, then switches to the\n * Behavior carried by each event occurrence.\n *\n * Denotation: holds the most recently received Behavior; samples it.\n */ const switcher = (initial, event, scheduler)=>{\n const impl = {\n tag: \"switcher\",\n current: _getBehaviorImpl(initial)\n };\n const source = _getSource(event);\n const disposable = source.run({\n event (_t, newBehavior) {\n impl.current = _getBehaviorImpl(newBehavior);\n },\n error () {},\n end () {}\n }, scheduler);\n return [\n _createBehavior(impl),\n disposable\n ];\n};\n/**\n * Flatten a Behavior of Behaviors — the Monad join for Behaviors.\n *\n * Denotation: `switchB(bb) = t => bb(t)(t)`\n *\n * At time `t`, samples the outer behavior to get the inner behavior,\n * then samples the inner behavior at the same time. This is inherently\n * non-cacheable (the inner behavior can change at any time).\n */ const switchB$1 = (bb)=>_createBehavior({\n tag: \"function\",\n f: (t)=>sampleBehavior(sampleBehavior(bb, t), t)\n });\n// --- Integration ---\n/**\n * Numerical integration of a Behavior over time.\n *\n * Denotation: `integral(b, dt) ≈ t => ∫₀ᵗ b(s) ds`\n *\n * Uses the trapezoidal rule with step size `dt`. The consumer's sampling\n * rate and the integration step size are decoupled — the integrator\n * subdivides [0, t] into steps of size `dt` regardless of when sampling\n * occurs.\n */ const integral$1 = (behavior, dt)=>{\n const step = dt;\n return fromFunction((t)=>{\n const end = t;\n if (end <= 0) return 0;\n let acc = 0;\n let prev = sampleBehavior(behavior, 0);\n let s = 0;\n while(s + step < end){\n s += step;\n const curr = sampleBehavior(behavior, s);\n acc += (prev + curr) * 0.5 * step;\n prev = curr;\n }\n // Final partial step\n if (s < end) {\n const remaining = end - s;\n const curr = sampleBehavior(behavior, end);\n acc += (prev + curr) * 0.5 * remaining;\n }\n return acc;\n });\n};\n/**\n * Numerical differentiation of a Behavior over time.\n *\n * Denotation: `derivative(b, dt) ≈ t => db/dt(t)`\n *\n * Uses the backward finite difference: `(b(t) - b(t - dt)) / dt`.\n * At `t = 0`, returns 0 (no history). For `t < dt`, uses the\n * available interval `[0, t]`.\n */ const derivative$1 = (behavior, dt)=>{\n const step = dt;\n return fromFunction((t)=>{\n const tNum = t;\n if (tNum <= 0) return 0;\n const interval = Math.min(step, tNum);\n const curr = sampleBehavior(behavior, t);\n const prev = sampleBehavior(behavior, tNum - interval);\n return (curr - prev) / interval;\n });\n};\n\n/**\n * Convert an Event to an AsyncIterableIterator.\n *\n * Backpressure: the source pushes into a buffer. The consumer pulls\n * via `next()`. If the consumer is slower than the producer, values\n * buffer in memory.\n */ const toAsyncIterator = (event, scheduler)=>{\n const queue = [];\n let resolve;\n let reject;\n let done = false;\n const source = _getSource(event);\n const disposable = source.run({\n event (_time, value) {\n if (resolve) {\n const r = resolve;\n resolve = undefined;\n r({\n value,\n done: false\n });\n } else {\n queue.push({\n tag: \"value\",\n value\n });\n }\n },\n error (_time, err) {\n done = true;\n if (reject) {\n const r = reject;\n reject = undefined;\n r(err);\n } else {\n queue.push({\n tag: \"error\",\n error: err\n });\n }\n },\n end (_time) {\n done = true;\n if (resolve) {\n const r = resolve;\n resolve = undefined;\n r({\n value: undefined,\n done: true\n });\n } else {\n queue.push({\n tag: \"end\"\n });\n }\n }\n }, scheduler);\n const iterator = {\n next () {\n if (queue.length > 0) {\n const item = queue.shift();\n switch(item.tag){\n case \"value\":\n return Promise.resolve({\n value: item.value,\n done: false\n });\n case \"error\":\n return Promise.reject(item.error);\n case \"end\":\n return Promise.resolve({\n value: undefined,\n done: true\n });\n }\n }\n if (done) {\n return Promise.resolve({\n value: undefined,\n done: true\n });\n }\n return new Promise((res, rej)=>{\n resolve = res;\n reject = rej;\n });\n },\n return () {\n done = true;\n disposable.dispose();\n return Promise.resolve({\n value: undefined,\n done: true\n });\n },\n [Symbol.asyncIterator] () {\n return this;\n },\n dispose () {\n done = true;\n disposable.dispose();\n }\n };\n return iterator;\n};\n/**\n * Create an Event from an AsyncIterable.\n *\n * The async iterable is pulled eagerly — each value is pushed\n * to subscribers as soon as it's available.\n */ const fromAsyncIterable = (iterable)=>_createEvent({\n run (sink, scheduler) {\n let disposed = false;\n (async ()=>{\n try {\n for await (const value of iterable){\n if (disposed) break;\n sink.event(scheduler.currentTime(), value);\n }\n if (!disposed) {\n sink.end(scheduler.currentTime());\n }\n } catch (err) {\n if (!disposed) {\n sink.error(scheduler.currentTime(), err);\n }\n }\n })();\n return {\n dispose () {\n disposed = true;\n }\n };\n }\n });\n\n/**\n * Share a single subscription to the source Event among all downstream consumers.\n *\n * - First subscriber triggers the source subscription\n * - Subsequent subscribers share the same subscription\n * - When the last subscriber disposes, the source subscription is disposed\n * - If a new subscriber arrives after disposal, the source is re-subscribed\n */ const multicast = (event)=>{\n const source = _getSource(event);\n const sinks = new Set();\n let sourceDisposable;\n let ended = false;\n return _createEvent({\n run (sink, sched) {\n sinks.add(sink);\n if (sinks.size === 1) {\n ended = false;\n sourceDisposable = source.run({\n event (time, value) {\n for (const s of sinks){\n s.event(time, value);\n }\n },\n error (time, err) {\n for (const s of sinks){\n s.error(time, err);\n }\n },\n end (time) {\n ended = true;\n for (const s of sinks){\n s.end(time);\n }\n }\n }, sched);\n } else if (ended) {\n // Source already ended — immediately end new subscriber\n sink.end(sched.currentTime());\n }\n return {\n dispose () {\n sinks.delete(sink);\n if (sinks.size === 0 && sourceDisposable !== undefined) {\n sourceDisposable.dispose();\n sourceDisposable = undefined;\n }\n }\n };\n }\n });\n};\n\n/**\n * Chainable wrapper around a pulse Event.\n *\n * Every method returns a new FluentEvent (or a terminal value like Promise).\n * The underlying Event is accessible via `.event`.\n */ class FluentEvent {\n constructor(event){\n this.event = event;\n }\n // --- Functor / Transform ---\n map(f) {\n return new FluentEvent(map$1(f, this.event));\n }\n filter(predicate) {\n return new FluentEvent(filter$1(predicate, this.event));\n }\n tap(f) {\n return new FluentEvent(tap$1(f, this.event));\n }\n constant(value) {\n return new FluentEvent(constant$1(value, this.event));\n }\n scan(f, seed) {\n return new FluentEvent(scan$1(f, seed, this.event));\n }\n dedupe(eq) {\n return new FluentEvent(dedupe$1(this.event, eq));\n }\n cons(value) {\n return new FluentEvent(cons$1(value, this.event));\n }\n pairwise() {\n return new FluentEvent(pairwise$1(this.event));\n }\n first(predicate) {\n return new FluentEvent(first$1(this.event, predicate));\n }\n last(predicate) {\n return new FluentEvent(last$1(this.event, predicate));\n }\n // --- Slicing ---\n take(n) {\n return new FluentEvent(take$1(n, this.event));\n }\n drop(n) {\n return new FluentEvent(drop$1(n, this.event));\n }\n takeWhile(predicate) {\n return new FluentEvent(takeWhile$1(predicate, this.event));\n }\n dropWhile(predicate) {\n return new FluentEvent(dropWhile$1(predicate, this.event));\n }\n slice(start, end) {\n return new FluentEvent(slice$1(start, end, this.event));\n }\n until(signal) {\n return new FluentEvent(until$1(signal, this.event));\n }\n since(signal) {\n return new FluentEvent(since$1(signal, this.event));\n }\n // --- Combining ---\n merge(...others) {\n return new FluentEvent(merge(this.event, ...others));\n }\n combine(f, other) {\n return new FluentEvent(combine(f, this.event, other));\n }\n zip(other) {\n return new FluentEvent(zip(this.event, other));\n }\n // --- Higher-order ---\n chain(f) {\n return new FluentEvent(chain$1(f, this.event));\n }\n mergeMap(f, concurrency) {\n return new FluentEvent(mergeMap$1(f, concurrency, this.event));\n }\n traverse(f, concurrency) {\n return new FluentEvent(traverse$1(f, concurrency, this.event));\n }\n exhaustMap(f) {\n return new FluentEvent(exhaustMap$1(f, this.event));\n }\n // --- Error handling ---\n catchError(handler) {\n return new FluentEvent(catchError$1(handler, this.event));\n }\n mapError(f) {\n return new FluentEvent(mapError$1(f, this.event));\n }\n // --- Time ---\n debounce(duration) {\n return new FluentEvent(debounce$1(duration, this.event));\n }\n throttle(duration) {\n return new FluentEvent(throttle$1(duration, this.event));\n }\n delay(duration) {\n return new FluentEvent(delay$1(duration, this.event));\n }\n bufferCount(count) {\n return new FluentEvent(bufferCount$1(count, this.event));\n }\n bufferTime(duration) {\n return new FluentEvent(bufferTime$1(duration, this.event));\n }\n // --- Behavior bridge ---\n sample(behavior) {\n return new FluentEvent(sample$1(behavior, this.event));\n }\n snapshot(f, behavior) {\n return new FluentEvent(snapshot$1(f, behavior, this.event));\n }\n retry(maxRetries, delayDuration) {\n return new FluentEvent(retry$1(maxRetries, this.event, delayDuration));\n }\n attach(f, sampler) {\n return new FluentEvent(attach$1(f, this.event, sampler));\n }\n timeout(duration) {\n return new FluentEvent(timeout$1(duration, this.event));\n }\n orElse(value) {\n return new FluentEvent(orElse$1(value, this.event));\n }\n ensure(cleanup) {\n return new FluentEvent(ensure$1(cleanup, this.event));\n }\n count() {\n return new FluentEvent(count$1(this.event));\n }\n all(predicate) {\n return new FluentEvent(all$1(predicate, this.event));\n }\n elementAt(n) {\n return new FluentEvent(elementAt$1(n, this.event));\n }\n race(...others) {\n return new FluentEvent(race(this.event, ...others));\n }\n // --- Utilities ---\n multicast() {\n return new FluentEvent(multicast(this.event));\n }\n share(bufferSize) {\n return new FluentEvent(share$1(bufferSize, this.event));\n }\n toAsyncIterator(scheduler) {\n return toAsyncIterator(this.event, scheduler);\n }\n // --- Terminal (activate the stream) ---\n reduce(f, seed, scheduler) {\n return reduce$1(f, seed, this.event, scheduler);\n }\n observe(f, scheduler) {\n return observe$1(f, this.event, scheduler);\n }\n drain(scheduler) {\n return drain$1(this.event, scheduler);\n }\n}\n/**\n * Wrap a pulse Event in a chainable fluent interface.\n *\n * ```typescript\n * const result = await fluent(fromArray([1, 2, 3, 4, 5]))\n * .filter(x => x % 2 === 0)\n * .map(x => x * 10)\n * .take(2)\n * .reduce((acc, x) => acc + x, 0, scheduler);\n * // result === 60\n * ```\n */ const fluent = (event)=>new FluentEvent(event);\n\n/**\n * Pipeable utility.\n *\n * Enables `pipe(event, map(f), filter(p), take(10))` style composition\n * with full type inference up to 12 operators.\n */ /* eslint-disable @typescript-eslint/no-explicit-any */ function pipe(source, ...ops) {\n let result = source;\n for (const op of ops){\n result = op(result);\n }\n return result;\n}\n\n// --- Event operators ---\nconst map = (f)=>(event)=>map$1(f, event);\nconst filter = (predicate)=>(event)=>filter$1(predicate, event);\nconst tap = (f)=>(event)=>tap$1(f, event);\nconst constant = (value)=>(event)=>constant$1(value, event);\nconst scan = (f, seed)=>(event)=>scan$1(f, seed, event);\nconst take = (n)=>(event)=>take$1(n, event);\nconst drop = (n)=>(event)=>drop$1(n, event);\nconst takeWhile = (predicate)=>(event)=>takeWhile$1(predicate, event);\nconst dropWhile = (predicate)=>(event)=>dropWhile$1(predicate, event);\nconst slice = (start, end)=>(event)=>slice$1(start, end, event);\nconst chain = (f)=>(event)=>chain$1(f, event);\nconst mergeMap = (f, concurrency)=>(event)=>mergeMap$1(f, concurrency, event);\nconst catchError = (handler)=>(event)=>catchError$1(handler, event);\nconst mapError = (f)=>(event)=>mapError$1(f, event);\nconst traverse = (f, concurrency)=>(event)=>traverse$1(f, concurrency, event);\nconst switchLatest = (event)=>switchLatest$1(event);\nconst retry = (maxRetries, delay)=>(event)=>retry$1(maxRetries, event, delay);\nconst share = (bufferSize)=>(event)=>share$1(bufferSize, event);\nconst attach = (f, sampled)=>(sampler)=>attach$1(f, sampled, sampler);\nconst until = (signal)=>(event)=>until$1(signal, event);\nconst since = (signal)=>(event)=>since$1(signal, event);\nconst dedupe = (eq)=>(event)=>dedupe$1(event, eq);\nconst cons = (value)=>(event)=>cons$1(value, event);\nconst first = (predicate)=>(event)=>first$1(event, predicate);\nconst last = (predicate)=>(event)=>last$1(event, predicate);\nconst pairwise = (event)=>pairwise$1(event);\nconst timeout = (duration)=>(event)=>timeout$1(duration, event);\nconst exhaustMap = (f)=>(event)=>exhaustMap$1(f, event);\nconst orElse = (value)=>(event)=>orElse$1(value, event);\nconst ensure = (cleanup)=>(event)=>ensure$1(cleanup, event);\nconst count = (event)=>count$1(event);\nconst all = (predicate)=>(event)=>all$1(predicate, event);\nconst elementAt = (n)=>(event)=>elementAt$1(n, event);\n// --- Time operators ---\nconst debounce = (duration)=>(event)=>debounce$1(duration, event);\nconst throttle = (duration)=>(event)=>throttle$1(duration, event);\nconst delay = (duration)=>(event)=>delay$1(duration, event);\nconst bufferCount = (count)=>(event)=>bufferCount$1(count, event);\nconst bufferTime = (duration)=>(event)=>bufferTime$1(duration, event);\n// --- Terminal operators ---\nconst reduce = (f, seed, scheduler)=>(event)=>reduce$1(f, seed, event, scheduler);\nconst observe = (f, scheduler)=>(event)=>observe$1(f, event, scheduler);\nconst drain = (scheduler)=>(event)=>drain$1(event, scheduler);\n// --- Behavior operators ---\nconst mapB = (f)=>(behavior)=>mapB$1(f, behavior);\nconst sample = (behavior)=>(sampler)=>sample$1(behavior, sampler);\nconst snapshot = (f, behavior)=>(event)=>snapshot$1(f, behavior, event);\nconst integral = (dt)=>(behavior)=>integral$1(behavior, dt);\nconst derivative = (dt)=>(behavior)=>derivative$1(behavior, dt);\nconst switchB = (bb)=>switchB$1(bb);\n\nvar pipeable = /*#__PURE__*/Object.freeze({\n __proto__: null,\n all: all,\n attach: attach,\n bufferCount: bufferCount,\n bufferTime: bufferTime,\n catchError: catchError,\n chain: chain,\n cons: cons,\n constant: constant,\n count: count,\n debounce: debounce,\n dedupe: dedupe,\n delay: delay,\n derivative: derivative,\n drain: drain,\n drop: drop,\n dropWhile: dropWhile,\n elementAt: elementAt,\n ensure: ensure,\n exhaustMap: exhaustMap,\n filter: filter,\n first: first,\n integral: integral,\n last: last,\n map: map,\n mapB: mapB,\n mapError: mapError,\n mergeMap: mergeMap,\n observe: observe,\n orElse: orElse,\n pairwise: pairwise,\n reduce: reduce,\n retry: retry,\n sample: sample,\n scan: scan,\n share: share,\n since: since,\n slice: slice,\n snapshot: snapshot,\n switchB: switchB,\n switchLatest: switchLatest,\n take: take,\n takeWhile: takeWhile,\n tap: tap,\n throttle: throttle,\n timeout: timeout,\n traverse: traverse,\n until: until\n});\n\n/**\n * Create an imperative push adapter.\n *\n * Returns [push, event] where:\n * - `push(value)` sends a value to all current subscribers\n * - `event` is a subscribable Event stream\n */ const createAdapter = ()=>{\n const sinks = new Set();\n const push = (value)=>{\n if (sinks.size === 0) return;\n for (const { sink, scheduler } of sinks){\n sink.event(scheduler.currentTime(), value);\n }\n };\n const event = _createEvent({\n run (sink, scheduler) {\n const entry = {\n sink,\n scheduler\n };\n sinks.add(entry);\n return {\n dispose () {\n sinks.delete(entry);\n }\n };\n }\n });\n return [\n push,\n event\n ];\n};\n\nexport { FluentEvent, pipeable as P, TimeoutError, accumB, all$1 as all, at, attach$1 as attach, bufferCount$1 as bufferCount, bufferTime$1 as bufferTime, catchError$1 as catchError, chain$1 as chain, combine, cons$1 as cons, constant$1 as constant, constantB, count$1 as count, createAdapter, debounce$1 as debounce, dedupe$1 as dedupe, delay$1 as delay, derivative$1 as derivative, drain$1 as drain, drop$1 as drop, dropWhile$1 as dropWhile, elementAt$1 as elementAt, empty, ensure$1 as ensure, exhaustMap$1 as exhaustMap, filter$1 as filter, first$1 as first, fluent, forkJoin, fromArray, fromAsyncIterable, fromFunction, fromIterable, fromPromise, integral$1 as integral, last$1 as last, liftA2B, liftA3B, liftA4B, liftA5B, map$1 as map, mapB$1 as mapB, mapError$1 as mapError, merge, mergeMap$1 as mergeMap, multicast, never, now, observe$1 as observe, orElse$1 as orElse, pairwise$1 as pairwise, periodic, pipe, pureB, race, range, sampleBehavior as readBehavior, reduce$1 as reduce, retry$1 as retry, sample$1 as sample, scan$1 as scan, share$1 as share, since$1 as since, slice$1 as slice, snapshot$1 as snapshot, stepper, switchB$1 as switchB, switchLatest$1 as switchLatest, switcher, take$1 as take, takeWhile$1 as takeWhile, tap$1 as tap, throttle$1 as throttle, throwError, time, timeout$1 as timeout, toAsyncIterator, traverse$1 as traverse, until$1 as until, zip };\n//# sourceMappingURL=index.js.map\n","/**\n * DOM Behaviors — continuous time-varying values derived from the DOM.\n *\n * These create Behaviors that are push-updated from DOM events and\n * pull-sampled when read. Each returns [Behavior, Disposable] since\n * they subscribe to DOM events internally.\n */\n\nimport { stepper } from \"aeon-core\";\nimport { map } from \"aeon-core\";\nimport type { Behavior, Disposable, Scheduler } from \"aeon-types\";\nimport { fromDOMEvent } from \"./events.js\";\n\n/** 2D point for mouse coordinates. */\nexport interface Point {\n readonly x: number;\n readonly y: number;\n}\n\n/** Dimensions for window size. */\nexport interface Size {\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * A Behavior holding the current mouse position.\n *\n * Denotation: `t => { x: mouseX(t), y: mouseY(t) }`\n *\n * Push-updated from mousemove events on the given target (defaults to document).\n * Returns [Behavior, Disposable] — dispose to stop listening.\n */\nexport const mousePosition = (\n scheduler: Scheduler,\n target: EventTarget = document,\n): [Behavior<Point, never>, Disposable] => {\n const moves = map(\n (e: MouseEvent) => ({ x: e.clientX, y: e.clientY }),\n fromDOMEvent(\"mousemove\", target as Document),\n );\n return stepper({ x: 0, y: 0 }, moves, scheduler);\n};\n\n/**\n * A Behavior holding the current window dimensions.\n *\n * Denotation: `t => { width: innerWidth(t), height: innerHeight(t) }`\n *\n * Push-updated from resize events on window.\n * Returns [Behavior, Disposable] — dispose to stop listening.\n */\nexport const windowSize = (scheduler: Scheduler): [Behavior<Size, never>, Disposable] => {\n const initial: Size =\n typeof window !== \"undefined\"\n ? { width: window.innerWidth, height: window.innerHeight }\n : { width: 0, height: 0 };\n\n const resizes = map(\n () => ({ width: window.innerWidth, height: window.innerHeight }),\n fromDOMEvent(\"resize\", window as unknown as Window),\n );\n return stepper(initial, resizes, scheduler);\n};\n"],"names":["createEvent","source","DOMEventSource","type","target","options","run","sink","scheduler","handler","e","event","currentTime","addEventListener","dispose","removeEventListener","fromDOMEvent","AnimationFrameSource","id","disposed","tick","timestamp","requestAnimationFrame","cancelAnimationFrame","ANIMATION_FRAME_SOURCE","animationFrames","disposeNone","mousePosition","document","moves","map","x","clientX","y","clientY","stepper","windowSize","initial","window","width","innerWidth","height","innerHeight","resizes"],"mappings":";;AAAA;;;;;AAKC,0EAKM,MAAMA,WAAAA,GAAc,CAAeC,SACxCA,MAAAA;;ACFF,IAAMC,iBAAN,MAAMA,cAAAA,CAAAA;AAKJ,IAAA,WAAA,CAAYC,IAAY,EAAEC,MAAmB,EAAEC,OAAiC,CAAE;QAChF,IAAI,CAACF,IAAI,GAAGA,IAAAA;QACZ,IAAI,CAACC,MAAM,GAAGA,MAAAA;QACd,IAAI,CAACC,OAAO,GAAGA,OAAAA;AACjB,IAAA;IAEAC,GAAAA,CAAIC,IAAoB,EAAEC,SAAoB,EAAc;AAC1D,QAAA,MAAMC,UAAU,CAACC,CAAAA,GAAAA;AACfH,YAAAA,IAAAA,CAAKI,KAAK,CAACH,SAAAA,CAAUI,WAAW,EAAA,EAAIF,CAAAA,CAAAA;AACtC,QAAA,CAAA;AACA,QAAA,IAAI,CAACN,MAAM,CAACS,gBAAgB,CAAC,IAAI,CAACV,IAAI,EAAEM,OAAAA,EAAS,IAAI,CAACJ,OAAO,CAAA;QAC7D,OAAO;YACLS,OAAAA,EAAS,IAAA;AACP,gBAAA,IAAI,CAACV,MAAM,CAACW,mBAAmB,CAAC,IAAI,CAACZ,IAAI,EAAEM,OAAAA,EAAS,IAAI,CAACJ,OAAO,CAAA;AAClE,YAAA;AACF,SAAA;AACF,IAAA;AACF,CAAA;AA6BO,SAASW,YAAAA,CACdb,IAAY,EACZC,MAAmB,EACnBC,OAAiC,EAAA;AAEjC,IAAA,OAAOL,WAAAA,CAAY,IAAIE,cAAAA,CAAeC,IAAAA,EAAMC,MAAAA,EAAQC,OAAAA,CAAAA,CAAAA;AACtD;;ACzDA,IAAMY,uBAAN,MAAMA,oBAAAA,CAAAA;IACJX,GAAAA,CAAIC,IAAsC,EAAEC,SAAoB,EAAc;AAC5E,QAAA,IAAIU,EAAAA,GAAK,CAAA;AACT,QAAA,IAAIC,QAAAA,GAAW,KAAA;AAEf,QAAA,MAAMC,OAAO,CAACC,SAAAA,GAAAA;AACZ,YAAA,IAAIF,QAAAA,EAAU;AACdZ,YAAAA,IAAAA,CAAKI,KAAK,CAACH,SAAAA,CAAUI,WAAW,EAAA,EAAIS,SAAAA,CAAAA;AACpCH,YAAAA,EAAAA,GAAKI,qBAAAA,CAAsBF,IAAAA,CAAAA;AAC7B,QAAA,CAAA;AAEAF,QAAAA,EAAAA,GAAKI,qBAAAA,CAAsBF,IAAAA,CAAAA;QAE3B,OAAO;AACLN,YAAAA,OAAAA,CAAAA,GAAAA;gBACEK,QAAAA,GAAW,IAAA;gBACXI,oBAAAA,CAAqBL,EAAAA,CAAAA;AACvB,YAAA;AACF,SAAA;AACF,IAAA;AACF,CAAA;AAEA,MAAMM,yBAAyB,IAAIP,oBAAAA,EAAAA;AAEnC;;;;;;AAMC,IACM,MAAMQ,eAAAA,GACXzB,WAAAA,CAAYwB,sBAAAA;;ACvCd,2BACO,MAAME,WAAAA,GAA0B;IAAEZ,OAAAA,CAAAA,GAAAA,CAAW;AAAE,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACsBtD;;;;;;;AAOC,IACM,MAAMa,aAAAA,GAAgB,CAC3BnB,SAAAA,EACAJ,SAAsBwB,QAAQ,GAAA;AAE9B,IAAA,MAAMC,KAAAA,GAAQC,KAAAA,CACZ,CAACpB,CAAAA,IAAmB;AAAEqB,YAAAA,CAAAA,EAAGrB,EAAEsB,OAAO;AAAEC,YAAAA,CAAAA,EAAGvB,EAAEwB;SAAQ,CAAA,EACjDlB,aAAa,WAAA,EAAaZ,MAAAA,CAAAA,CAAAA;AAE5B,IAAA,OAAO+B,OAAAA,CAAQ;QAAEJ,CAAAA,EAAG,CAAA;QAAGE,CAAAA,EAAG;AAAE,KAAA,EAAGJ,KAAAA,EAAOrB,SAAAA,CAAAA;AACxC;AAEA;;;;;;;IAQO,MAAM4B,UAAAA,GAAa,CAAC5B,SAAAA,GAAAA;IACzB,MAAM6B,OAAAA,GACJ,OAAOC,MAAAA,KAAW,WAAA,GACd;AAAEC,QAAAA,KAAAA,EAAOD,OAAOE,UAAU;AAAEC,QAAAA,MAAAA,EAAQH,OAAOI;KAAY,GACvD;QAAEH,KAAAA,EAAO,CAAA;QAAGE,MAAAA,EAAQ;AAAE,KAAA;IAE5B,MAAME,OAAAA,GAAUb,KAAAA,CACd,KAAO;AAAES,YAAAA,KAAAA,EAAOD,OAAOE,UAAU;AAAEC,YAAAA,MAAAA,EAAQH,OAAOI;SAAY,CAAA,EAC9D1B,aAAa,QAAA,EAAUsB,MAAAA,CAAAA,CAAAA;IAEzB,OAAOH,OAAAA,CAAQE,SAASM,OAAAA,EAASnC,SAAAA,CAAAA;AACnC;;;;;;;"}
@@ -0,0 +1,5 @@
1
+ export { fromDOMEvent } from "./events.js";
2
+ export { animationFrames } from "./animationFrames.js";
3
+ export { mousePosition, windowSize } from "./behaviors.js";
4
+ export type { Point, Size } from "./behaviors.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ export { fromDOMEvent } from "./events.js";
2
+ export { animationFrames } from "./animationFrames.js";
3
+ export { mousePosition, windowSize } from "./behaviors.js";
4
+ export type { Point, Size } from "./behaviors.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC3D,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Internal helpers for aeon-dom.
3
+ *
4
+ * At runtime, Event<A, E> IS Source<A, E> — the opaque type brand is
5
+ * purely type-level. This mirrors the zero-cost identity cast in aeon-core.
6
+ */ /** Create an opaque Event from a Source. Zero-cost identity cast. */ const createEvent = (source)=>source;
7
+
8
+ let DOMEventSource = class DOMEventSource {
9
+ constructor(type, target, options){
10
+ this.type = type;
11
+ this.target = target;
12
+ this.options = options;
13
+ }
14
+ run(sink, scheduler) {
15
+ const handler = (e)=>{
16
+ sink.event(scheduler.currentTime(), e);
17
+ };
18
+ this.target.addEventListener(this.type, handler, this.options);
19
+ return {
20
+ dispose: ()=>{
21
+ this.target.removeEventListener(this.type, handler, this.options);
22
+ }
23
+ };
24
+ }
25
+ };
26
+ function fromDOMEvent(type, target, options) {
27
+ return createEvent(new DOMEventSource(type, target, options));
28
+ }
29
+
30
+ let AnimationFrameSource = class AnimationFrameSource {
31
+ run(sink, scheduler) {
32
+ let id = 0;
33
+ let disposed = false;
34
+ const tick = (timestamp)=>{
35
+ if (disposed) return;
36
+ sink.event(scheduler.currentTime(), timestamp);
37
+ id = requestAnimationFrame(tick);
38
+ };
39
+ id = requestAnimationFrame(tick);
40
+ return {
41
+ dispose () {
42
+ disposed = true;
43
+ cancelAnimationFrame(id);
44
+ }
45
+ };
46
+ }
47
+ };
48
+ const ANIMATION_FRAME_SOURCE = new AnimationFrameSource();
49
+ /**
50
+ * An Event that emits a DOMHighResTimeStamp on each animation frame.
51
+ *
52
+ * Denotation: `[(t, timestamp) | each requestAnimationFrame callback]`
53
+ *
54
+ * Cancels the animation frame loop when disposed.
55
+ */ const animationFrames = createEvent(ANIMATION_FRAME_SOURCE);
56
+
57
+ /** A no-op disposable. */ const disposeNone = {
58
+ dispose () {}
59
+ };
60
+ /** Create an opaque Event from a Source. Zero-cost identity cast. */ const _createEvent = (source)=>source;
61
+ /** Extract the Source from an opaque Event. Zero-cost identity cast. */ const _getSource = (event)=>event;
62
+ // --- Source classes for V8 hidden class stability ---
63
+ let EmptySource = class EmptySource {
64
+ constructor(){
65
+ this._sync = true;
66
+ }
67
+ run(sink, scheduler) {
68
+ sink.end(scheduler.currentTime());
69
+ return disposeNone;
70
+ }
71
+ syncIterate(_emit) {}
72
+ };
73
+ let NowSource = class NowSource {
74
+ constructor(value){
75
+ this.value = value;
76
+ this._sync = true;
77
+ }
78
+ run(sink, scheduler) {
79
+ const t = scheduler.currentTime();
80
+ sink.event(t, this.value);
81
+ sink.end(t);
82
+ return disposeNone;
83
+ }
84
+ syncIterate(emit) {
85
+ emit(this.value);
86
+ }
87
+ };
88
+ // --- Singletons for empty/never ---
89
+ const EMPTY_SOURCE = new EmptySource();
90
+ /**
91
+ * Pipe base class for sinks that forward error/end unchanged.
92
+ *
93
+ * With ES2022 target, `extends Pipe` compiles to native `class extends` —
94
+ * zero helpers, zero overhead. V8 devirtualizes the shared error/end
95
+ * methods across all sink subtypes.
96
+ */ let Pipe = class Pipe {
97
+ constructor(sink){
98
+ this.sink = sink;
99
+ }
100
+ error(time, err) {
101
+ this.sink.error(time, err);
102
+ }
103
+ end(time) {
104
+ this.sink.end(time);
105
+ }
106
+ };
107
+ // --- Sink classes ---
108
+ /** Map sink: applies f to each value. */ let MapSink = class MapSink extends Pipe {
109
+ constructor(f, sink){
110
+ super(sink);
111
+ this.f = f;
112
+ }
113
+ event(time, value) {
114
+ const f = this.f;
115
+ this.sink.event(time, f(value));
116
+ }
117
+ };
118
+ /** Filter sink: only forwards values that pass the predicate. */ let FilterSink = class FilterSink extends Pipe {
119
+ constructor(predicate, sink){
120
+ super(sink);
121
+ this.predicate = predicate;
122
+ }
123
+ event(time, value) {
124
+ const p = this.predicate;
125
+ if (p(value)) {
126
+ this.sink.event(time, value);
127
+ }
128
+ }
129
+ };
130
+ /** Combined filter+map sink: filter then map in one node. */ let FilterMapSink = class FilterMapSink extends Pipe {
131
+ constructor(predicate, f, sink){
132
+ super(sink);
133
+ this.predicate = predicate;
134
+ this.f = f;
135
+ }
136
+ event(time, value) {
137
+ const p = this.predicate;
138
+ if (p(value)) {
139
+ const f = this.f;
140
+ this.sink.event(time, f(value));
141
+ }
142
+ }
143
+ };
144
+ /** Combined map+filter sink: map then filter in one node. */ let MapFilterSink = class MapFilterSink extends Pipe {
145
+ constructor(f, predicate, sink){
146
+ super(sink);
147
+ this.f = f;
148
+ this.predicate = predicate;
149
+ }
150
+ event(time, value) {
151
+ const f = this.f;
152
+ const mapped = f(value);
153
+ const p = this.predicate;
154
+ if (p(mapped)) {
155
+ this.sink.event(time, mapped);
156
+ }
157
+ }
158
+ };
159
+ // --- Source classes (for instanceof fusion detection) ---
160
+ /** A map source, tagged for fusion detection via instanceof. */ let MapSource = class MapSource {
161
+ constructor(f, source){
162
+ this.f = f;
163
+ this.source = source;
164
+ }
165
+ run(sink, scheduler) {
166
+ return this.source.run(new MapSink(this.f, sink), scheduler);
167
+ }
168
+ /** Factory with fusion and algebraic simplification. */ static create(f, source) {
169
+ // map(f, empty()) → empty()
170
+ if (source instanceof EmptySource) {
171
+ return EMPTY_SOURCE;
172
+ }
173
+ // map(f, now(x)) → now(f(x)) — constant folding
174
+ if (source instanceof NowSource) {
175
+ return new NowSource(f(source.value));
176
+ }
177
+ // map(f, map(g, s)) → map(f∘g, s)
178
+ if (source instanceof MapSource) {
179
+ const inner = source;
180
+ return new MapSource((x)=>f(inner.f(x)), inner.source);
181
+ }
182
+ // map(f, filter(p, s)) → filterMap(p, f, s)
183
+ if (source instanceof FilterSource) {
184
+ const inner = source;
185
+ return new FilterMapSource(inner.predicate, f, inner.source);
186
+ }
187
+ return new MapSource(f, source);
188
+ }
189
+ };
190
+ /** A filter source, tagged for fusion detection via instanceof. */ let FilterSource = class FilterSource {
191
+ constructor(predicate, source){
192
+ this.predicate = predicate;
193
+ this.source = source;
194
+ }
195
+ run(sink, scheduler) {
196
+ return this.source.run(new FilterSink(this.predicate, sink), scheduler);
197
+ }
198
+ /** Factory with fusion and algebraic simplification. */ static create(predicate, source) {
199
+ // filter(p, empty()) → empty()
200
+ if (source instanceof EmptySource) {
201
+ return EMPTY_SOURCE;
202
+ }
203
+ // filter(p, now(x)) → p(x) ? now(x) : empty() — constant folding
204
+ if (source instanceof NowSource) {
205
+ const val = source.value;
206
+ return predicate(val) ? source : EMPTY_SOURCE;
207
+ }
208
+ // filter(p, filter(q, s)) → filter(x => q(x) && p(x), s)
209
+ if (source instanceof FilterSource) {
210
+ const inner = source;
211
+ return new FilterSource((x)=>inner.predicate(x) && predicate(x), inner.source);
212
+ }
213
+ // filter(p, map(f, s)) → mapFilter(f, p, s)
214
+ if (source instanceof MapSource) {
215
+ const inner = source;
216
+ return new MapFilterSource(inner.f, predicate, inner.source);
217
+ }
218
+ return new FilterSource(predicate, source);
219
+ }
220
+ };
221
+ /** Fused filter-then-map source. */ let FilterMapSource = class FilterMapSource {
222
+ constructor(predicate, f, source){
223
+ this.predicate = predicate;
224
+ this.f = f;
225
+ this.source = source;
226
+ }
227
+ run(sink, scheduler) {
228
+ return this.source.run(new FilterMapSink(this.predicate, this.f, sink), scheduler);
229
+ }
230
+ };
231
+ /** Fused map-then-filter source. */ let MapFilterSource = class MapFilterSource {
232
+ constructor(f, predicate, source){
233
+ this.f = f;
234
+ this.predicate = predicate;
235
+ this.source = source;
236
+ }
237
+ run(sink, scheduler) {
238
+ return this.source.run(new MapFilterSink(this.f, this.predicate, sink), scheduler);
239
+ }
240
+ };
241
+ // --- Public API ---
242
+ /**
243
+ * Create a fusible map Event. Detects map∘map and composes functions.
244
+ */ const fusedMap = (f, event)=>{
245
+ const source = _getSource(event);
246
+ return _createEvent(MapSource.create(f, source));
247
+ };
248
+ /**
249
+ * Transform each value in an Event stream.
250
+ *
251
+ * Denotation: `map(f, e) = [(t, f(v)) | (t, v) ∈ e]`
252
+ */ const map$1 = (f, event)=>fusedMap(f, event);
253
+ // --- Internal tag ---
254
+ const BEHAVIOR_KEY = Symbol("pulse/behavior");
255
+ /** Create an opaque Behavior from a BehaviorImpl. Internal use only. */ const _createBehavior = (impl)=>({
256
+ [BEHAVIOR_KEY]: impl
257
+ });
258
+ // --- Stepper subscription ---
259
+ /**
260
+ * Subscribe a stepper behavior to an event stream.
261
+ * Returns a Disposable to unsubscribe.
262
+ */ const subscribeStepperToEvent = (stepperImpl, event, scheduler)=>{
263
+ const source = _getSource(event);
264
+ const sink = {
265
+ event (time, value) {
266
+ stepperImpl.value = value;
267
+ stepperImpl.time = time;
268
+ stepperImpl.generation++;
269
+ },
270
+ error () {},
271
+ end () {}
272
+ };
273
+ return source.run(sink, scheduler);
274
+ };
275
+ // --- Event ↔ Behavior Bridge ---
276
+ /**
277
+ * Create a Behavior that holds the latest value from an Event.
278
+ *
279
+ * Denotation: `stepper(init, e) = t => latestValue(e, t) ?? init`
280
+ *
281
+ * This is the primary push→pull bridge. The returned behavior is
282
+ * push-updated when the event fires, and pull-sampled when read.
283
+ *
284
+ * IMPORTANT: The caller must provide a scheduler to subscribe to the event.
285
+ * Returns [Behavior, Disposable] — the disposable unsubscribes from the event.
286
+ */ const stepper = (initial, event, scheduler)=>{
287
+ const impl = {
288
+ tag: "stepper",
289
+ initial,
290
+ value: initial,
291
+ time: scheduler.currentTime(),
292
+ generation: 0
293
+ };
294
+ const disposable = subscribeStepperToEvent(impl, event, scheduler);
295
+ return [
296
+ _createBehavior(impl),
297
+ disposable
298
+ ];
299
+ };
300
+
301
+ /**
302
+ * A Behavior holding the current mouse position.
303
+ *
304
+ * Denotation: `t => { x: mouseX(t), y: mouseY(t) }`
305
+ *
306
+ * Push-updated from mousemove events on the given target (defaults to document).
307
+ * Returns [Behavior, Disposable] — dispose to stop listening.
308
+ */ const mousePosition = (scheduler, target = document)=>{
309
+ const moves = map$1((e)=>({
310
+ x: e.clientX,
311
+ y: e.clientY
312
+ }), fromDOMEvent("mousemove", target));
313
+ return stepper({
314
+ x: 0,
315
+ y: 0
316
+ }, moves, scheduler);
317
+ };
318
+ /**
319
+ * A Behavior holding the current window dimensions.
320
+ *
321
+ * Denotation: `t => { width: innerWidth(t), height: innerHeight(t) }`
322
+ *
323
+ * Push-updated from resize events on window.
324
+ * Returns [Behavior, Disposable] — dispose to stop listening.
325
+ */ const windowSize = (scheduler)=>{
326
+ const initial = typeof window !== "undefined" ? {
327
+ width: window.innerWidth,
328
+ height: window.innerHeight
329
+ } : {
330
+ width: 0,
331
+ height: 0
332
+ };
333
+ const resizes = map$1(()=>({
334
+ width: window.innerWidth,
335
+ height: window.innerHeight
336
+ }), fromDOMEvent("resize", window));
337
+ return stepper(initial, resizes, scheduler);
338
+ };
339
+
340
+ export { animationFrames, fromDOMEvent, mousePosition, windowSize };
341
+ //# sourceMappingURL=index.js.map