@mindees/core 0.4.0 → 0.6.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":"recognizers.js","names":[],"sources":["../../src/gesture/recognizers.ts"],"sourcesContent":["/**\n * Gesture recognizers — RN Gesture Handler / Flutter GestureDetector parity, built on the reactive\n * core. Each factory returns a {@link Recognizer}: a bag of pointer-event handlers to spread onto a\n * host element, plus REACTIVE state (signals) you read in a `style` accessor or feed to the\n * animation engine. The only platform-aware code is {@link normalizePointer}; everything else is\n * pure payload → signal, so it runs on web (Pointer Events), native (the command-backend payload),\n * and tests (synthetic events), and SSRs safely (no `document` access).\n *\n * Attach two recognizers to ONE element via {@link composeGestures} — the renderer binds a single\n * listener per event name, so spreading two `onPointerMove`s would drop one; compose merges them.\n *\n * @module\n */\n\nimport { batch, signal } from '../reactive'\n\n/** A normalized pointer sample (platform differences absorbed by {@link normalizePointer}). */\nexport interface PointerSample {\n readonly pointerId: number\n readonly x: number\n readonly y: number\n /** Timestamp in ms. */\n readonly t: number\n readonly pointerType?: string\n}\n\n// --- injectable clock (deterministic longPress tests; mirrors the animation FrameSource pattern) ---\nlet nowMs = (): number => Date.now()\nlet scheduleTimer = (fn: () => void, ms: number): (() => void) => {\n const id = setTimeout(fn, ms)\n return () => clearTimeout(id)\n}\n\n/** @internal Test-only: inject a deterministic clock + timer. */\nexport function _setGestureClock(opts: {\n now?: () => number\n schedule?: (fn: () => void, ms: number) => () => void\n}): void {\n if (opts.now) nowMs = opts.now\n if (opts.schedule) scheduleTimer = opts.schedule\n}\n\n/** Normalize a host pointer event to a {@link PointerSample}. Web `PointerEvent` or a native payload. */\nexport function normalizePointer(e: unknown): PointerSample {\n const ev = (e ?? {}) as Record<string, unknown>\n const web = 'clientX' in ev // distinguishes a DOM PointerEvent from a native JSON payload\n const num = (v: unknown, d = 0): number => (typeof v === 'number' && Number.isFinite(v) ? v : d)\n return {\n pointerId: num(ev.pointerId, 1),\n x: web ? num(ev.clientX) : num(ev.x),\n y: web ? num(ev.clientY) : num(ev.y),\n t: num(web ? ev.timeStamp : ev.timestamp, nowMs()),\n ...(typeof (web ? ev.pointerType : ev.type) === 'string'\n ? { pointerType: (web ? ev.pointerType : ev.type) as string }\n : {}),\n }\n}\n\n/** Handlers to spread onto a host element. */\nexport interface GestureHandlers {\n onPointerDown(e: unknown): void\n onPointerMove(e: unknown): void\n onPointerUp(e: unknown): void\n onPointerCancel(e: unknown): void\n}\n\n/** A recognizer: handlers to attach, reactive `state`, and a `reset()` for cleanup. */\nexport interface Recognizer<S = Record<string, () => number | boolean>> {\n readonly handlers: GestureHandlers\n readonly state: S\n /** Clear pointers, timers, and reset state to rest (call from `onCleanup`). */\n reset(): void\n}\n\ninterface Tracked {\n startX: number\n startY: number\n startT: number\n x: number\n y: number\n lastX: number\n lastY: number\n lastT: number\n vx: number // EWMA velocity, px/ms\n vy: number\n}\n\nconst VEL_ALPHA = 0.6\nconst dist = (ax: number, ay: number, bx: number, by: number): number =>\n Math.hypot(ax - bx, ay - by)\n\n/** Update a tracked pointer + its EWMA velocity from a new sample. */\nfunction track(p: Tracked, s: PointerSample): void {\n const dtMs = s.t - p.lastT\n if (dtMs > 0) {\n p.vx = VEL_ALPHA * ((s.x - p.lastX) / dtMs) + (1 - VEL_ALPHA) * p.vx\n p.vy = VEL_ALPHA * ((s.y - p.lastY) / dtMs) + (1 - VEL_ALPHA) * p.vy\n }\n p.lastX = s.x\n p.lastY = s.y\n p.lastT = s.t\n p.x = s.x\n p.y = s.y\n}\n\nfunction newTracked(s: PointerSample): Tracked {\n return {\n startX: s.x,\n startY: s.y,\n startT: s.t,\n x: s.x,\n y: s.y,\n lastX: s.x,\n lastY: s.y,\n lastT: s.t,\n vx: 0,\n vy: 0,\n }\n}\n\n// --- Pan (drag) -----------------------------------------------------------------------------------\n\n/** A continuous pan/drag update (translations relative to gesture start; velocity in px/ms). */\nexport interface PanEvent {\n readonly translationX: number\n readonly translationY: number\n readonly velocityX: number\n readonly velocityY: number\n readonly x: number\n readonly y: number\n}\n\nexport interface PanState {\n readonly active: () => boolean\n readonly translationX: () => number\n readonly translationY: () => number\n readonly velocityX: () => number\n readonly velocityY: () => number\n readonly x: () => number\n readonly y: () => number\n}\n\n/** Recognize a drag. Becomes active once the pointer moves past `minDistance` (slop). */\nexport function pan(config: {\n onBegin?: (e: PanEvent) => void\n onUpdate?: (e: PanEvent) => void\n onEnd?: (e: PanEvent & { completed: boolean }) => void\n minDistance?: number\n axis?: 'both' | 'x' | 'y'\n}): Recognizer<PanState> {\n const minDistance = config.minDistance ?? 10\n const axis = config.axis ?? 'both'\n const pointers = new Map<number, Tracked>()\n let id: number | null = null // the claimed pointer\n let active = false\n const active$ = signal(false)\n const tx$ = signal(0)\n const ty$ = signal(0)\n const vx$ = signal(0)\n const vy$ = signal(0)\n const x$ = signal(0)\n const y$ = signal(0)\n\n const filt = (dx: number, dy: number): [number, number] =>\n axis === 'x' ? [dx, 0] : axis === 'y' ? [0, dy] : [dx, dy]\n\n const eventFor = (p: Tracked): PanEvent => {\n const [tx, ty] = filt(p.x - p.startX, p.y - p.startY)\n const [vx, vy] = filt(p.vx, p.vy)\n return { translationX: tx, translationY: ty, velocityX: vx, velocityY: vy, x: p.x, y: p.y }\n }\n const writeFrom = (p: Tracked): void => {\n const e = eventFor(p)\n tx$.set(e.translationX)\n ty$.set(e.translationY)\n vx$.set(e.velocityX)\n vy$.set(e.velocityY)\n x$.set(e.x)\n y$.set(e.y)\n }\n\n const reset = (): void => {\n pointers.clear()\n id = null\n active = false\n batch(() => {\n active$.set(false)\n tx$.set(0)\n ty$.set(0)\n vx$.set(0)\n vy$.set(0)\n })\n }\n\n return {\n state: {\n active: () => active$(),\n translationX: () => tx$(),\n translationY: () => ty$(),\n velocityX: () => vx$(),\n velocityY: () => vy$(),\n x: () => x$(),\n y: () => y$(),\n },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pointers.set(s.pointerId, newTracked(s))\n if (id === null) id = s.pointerId\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (!p) return\n track(p, s)\n if (s.pointerId !== id) return\n // Slop on the AXIS-FILTERED delta: an `axis: 'y'` pan must not activate on horizontal travel.\n const [sx, sy] = filt(p.x - p.startX, p.y - p.startY)\n const slop = Math.hypot(sx, sy)\n batch(() => {\n if (!active && slop >= minDistance) {\n active = true\n active$.set(true)\n writeFrom(p)\n config.onBegin?.(eventFor(p))\n } else if (active) {\n writeFrom(p)\n config.onUpdate?.(eventFor(p))\n }\n })\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) track(p, s)\n if (s.pointerId === id && active && p) {\n config.onEnd?.({ ...eventFor(p), completed: true })\n }\n pointers.delete(s.pointerId)\n if (s.pointerId === id) {\n id = pointers.keys().next().value ?? null\n active = false\n active$.set(false)\n }\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (s.pointerId === id && active && p) {\n config.onEnd?.({ ...eventFor(p), completed: false })\n }\n pointers.delete(s.pointerId)\n if (s.pointerId === id) {\n // Hand off to another still-down pointer (mirror onPointerUp) so it can re-claim the pan.\n id = pointers.keys().next().value ?? null\n active = false\n active$.set(false)\n }\n },\n },\n }\n}\n\n// --- Tap ------------------------------------------------------------------------------------------\n\nexport interface TapState {\n readonly active: () => boolean\n}\n\n/** Recognize a tap: down + up within `maxDistance` and `maxDurationMs`, no extra pointer. */\nexport function tap(config: {\n onTap?: () => void\n maxDistance?: number\n maxDurationMs?: number\n}): Recognizer<TapState> {\n const maxDistance = config.maxDistance ?? 10\n const maxDurationMs = config.maxDurationMs ?? 500\n let down: PointerSample | null = null\n let failed = false\n const active$ = signal(false)\n const reset = (): void => {\n down = null\n failed = false\n active$.set(false)\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n if (down !== null) {\n failed = true // a second pointer fails a tap\n return\n }\n down = normalizePointer(e)\n failed = false\n active$.set(true)\n },\n onPointerMove(e): void {\n if (!down || failed) return\n const s = normalizePointer(e)\n if (s.pointerId === down.pointerId && dist(s.x, s.y, down.x, down.y) > maxDistance) {\n failed = true\n active$.set(false)\n }\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n if (down && !failed && s.pointerId === down.pointerId) {\n const within =\n dist(s.x, s.y, down.x, down.y) <= maxDistance && s.t - down.t <= maxDurationMs\n if (within) config.onTap?.()\n }\n if (!down || s.pointerId === down.pointerId) reset() // ignore a foreign pointer's cancel/up\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n if (!down || s.pointerId === down.pointerId) reset() // a foreign pointer must not kill our tap\n },\n },\n }\n}\n\n// --- Long press -----------------------------------------------------------------------------------\n\n/** Recognize a long press: pointer held past `minDurationMs` without moving past `maxDistance`. */\nexport function longPress(config: {\n onBegin?: () => void\n onLongPress?: () => void\n onEnd?: () => void\n minDurationMs?: number\n maxDistance?: number\n}): Recognizer<TapState> {\n const minDurationMs = config.minDurationMs ?? 500\n const maxDistance = config.maxDistance ?? 10\n let down: PointerSample | null = null\n let cancelTimer: (() => void) | null = null\n let fired = false\n const active$ = signal(false)\n const clear = (): void => {\n cancelTimer?.()\n cancelTimer = null\n }\n const reset = (): void => {\n clear()\n down = null\n fired = false\n active$.set(false)\n }\n /** End the press, firing onEnd iff the long-press had fired, then reset. */\n const finish = (): void => {\n if (fired) config.onEnd?.()\n reset()\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n if (down !== null) return\n down = normalizePointer(e)\n fired = false\n active$.set(true)\n config.onBegin?.()\n cancelTimer = scheduleTimer(() => {\n fired = true\n config.onLongPress?.()\n }, minDurationMs)\n },\n onPointerMove(e): void {\n if (!down) return\n const s = normalizePointer(e)\n if (s.pointerId === down.pointerId && dist(s.x, s.y, down.x, down.y) > maxDistance) {\n finish() // slop exceeded → end (onEnd iff it had fired), then fail\n }\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n if (down && s.pointerId === down.pointerId) finish()\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n if (!down || s.pointerId === down.pointerId) finish()\n },\n },\n }\n}\n\n// --- Pinch (scale) --------------------------------------------------------------------------------\n\nexport interface PinchEvent {\n readonly scale: number\n readonly velocity: number\n readonly focalX: number\n readonly focalY: number\n}\nexport interface PinchState {\n readonly active: () => boolean\n readonly scale: () => number\n readonly focalX: () => number\n readonly focalY: () => number\n}\n\n/** Recognize a two-finger pinch. `scale` is current distance / start distance between the pinned pair. */\nexport function pinch(config: {\n onBegin?: (e: PinchEvent) => void\n onUpdate?: (e: PinchEvent) => void\n onEnd?: (e: PinchEvent) => void\n}): Recognizer<PinchState> {\n const pts = new Map<number, PointerSample>()\n let pair: [number, number] | null = null\n let startDist = 0\n let lastScale = 1\n let lastT = 0\n const active$ = signal(false)\n const scale$ = signal(1)\n const fx$ = signal(0)\n const fy$ = signal(0)\n\n const pairPts = (): [PointerSample, PointerSample] | null => {\n if (!pair) return null\n const a = pts.get(pair[0])\n const b = pts.get(pair[1])\n return a && b ? [a, b] : null\n }\n const eventNow = (a: PointerSample, b: PointerSample, t: number): PinchEvent => {\n const d = dist(a.x, a.y, b.x, b.y)\n const scale = startDist > 0 ? d / startDist : 1\n const dt = t - lastT\n const velocity = dt > 0 ? (scale - lastScale) / dt : 0\n lastScale = scale\n lastT = t\n return { scale, velocity, focalX: (a.x + b.x) / 2, focalY: (a.y + b.y) / 2 }\n }\n const reset = (): void => {\n pts.clear()\n pair = null\n startDist = 0\n lastScale = 1\n batch(() => {\n active$.set(false)\n scale$.set(1)\n fx$.set(0)\n fy$.set(0)\n })\n }\n const begin = (): void => {\n const pp = pairPts()\n if (!pp) return\n startDist = dist(pp[0].x, pp[0].y, pp[1].x, pp[1].y)\n lastScale = 1\n lastT = Math.max(pp[0].t, pp[1].t)\n const focalX = (pp[0].x + pp[1].x) / 2\n const focalY = (pp[0].y + pp[1].y) / 2\n batch(() => {\n active$.set(true)\n scale$.set(1)\n fx$.set(focalX) // seed focal so a style reading focalX/Y is correct from the first frame\n fy$.set(focalY)\n })\n config.onBegin?.({ scale: 1, velocity: 0, focalX, focalY })\n }\n /** A pointer left: if it was a pinned finger but ≥2 remain, re-pin survivors continuously; else end. */\n const onLift = (s: PointerSample): void => {\n pts.delete(s.pointerId)\n if (!active$() || !pair) return\n const wasPinned = s.pointerId === pair[0] || s.pointerId === pair[1]\n if (!wasPinned) return // a non-pinned finger lifted — pinch continues unaffected\n if (pts.size >= 2) {\n const ids = [...pts.keys()]\n pair = [ids[0] as number, ids[1] as number]\n const pp = pairPts()\n if (pp) {\n // Re-base so dist/startDist keeps equalling the CURRENT scale (no jump on the next move).\n const d = dist(pp[0].x, pp[0].y, pp[1].x, pp[1].y)\n startDist = d / Math.max(scale$(), 1e-4)\n lastScale = scale$()\n }\n return\n }\n config.onEnd?.({ scale: scale$(), velocity: 0, focalX: fx$(), focalY: fy$() })\n reset()\n }\n return {\n state: {\n active: () => active$(),\n scale: () => scale$(),\n focalX: () => fx$(),\n focalY: () => fy$(),\n },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pts.set(s.pointerId, s)\n if (!pair && pts.size >= 2) {\n const ids = [...pts.keys()]\n pair = [ids[0] as number, ids[1] as number]\n begin()\n }\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n if (!pts.has(s.pointerId)) return\n pts.set(s.pointerId, s)\n const pp = pairPts()\n if (!active$() || !pp) return\n const ev = eventNow(pp[0], pp[1], s.t)\n batch(() => {\n scale$.set(ev.scale)\n fx$.set(ev.focalX)\n fy$.set(ev.focalY)\n })\n config.onUpdate?.(ev)\n },\n onPointerUp(e): void {\n onLift(normalizePointer(e))\n },\n onPointerCancel(e): void {\n onLift(normalizePointer(e))\n },\n },\n }\n}\n\n// --- Swipe ----------------------------------------------------------------------------------------\n\nexport type SwipeDirection = 'left' | 'right' | 'up' | 'down'\nexport interface SwipeEvent {\n readonly direction: SwipeDirection\n readonly velocityX: number\n readonly velocityY: number\n readonly x: number\n readonly y: number\n}\n\n/** Recognize a fast flick on pointer-up (velocity ≥ `minVelocity` px/ms over `minDistance`). */\nexport function swipe(config: {\n onSwipe?: (e: SwipeEvent) => void\n direction?: 'any' | SwipeDirection\n minVelocity?: number\n minDistance?: number\n}): Recognizer<TapState> {\n const want = config.direction ?? 'any'\n const minVelocity = config.minVelocity ?? 0.3\n const minDistance = config.minDistance ?? 30\n const pointers = new Map<number, Tracked>()\n const active$ = signal(false)\n const reset = (): void => {\n pointers.clear()\n active$.set(false)\n }\n const dominant = (p: Tracked): SwipeDirection => {\n const dx = p.x - p.startX\n const dy = p.y - p.startY\n if (Math.abs(dx) >= Math.abs(dy)) return dx >= 0 ? 'right' : 'left'\n return dy >= 0 ? 'down' : 'up'\n }\n return {\n state: { active: () => active$() },\n reset,\n handlers: {\n onPointerDown(e): void {\n const s = normalizePointer(e)\n pointers.set(s.pointerId, newTracked(s))\n active$.set(true)\n },\n onPointerMove(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) track(p, s)\n },\n onPointerUp(e): void {\n const s = normalizePointer(e)\n const p = pointers.get(s.pointerId)\n if (p) {\n track(p, s)\n const speed = Math.hypot(p.vx, p.vy)\n const moved = dist(p.x, p.y, p.startX, p.startY)\n const dir = dominant(p)\n if (speed >= minVelocity && moved >= minDistance && (want === 'any' || want === dir)) {\n config.onSwipe?.({ direction: dir, velocityX: p.vx, velocityY: p.vy, x: p.x, y: p.y })\n }\n }\n pointers.delete(s.pointerId) // per-pointer: another finger can still produce its own swipe\n if (pointers.size === 0) active$.set(false)\n },\n onPointerCancel(e): void {\n const s = normalizePointer(e)\n pointers.delete(s.pointerId)\n if (pointers.size === 0) active$.set(false)\n },\n },\n }\n}\n\n// --- Composition ----------------------------------------------------------------------------------\n\n/**\n * Merge several recognizers into ONE so they can attach to a single element — required because the\n * renderer binds a single listener per event name (spreading two `onPointerMove`s would drop one).\n * `simultaneous` (the default): every recognizer sees every event independently (e.g. pan + pinch\n * together). Per-recognizer slop already disambiguates tap-vs-pan; an explicit exclusive arena is a\n * follow-up.\n */\nexport function composeGestures(recognizers: readonly Recognizer<never>[]): Recognizer<never> {\n const fan =\n (key: keyof GestureHandlers) =>\n (e: unknown): void => {\n let firstError: unknown\n batch(() => {\n // Isolate each recognizer: one throwing must not skip the rest (e.g. leaving a sibling's\n // long-press timer armed). Collect the first error and rethrow after all have run.\n for (const r of recognizers) {\n try {\n r.handlers[key](e)\n } catch (err) {\n if (firstError === undefined) firstError = err\n }\n }\n })\n if (firstError !== undefined) throw firstError\n }\n return {\n state: {} as never,\n reset: () => {\n for (const r of recognizers) r.reset()\n },\n handlers: {\n onPointerDown: fan('onPointerDown'),\n onPointerMove: fan('onPointerMove'),\n onPointerUp: fan('onPointerUp'),\n onPointerCancel: fan('onPointerCancel'),\n },\n }\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,16 +1,20 @@
1
1
  import { Maturity, PackageInfo } from "./types.js";
2
+ import { Easing, cubicBezier, easeInOutQuad, easeInQuad, easeOutCubic, easeOutQuad, linear } from "./animation/easing.js";
3
+ import { AnimatedValue, AnimationHandle, FrameSource, _activeAnimationCount, _resetAnimation, animate, getFrameSource, interpolate, manualFrameSource, rafFrameSource, setFrameSource, spring, timing } from "./animation/animation.js";
2
4
  import { Component, Context, ContextProvider, ELEMENT_TYPE, ElementType, Fragment, KEYED_REGION, KeyedRegion, KeyedRegionOptions, MindeesElement, MindeesNode, PORTAL, PortalRegion, SelectorEquals, createContext, createElement, createProvider, hasOwner, isElement, isKeyedRegion, isPortal, keyedRegion, portal, renderComponent } from "./component/component.js";
3
5
  import { NotImplementedError } from "./errors.js";
6
+ import { GestureHandlers, PanEvent, PanState, PinchEvent, PinchState, PointerSample, Recognizer, SwipeDirection, SwipeEvent, TapState, _setGestureClock, composeGestures, longPress, normalizePointer, pan, pinch, swipe, tap } from "./gesture/recognizers.js";
7
+ import { panAnimated } from "./gesture/animated.js";
4
8
  import { notImplemented } from "./not-implemented.js";
5
- import { Accessor, ComputedOptions, EqualsFn, Memo, Owner, Signal, SignalOptions, batch, computed, createRoot, effect, getOwner, memo, onCleanup, runWithOwner, signal, untrack } from "./reactive/reactive.js";
6
9
  import { Priority, ScheduleOptions, ScheduledTask, Scheduler, SchedulerOptions, Task, createScheduler } from "./scheduler/scheduler.js";
10
+ import { Accessor, ComputedOptions, EffectOptions, EqualsFn, Memo, Owner, Signal, SignalOptions, batch, computed, createRoot, deferred, effect, getOwner, memo, onCleanup, runWithOwner, setReactiveScheduler, signal, startTransition, untrack } from "./reactive/reactive.js";
7
11
  import { ThreadPool, WorkerLike, WorkerPoolOptions, createInlineThreadPool, createNativeThreadPool, createWorkerPool } from "./threading/thread-pool.js";
8
12
 
9
13
  //#region src/index.d.ts
10
14
  /** The npm package name. */
11
15
  declare const name = "@mindees/core";
12
16
  /** The package version. All `@mindees/*` packages share one locked version line. */
13
- declare const VERSION = "0.4.0";
17
+ declare const VERSION = "0.6.0";
14
18
  /**
15
19
  * Current maturity of this package. See the repository `STATUS.md`.
16
20
  *
@@ -27,5 +31,5 @@ declare const maturity: Maturity;
27
31
  */
28
32
  declare const info: PackageInfo;
29
33
  //#endregion
30
- export { type Accessor, type Component, type ComputedOptions, type Context, type ContextProvider, ELEMENT_TYPE, type ElementType, type EqualsFn, Fragment, KEYED_REGION, type KeyedRegion, type KeyedRegionOptions, type Maturity, type Memo, type MindeesElement, type MindeesNode, NotImplementedError, type Owner, PORTAL, type PackageInfo, type PortalRegion, type Priority, type ScheduleOptions, type ScheduledTask, Scheduler, type SchedulerOptions, type SelectorEquals, type Signal, type SignalOptions, type Task, type ThreadPool, VERSION, type WorkerLike, type WorkerPoolOptions, batch, computed, createContext, createElement, createInlineThreadPool, createNativeThreadPool, createProvider, createRoot, createScheduler, createWorkerPool, effect, getOwner, hasOwner, info, isElement, isKeyedRegion, isPortal, keyedRegion, maturity, memo, name, notImplemented, onCleanup, portal, renderComponent, runWithOwner, signal, untrack };
34
+ export { type Accessor, type AnimatedValue, type AnimationHandle, type Component, type ComputedOptions, type Context, type ContextProvider, ELEMENT_TYPE, type Easing, type EffectOptions, type ElementType, type EqualsFn, Fragment, type FrameSource, type GestureHandlers, KEYED_REGION, type KeyedRegion, type KeyedRegionOptions, type Maturity, type Memo, type MindeesElement, type MindeesNode, NotImplementedError, type Owner, PORTAL, type PackageInfo, type PanEvent, type PanState, type PinchEvent, type PinchState, type PointerSample, type PortalRegion, type Priority, type Recognizer, type ScheduleOptions, type ScheduledTask, Scheduler, type SchedulerOptions, type SelectorEquals, type Signal, type SignalOptions, type SwipeDirection, type SwipeEvent, type TapState, type Task, type ThreadPool, VERSION, type WorkerLike, type WorkerPoolOptions, _activeAnimationCount, _resetAnimation, _setGestureClock, animate, batch, composeGestures, computed, createContext, createElement, createInlineThreadPool, createNativeThreadPool, createProvider, createRoot, createScheduler, createWorkerPool, cubicBezier, deferred, easeInOutQuad, easeInQuad, easeOutCubic, easeOutQuad, effect, getFrameSource, getOwner, hasOwner, info, interpolate, isElement, isKeyedRegion, isPortal, keyedRegion, linear, longPress, manualFrameSource, maturity, memo, name, normalizePointer, notImplemented, onCleanup, pan, panAnimated, pinch, portal, rafFrameSource, renderComponent, runWithOwner, setFrameSource, setReactiveScheduler, signal, spring, startTransition, swipe, tap, timing, untrack };
31
35
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;AAyGA;AAAA,cApBa,IAAA;;cAGA,OAAA;AAiBuE;;;;;;;;AAAA,cAPvE,QAAA,EAAU,QAAyB;;;;;;cAOnC,IAAA,EAAM,WAAiE"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;cA4Ia,IAAA;;cAGA,OAAA;;;;;;;;;cAUA,QAAA,EAAU,QAAyB;;;;;;cAOnC,IAAA,EAAM,WAAiE"}
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
- import { batch, computed, createRoot, effect, getOwner, memo, onCleanup, runWithOwner, signal, untrack } from "./reactive/reactive.js";
1
+ import { batch, computed, createRoot, deferred, effect, getOwner, memo, onCleanup, runWithOwner, setReactiveScheduler, signal, startTransition, untrack } from "./reactive/reactive.js";
2
+ import { cubicBezier, easeInOutQuad, easeInQuad, easeOutCubic, easeOutQuad, linear } from "./animation/easing.js";
3
+ import { _activeAnimationCount, _resetAnimation, animate, getFrameSource, interpolate, manualFrameSource, rafFrameSource, setFrameSource, spring, timing } from "./animation/animation.js";
2
4
  import { ELEMENT_TYPE, Fragment, KEYED_REGION, PORTAL, createContext, createElement, createProvider, hasOwner, isElement, isKeyedRegion, isPortal, keyedRegion, portal, renderComponent } from "./component/component.js";
3
5
  import { NotImplementedError } from "./errors.js";
6
+ import { _setGestureClock, composeGestures, longPress, normalizePointer, pan, pinch, swipe, tap } from "./gesture/recognizers.js";
7
+ import { panAnimated } from "./gesture/animated.js";
4
8
  import { notImplemented } from "./not-implemented.js";
5
9
  import { Scheduler, createScheduler } from "./scheduler/scheduler.js";
6
10
  import { createInlineThreadPool, createNativeThreadPool, createWorkerPool } from "./threading/thread-pool.js";
@@ -8,7 +12,7 @@ import { createInlineThreadPool, createNativeThreadPool, createWorkerPool } from
8
12
  /** The npm package name. */
9
13
  const name = "@mindees/core";
10
14
  /** The package version. All `@mindees/*` packages share one locked version line. */
11
- const VERSION = "0.4.0";
15
+ const VERSION = "0.6.0";
12
16
  /**
13
17
  * Current maturity of this package. See the repository `STATUS.md`.
14
18
  *
@@ -29,6 +33,6 @@ const info = Object.freeze({
29
33
  maturity
30
34
  });
31
35
  //#endregion
32
- export { ELEMENT_TYPE, Fragment, KEYED_REGION, NotImplementedError, PORTAL, Scheduler, VERSION, batch, computed, createContext, createElement, createInlineThreadPool, createNativeThreadPool, createProvider, createRoot, createScheduler, createWorkerPool, effect, getOwner, hasOwner, info, isElement, isKeyedRegion, isPortal, keyedRegion, maturity, memo, name, notImplemented, onCleanup, portal, renderComponent, runWithOwner, signal, untrack };
36
+ export { ELEMENT_TYPE, Fragment, KEYED_REGION, NotImplementedError, PORTAL, Scheduler, VERSION, _activeAnimationCount, _resetAnimation, _setGestureClock, animate, batch, composeGestures, computed, createContext, createElement, createInlineThreadPool, createNativeThreadPool, createProvider, createRoot, createScheduler, createWorkerPool, cubicBezier, deferred, easeInOutQuad, easeInQuad, easeOutCubic, easeOutQuad, effect, getFrameSource, getOwner, hasOwner, info, interpolate, isElement, isKeyedRegion, isPortal, keyedRegion, linear, longPress, manualFrameSource, maturity, memo, name, normalizePointer, notImplemented, onCleanup, pan, panAnimated, pinch, portal, rafFrameSource, renderComponent, runWithOwner, setFrameSource, setReactiveScheduler, signal, spring, startTransition, swipe, tap, timing, untrack };
33
37
 
34
38
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Maturity, PackageInfo } from './types'\n\n/**\n * Component model: a renderer-agnostic element tree plus selector-based,\n * re-render-isolated context. (Phase 2)\n */\nexport {\n type Component,\n type Context,\n type ContextProvider,\n createContext,\n createElement,\n createProvider,\n ELEMENT_TYPE,\n type ElementType,\n Fragment,\n hasOwner,\n isElement,\n isKeyedRegion,\n isPortal,\n KEYED_REGION,\n type KeyedRegion,\n type KeyedRegionOptions,\n keyedRegion,\n type MindeesElement,\n type MindeesNode,\n PORTAL,\n type PortalRegion,\n portal,\n renderComponent,\n type SelectorEquals,\n} from './component'\nexport { NotImplementedError } from './errors'\nexport { notImplemented } from './not-implemented'\n/**\n * Fine-grained reactivity: signals, computed values, effects, batching, and\n * disposal scopes. This is the reactive core of MindeesNative.\n */\nexport {\n type Accessor,\n batch,\n type ComputedOptions,\n computed,\n createRoot,\n type EqualsFn,\n effect,\n getOwner,\n type Memo,\n memo,\n type Owner,\n onCleanup,\n runWithOwner,\n type Signal,\n type SignalOptions,\n signal,\n untrack,\n} from './reactive'\n/**\n * Priority scheduler: two-lane (sync/normal), microtask-batched, with\n * cancellable and dedupable tasks. (Phase 2)\n */\nexport {\n createScheduler,\n type Priority,\n type ScheduledTask,\n type ScheduleOptions,\n Scheduler,\n type SchedulerOptions,\n type Task,\n} from './scheduler'\n/**\n * Threading abstraction: a {@link ThreadPool} contract with a working Web Worker\n * backend and an inline fallback. Native multi-threading is a research track. (Phase 2)\n */\nexport {\n createInlineThreadPool,\n createNativeThreadPool,\n createWorkerPool,\n type ThreadPool,\n type WorkerLike,\n type WorkerPoolOptions,\n} from './threading'\nexport type { Maturity, PackageInfo } from './types'\n\n/** The npm package name. */\nexport const name = '@mindees/core'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.4.0'\n\n/**\n * Current maturity of this package. See the repository `STATUS.md`.\n *\n * The reactivity layer (signals/computed/effect/batch), the component model with\n * selector-isolated context, the priority scheduler, and the thread-pool\n * abstraction (Web Worker + inline) are all implemented and tested. Native\n * multi-threading remains a research track (throws `NotImplementedError`).\n */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n"],"mappings":";;;;;;;;AAqFA,MAAa,OAAO;;AAGpB,MAAa,UAAU;;;;;;;;;AAUvB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Maturity, PackageInfo } from './types'\n\n/**\n * Animation engine: reactive animated values + timing/spring drivers + interpolate, driven by an\n * injected frame source (RN Animated/Reanimated + Flutter AnimationController parity).\n */\nexport {\n _activeAnimationCount,\n _resetAnimation,\n type AnimatedValue,\n type AnimationHandle,\n animate,\n cubicBezier,\n type Easing,\n easeInOutQuad,\n easeInQuad,\n easeOutCubic,\n easeOutQuad,\n type FrameSource,\n getFrameSource,\n interpolate,\n linear,\n manualFrameSource,\n rafFrameSource,\n setFrameSource,\n spring,\n timing,\n} from './animation'\n/**\n * Component model: a renderer-agnostic element tree plus selector-based,\n * re-render-isolated context. (Phase 2)\n */\nexport {\n type Component,\n type Context,\n type ContextProvider,\n createContext,\n createElement,\n createProvider,\n ELEMENT_TYPE,\n type ElementType,\n Fragment,\n hasOwner,\n isElement,\n isKeyedRegion,\n isPortal,\n KEYED_REGION,\n type KeyedRegion,\n type KeyedRegionOptions,\n keyedRegion,\n type MindeesElement,\n type MindeesNode,\n PORTAL,\n type PortalRegion,\n portal,\n renderComponent,\n type SelectorEquals,\n} from './component'\nexport { NotImplementedError } from './errors'\n/**\n * Gesture recognizers: tap/longPress/pan/pinch/swipe → reactive state that drives styles and the\n * animation engine (RN Gesture Handler / Flutter GestureDetector parity).\n */\nexport {\n _setGestureClock,\n composeGestures,\n type GestureHandlers,\n longPress,\n normalizePointer,\n type PanEvent,\n type PanState,\n type PinchEvent,\n type PinchState,\n type PointerSample,\n pan,\n panAnimated,\n pinch,\n type Recognizer,\n type SwipeDirection,\n type SwipeEvent,\n swipe,\n type TapState,\n tap,\n} from './gesture'\nexport { notImplemented } from './not-implemented'\n/**\n * Fine-grained reactivity: signals, computed values, effects, batching, and\n * disposal scopes. This is the reactive core of MindeesNative.\n */\nexport {\n type Accessor,\n batch,\n type ComputedOptions,\n computed,\n createRoot,\n deferred,\n type EffectOptions,\n type EqualsFn,\n effect,\n getOwner,\n type Memo,\n memo,\n type Owner,\n onCleanup,\n runWithOwner,\n type Signal,\n type SignalOptions,\n setReactiveScheduler,\n signal,\n startTransition,\n untrack,\n} from './reactive'\n/**\n * Priority scheduler: two-lane (sync/normal), microtask-batched, with\n * cancellable and dedupable tasks. (Phase 2)\n */\nexport {\n createScheduler,\n type Priority,\n type ScheduledTask,\n type ScheduleOptions,\n Scheduler,\n type SchedulerOptions,\n type Task,\n} from './scheduler'\n/**\n * Threading abstraction: a {@link ThreadPool} contract with a working Web Worker\n * backend and an inline fallback. Native multi-threading is a research track. (Phase 2)\n */\nexport {\n createInlineThreadPool,\n createNativeThreadPool,\n createWorkerPool,\n type ThreadPool,\n type WorkerLike,\n type WorkerPoolOptions,\n} from './threading'\nexport type { Maturity, PackageInfo } from './types'\n\n/** The npm package name. */\nexport const name = '@mindees/core'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.6.0'\n\n/**\n * Current maturity of this package. See the repository `STATUS.md`.\n *\n * The reactivity layer (signals/computed/effect/batch), the component model with\n * selector-isolated context, the priority scheduler, and the thread-pool\n * abstraction (Web Worker + inline) are all implemented and tested. Native\n * multi-threading remains a research track (throws `NotImplementedError`).\n */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n"],"mappings":";;;;;;;;;;;;AA4IA,MAAa,OAAO;;AAGpB,MAAa,UAAU;;;;;;;;;AAUvB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
@@ -1,23 +1,6 @@
1
+ import { Priority, Scheduler } from "../scheduler/scheduler.js";
2
+
1
3
  //#region src/reactive/reactive.d.ts
2
- /**
3
- * MindeesNative reactivity — fine-grained, glitch-free, lazy signals.
4
- *
5
- * Algorithm: push–pull with graph coloring (`CLEAN` / `CHECK` / `DIRTY`), in the
6
- * lineage of SolidJS and the "reactively" library. A write *pushes* staleness
7
- * markers through the observer graph; a read *pulls*, recomputing a node only
8
- * when one of its sources actually changed. This guarantees:
9
- *
10
- * - **Glitch freedom** — no observer ever sees an inconsistent intermediate
11
- * state (the classic diamond dependency recomputes its consumer exactly once).
12
- * - **No redundant recomputation** — a node recomputes at most once per change,
13
- * and an equal recomputation does not propagate to its observers.
14
- * - **Deterministic, synchronous propagation** — effects run in a predictable
15
- * order, batched to the end of the outermost write/batch.
16
- * - **Complete disposal** — disposing an owner unlinks every subscription, so
17
- * there are no leaked observers.
18
- *
19
- * @module
20
- */
21
4
  /** @internal Phantom brand making {@link Owner} nominal — see below. */
22
5
  declare const OWNER_BRAND: unique symbol;
23
6
  /**
@@ -40,6 +23,12 @@ interface Owner {
40
23
  }
41
24
  /** Equality comparator used to decide whether a value actually changed. */
42
25
  type EqualsFn<T> = (a: T, b: T) => boolean;
26
+ /**
27
+ * Inject (or clear) the {@link Scheduler} that `effect(fn, { priority: 'normal' })` defers through.
28
+ * With no scheduler (the default), `'normal'`-lane effects flush synchronously — so behavior is
29
+ * identical to today until a host wires one in. Pass `null` to detach.
30
+ */
31
+ declare function setReactiveScheduler(scheduler: Scheduler | null): void;
43
32
  /** A read accessor for a derived/reactive value. */
44
33
  type Accessor<T> = () => T;
45
34
  /** Options accepted by {@link signal}. */
@@ -112,7 +101,35 @@ declare const memo: typeof computed;
112
101
  * return () => clearInterval(id) // cleanup
113
102
  * })
114
103
  */
115
- declare function effect(fn: () => void): () => void;
104
+ /** Options for {@link effect}. */
105
+ interface EffectOptions {
106
+ /**
107
+ * `'sync'` (default) flushes the effect inline on every change — the synchronous, glitch-free
108
+ * behavior. `'normal'` defers the effect through the injected {@link setReactiveScheduler scheduler}
109
+ * (interaction priority / deferred heavy work); with no scheduler it falls back to synchronous.
110
+ */
111
+ priority?: Priority;
112
+ }
113
+ declare function effect(fn: () => void, options?: EffectOptions): () => void;
114
+ /**
115
+ * Apply the writes in `fn` as a low-priority **transition**: the writes take effect immediately
116
+ * (reads inside/after see the latest values), but the effects they invalidate are **deferred**
117
+ * through the injected {@link setReactiveScheduler scheduler} instead of running synchronously — so a
118
+ * heavy re-render triggered by, say, a keystroke doesn't block the interaction. With no scheduler
119
+ * injected, this is a plain synchronous batch (no deferral) — safe for SSR/tests.
120
+ *
121
+ * @example
122
+ * input.set(value) // urgent: the field updates now
123
+ * startTransition(() => query.set(value)) // the expensive results re-render can lag
124
+ */
125
+ declare function startTransition(fn: () => void): void;
126
+ /**
127
+ * A **deferred view** of `source`: it tracks `source` on the scheduler's low-priority lane, so under
128
+ * sustained updates it lags behind the live value (the React `useDeferredValue` pattern — show stale
129
+ * results while the latest are computed). With no scheduler injected it mirrors `source`
130
+ * synchronously (no lag), so SSR/tests see the live value. Must be created inside an owner.
131
+ */
132
+ declare function deferred<T>(source: Accessor<T>): Accessor<T>;
116
133
  /**
117
134
  * Batch multiple writes so dependent effects run once, after the batch. Reads
118
135
  * inside a batch still observe the latest written values synchronously.
@@ -142,5 +159,5 @@ declare function getOwner(): Owner | null;
142
159
  /** Run `fn` with `owner` as the active scope (e.g. to re-attach cleanups). */
143
160
  declare function runWithOwner<T>(owner: Owner | null, fn: () => T): T;
144
161
  //#endregion
145
- export { Accessor, ComputedOptions, EqualsFn, Memo, Owner, Signal, SignalOptions, batch, computed, createRoot, effect, getOwner, memo, onCleanup, runWithOwner, signal, untrack };
162
+ export { Accessor, ComputedOptions, EffectOptions, EqualsFn, Memo, Owner, Signal, SignalOptions, batch, computed, createRoot, deferred, effect, getOwner, memo, onCleanup, runWithOwner, setReactiveScheduler, signal, startTransition, untrack };
146
163
  //# sourceMappingURL=reactive.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.d.ts","names":[],"sources":["../../src/reactive/reactive.ts"],"mappings":";;;;;;AAsCwC;AAgBxC;;;;AAEuB;AAcvB;;;;;;;;;cAhCc,WAAA;AAgCuB;AA2WrC;;;;AAAiC;AAGjC;;;;;;;;AA9WqC,UAhBpB,KAAA;EAgYI;EAAA,UA9XT,WAAW;AAAA;;KAcX,QAAA,OAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC;;KA2WzB,QAAA,YAAoB,CAAC;;UAGhB,aAAA;EAcN;EAZT,MAAA,GAAS,QAAQ,CAAC,CAAA;AAAA;;UAIH,MAAA;EAIJ;EAAA,IAFP,CAAA;EAEW;EAAf,GAAA,CAAI,KAAA,EAAO,CAAA,GAAI,CAAA;EAEG;EAAlB,MAAA,CAAO,EAAA,GAAK,IAAA,EAAM,CAAA,KAAM,CAAA,GAAI,CAAA;EAAJ;EAExB,IAAA,IAAQ,CAAA;AAAA;;UAIO,eAAA;EAJN;EAMT,MAAA,GAAS,QAAQ,CAAC,CAAA;AAAA;;UAIH,IAAA;EAJE;EAAA,IAMb,CAAA;EANJ;EAQA,IAAA,IAAQ,CAAC;AAAA;;AARU;AAIrB;;;;;;;iBAgBgB,MAAA,IAAU,KAAA,EAAO,CAAA,EAAG,OAAA,GAAU,aAAA,CAAc,CAAA,IAAK,MAAA,CAAO,CAAA;;AAZ7D;AAYX;;;;;;iBAiBgB,QAAA,IAAY,EAAA,QAAU,CAAA,EAAG,OAAA,GAAU,eAAA,CAAgB,CAAA,IAAK,IAAA,CAAK,CAAA;;cAYhE,IAAA,SAAI,QAAW;;;;;;;;;;;AA7B6C;AAiBzE;;;;;;;;;;iBAmCgB,MAAA,CAAO,EAAc;;;;;iBAmBrB,KAAA,IAAS,EAAA,QAAU,CAAA,GAAI,CAAC;;iBAYxB,OAAA,IAAW,EAAA,QAAU,CAAA,GAAI,CAAC;;AAlEoC;AAY9E;;iBAoEgB,SAAA,CAAU,EAAc;;AApEZ;AAuB5B;;;;AAAqC;AAmBrC;;;;iBA2CgB,UAAA,IAAc,EAAA,GAAK,OAAA,iBAAwB,CAAA,GAAI,CAAC;;iBAehD,QAAA,IAAY,KAAK;;iBAOjB,YAAA,IAAgB,KAAA,EAAO,KAAA,SAAc,EAAA,QAAU,CAAA,GAAI,CAAA"}
1
+ {"version":3,"file":"reactive.d.ts","names":[],"sources":["../../src/reactive/reactive.ts"],"mappings":";;;;cAwCc,WAAA;;AAgCuB;AAoDrC;;;;AAAgE;AA2XhE;;;;AAAiC;AAGjC;;UAlciB,KAAA;EAocE;EAAA,UAlcP,WAAW;AAAA;;KAcX,QAAA,OAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC;;AAobhB;AAIrB;;;iBApYgB,oBAAA,CAAqB,SAA2B,EAAhB,SAAS;;KA2X7C,QAAA,YAAoB,CAAC;;UAGhB,aAAA;EAcN;EAZT,MAAA,GAAS,QAAQ,CAAC,CAAA;AAAA;;UAIH,MAAA;EAIJ;EAAA,IAFP,CAAA;EAEW;EAAf,GAAA,CAAI,KAAA,EAAO,CAAA,GAAI,CAAA;EAEG;EAAlB,MAAA,CAAO,EAAA,GAAK,IAAA,EAAM,CAAA,KAAM,CAAA,GAAI,CAAA;EAAJ;EAExB,IAAA,IAAQ,CAAA;AAAA;;UAIO,eAAA;EAJN;EAMT,MAAA,GAAS,QAAQ,CAAC,CAAA;AAAA;;UAIH,IAAA;EAJE;EAAA,IAMb,CAAA;EANJ;EAQA,IAAA,IAAQ,CAAC;AAAA;;AARU;AAIrB;;;;;;;iBAgBgB,MAAA,IAAU,KAAA,EAAO,CAAA,EAAG,OAAA,GAAU,aAAA,CAAc,CAAA,IAAK,MAAA,CAAO,CAAA;;AAZ7D;AAYX;;;;;;iBAiBgB,QAAA,IAAY,EAAA,QAAU,CAAA,EAAG,OAAA,GAAU,eAAA,CAAgB,CAAA,IAAK,IAAA,CAAK,CAAA;;cAYhE,IAAA,SAAI,QAAW;;;;;;;;;;;AA7B6C;AAiBzE;;;;;;;;;;;UAoCiB,aAAA;EApCW;;;;;EA0C1B,QAAA,GAAW,QAAQ;AAAA;AAAA,iBAGL,MAAA,CAAO,EAAA,cAAgB,OAAA,GAAU,aAAa;AAjC9D;;;;AAA4B;AAwB5B;;;;AAMqB;AAGrB;AAjCA,iBAmEgB,eAAA,CAAgB,EAAc;;;;;;;iBAe9B,QAAA,IAAY,MAAA,EAAQ,QAAA,CAAS,CAAA,IAAK,QAAA,CAAS,CAAA;AAf3D;;;;AAAA,iBAyBgB,KAAA,IAAS,EAAA,QAAU,CAAA,GAAI,CAAC;AAVxC;AAAA,iBAsBgB,OAAA,IAAW,EAAA,QAAU,CAAA,GAAI,CAAC;;;;;iBAc1B,SAAA,CAAU,EAAc;;;;;;;;;;AApCoB;AAU5D;iBA2CgB,UAAA,IAAc,EAAA,GAAK,OAAA,iBAAwB,CAAA,GAAI,CAAC;;iBAehD,QAAA,IAAY,KAAK;;iBAOjB,YAAA,IAAgB,KAAA,EAAO,KAAA,SAAc,EAAA,QAAU,CAAA,GAAI,CAAA"}
@@ -16,6 +16,26 @@ const effectQueue = [];
16
16
  let flushing = false;
17
17
  /** Safety valve against accidental infinite reactive loops. */
18
18
  const MAX_FLUSH_ITERATIONS = 1e5;
19
+ /**
20
+ * The scheduler that `'normal'`-lane effects defer through. `null` by default — and while it is null
21
+ * EVERY effect (including `priority: 'normal'`) flushes synchronously, so the sync default is
22
+ * unchanged for all of SSR + tests until a host opts in. Set once at app bootstrap.
23
+ */
24
+ let reactiveScheduler = null;
25
+ /** Monotonic counter for default `'normal'`-lane dedup keys. */
26
+ let effectKeySeq = 0;
27
+ /** >0 while inside a {@link startTransition}; effects staled during it defer (when a scheduler exists). */
28
+ let transitionDepth = 0;
29
+ /** Sync effects staled inside the current transition — treated as deferred for THIS drain only. */
30
+ const transitionTagged = /* @__PURE__ */ new Set();
31
+ /**
32
+ * Inject (or clear) the {@link Scheduler} that `effect(fn, { priority: 'normal' })` defers through.
33
+ * With no scheduler (the default), `'normal'`-lane effects flush synchronously — so behavior is
34
+ * identical to today until a host wires one in. Pass `null` to detach.
35
+ */
36
+ function setReactiveScheduler(scheduler) {
37
+ reactiveScheduler = scheduler;
38
+ }
19
39
  /** @internal Test-only handle to a node behind an accessor. Not public API. */
20
40
  const NODE = Symbol("mindees.reactive.node");
21
41
  var Computation = class {
@@ -29,6 +49,17 @@ var Computation = class {
29
49
  equals;
30
50
  isEffect;
31
51
  /**
52
+ * Flush lane. `'sync'` (the default for every signal/computed and every plain `effect`) flushes
53
+ * inline exactly as before. Only `effect(fn, { priority: 'normal' })` sets `'normal'`, and even
54
+ * then it only defers when a scheduler is injected via {@link setReactiveScheduler} — otherwise it
55
+ * falls back to synchronous flush. This keeps the synchronous default provably untouched.
56
+ */
57
+ lane = "sync";
58
+ /** A pending scheduled flush for a `'normal'`-lane effect (cancelled on disposal). */
59
+ pendingTask = null;
60
+ /** Scheduler dedup key for a `'normal'`-lane effect (so rapid re-stales coalesce). */
61
+ schedKey;
62
+ /**
32
63
  * Whether {@link value} holds a real computed result yet. Derivations start
33
64
  * uninitialized (their initial `value` is a placeholder); the first
34
65
  * computation must NOT call `equals(oldValue, …)` against that placeholder —
@@ -80,7 +111,10 @@ var Computation = class {
80
111
  if (this.state < state) {
81
112
  const wasClean = this.state === CLEAN;
82
113
  this.state = state;
83
- if (this.isEffect && wasClean) effectQueue.push(this);
114
+ if (this.isEffect && wasClean) {
115
+ effectQueue.push(this);
116
+ if (transitionDepth > 0 && reactiveScheduler && this.lane === "sync") transitionTagged.add(this);
117
+ }
84
118
  if (this.observers) for (const o of this.observers) o.markStale(CHECK);
85
119
  }
86
120
  }
@@ -208,6 +242,10 @@ function disposeComputation(node) {
208
242
  unlinkSources(node);
209
243
  node.observers = null;
210
244
  node.state = DISPOSED;
245
+ if (node.pendingTask) {
246
+ node.pendingTask.cancel();
247
+ node.pendingTask = null;
248
+ }
211
249
  }
212
250
  }
213
251
  function adopt(node) {
@@ -229,7 +267,18 @@ function flushEffects() {
229
267
  }
230
268
  const e = effectQueue[i];
231
269
  i++;
232
- if (e && e.state !== CLEAN && e.state !== DISPOSED) try {
270
+ if (e && e.state !== CLEAN && e.state !== DISPOSED) if (reactiveScheduler && (e.lane === "normal" || transitionTagged.has(e))) {
271
+ const node = e;
272
+ const sched = reactiveScheduler;
273
+ if (node.schedKey === void 0) node.schedKey = `mindees:effect:${effectKeySeq++}`;
274
+ node.pendingTask = sched.schedule(() => {
275
+ node.pendingTask = null;
276
+ if (node.state !== CLEAN && node.state !== DISPOSED) node.updateIfNecessary();
277
+ }, {
278
+ priority: "normal",
279
+ key: node.schedKey
280
+ });
281
+ } else try {
233
282
  e.updateIfNecessary();
234
283
  } catch (err) {
235
284
  errors.push(err);
@@ -237,6 +286,7 @@ function flushEffects() {
237
286
  }
238
287
  } finally {
239
288
  effectQueue.length = 0;
289
+ transitionTagged.clear();
240
290
  flushing = false;
241
291
  }
242
292
  if (errors.length === 1) throw errors[0];
@@ -283,37 +333,50 @@ function computed(fn, options) {
283
333
  }
284
334
  /** Alias of {@link computed}. */
285
335
  const memo = computed;
286
- /**
287
- * Run a side effect that re-runs whenever its reactive dependencies change.
288
- * Runs once immediately to establish dependencies.
289
- *
290
- * To clean up before each re-run and on disposal, either return a cleanup
291
- * function from the effect, or call {@link onCleanup}. Any non-function return
292
- * value is ignored (so expression-bodied effects like `() => list.push(x())`
293
- * are fine).
294
- *
295
- * @returns A disposer that stops the effect and runs its cleanups.
296
- *
297
- * @example
298
- * const stop = effect(() => console.log(count()))
299
- * stop() // unsubscribe
300
- *
301
- * @example
302
- * effect(() => {
303
- * const id = setInterval(tick, 1000)
304
- * return () => clearInterval(id) // cleanup
305
- * })
306
- */
307
- function effect(fn) {
336
+ function effect(fn, options) {
308
337
  const node = new Computation(void 0, () => {
309
338
  const result = fn();
310
339
  if (typeof result === "function") onCleanup(result);
311
340
  }, false, true);
341
+ if (options?.priority === "normal") {
342
+ node.lane = "normal";
343
+ node.schedKey = `mindees:effect:${effectKeySeq++}`;
344
+ }
312
345
  adopt(node);
313
346
  node.updateIfNecessary();
314
347
  return () => disposeComputation(node);
315
348
  }
316
349
  /**
350
+ * Apply the writes in `fn` as a low-priority **transition**: the writes take effect immediately
351
+ * (reads inside/after see the latest values), but the effects they invalidate are **deferred**
352
+ * through the injected {@link setReactiveScheduler scheduler} instead of running synchronously — so a
353
+ * heavy re-render triggered by, say, a keystroke doesn't block the interaction. With no scheduler
354
+ * injected, this is a plain synchronous batch (no deferral) — safe for SSR/tests.
355
+ *
356
+ * @example
357
+ * input.set(value) // urgent: the field updates now
358
+ * startTransition(() => query.set(value)) // the expensive results re-render can lag
359
+ */
360
+ function startTransition(fn) {
361
+ transitionDepth++;
362
+ try {
363
+ batch(fn);
364
+ } finally {
365
+ transitionDepth--;
366
+ }
367
+ }
368
+ /**
369
+ * A **deferred view** of `source`: it tracks `source` on the scheduler's low-priority lane, so under
370
+ * sustained updates it lags behind the live value (the React `useDeferredValue` pattern — show stale
371
+ * results while the latest are computed). With no scheduler injected it mirrors `source`
372
+ * synchronously (no lag), so SSR/tests see the live value. Must be created inside an owner.
373
+ */
374
+ function deferred(source) {
375
+ const out = signal(source());
376
+ effect(() => out.set(source()), { priority: "normal" });
377
+ return () => out();
378
+ }
379
+ /**
317
380
  * Batch multiple writes so dependent effects run once, after the batch. Reads
318
381
  * inside a batch still observe the latest written values synchronously.
319
382
  */
@@ -388,6 +451,6 @@ function runWithOwner(owner, fn) {
388
451
  }
389
452
  }
390
453
  //#endregion
391
- export { batch, computed, createRoot, effect, getOwner, memo, onCleanup, runWithOwner, signal, untrack };
454
+ export { batch, computed, createRoot, deferred, effect, getOwner, memo, onCleanup, runWithOwner, setReactiveScheduler, signal, startTransition, untrack };
392
455
 
393
456
  //# sourceMappingURL=reactive.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.js","names":[],"sources":["../../src/reactive/reactive.ts"],"sourcesContent":["/**\n * MindeesNative reactivity — fine-grained, glitch-free, lazy signals.\n *\n * Algorithm: push–pull with graph coloring (`CLEAN` / `CHECK` / `DIRTY`), in the\n * lineage of SolidJS and the \"reactively\" library. A write *pushes* staleness\n * markers through the observer graph; a read *pulls*, recomputing a node only\n * when one of its sources actually changed. This guarantees:\n *\n * - **Glitch freedom** — no observer ever sees an inconsistent intermediate\n * state (the classic diamond dependency recomputes its consumer exactly once).\n * - **No redundant recomputation** — a node recomputes at most once per change,\n * and an equal recomputation does not propagate to its observers.\n * - **Deterministic, synchronous propagation** — effects run in a predictable\n * order, batched to the end of the outermost write/batch.\n * - **Complete disposal** — disposing an owner unlinks every subscription, so\n * there are no leaked observers.\n *\n * @module\n */\n\n// ---------------------------------------------------------------------------\n// Ownership\n// ---------------------------------------------------------------------------\n\n/**\n * @internal Engine-side disposal scope. Computations and roots own the cleanups\n * and child computations created while they are the active owner; disposing an\n * owner tears all of them down. This concrete shape stays internal — see the\n * public {@link Owner} opaque handle.\n */\ninterface OwnerNode {\n /** Child computations created while this owner was active. */\n owned: AnyComputation[] | null\n /** Cleanup callbacks registered via {@link onCleanup}. */\n cleanups: Array<() => void> | null\n}\n\n/** @internal Phantom brand making {@link Owner} nominal — see below. */\ndeclare const OWNER_BRAND: unique symbol\n\n/**\n * An opaque disposal-scope handle. Obtain one with {@link getOwner} and re-enter\n * it with {@link runWithOwner}. Its internal shape — the reactive graph nodes it\n * owns — is intentionally not part of the public type surface, so the type-erased\n * {@link Computation} graph never leaks (no `any`, no internal mutable fields)\n * into consumers' types. Treat it as a token: hold it, pass it back; do not reach\n * inside it.\n *\n * It is **nominal** (branded with a private phantom symbol) so a structural\n * object literal — e.g. `{}` — is *not* assignable to it. Only a value handed out\n * by {@link getOwner} is a valid `Owner`; this prevents a fabricated owner from\n * flowing through {@link runWithOwner} into `onCleanup`/`adopt` and crashing on a\n * missing `owned`/`cleanups` field.\n */\nexport interface Owner {\n /** @internal Phantom brand — never present at runtime; blocks fabrication. */\n readonly [OWNER_BRAND]: never\n}\n\n// ---------------------------------------------------------------------------\n// Node state\n// ---------------------------------------------------------------------------\n\ntype State = 0 | 1 | 2 | 3\nconst CLEAN: State = 0\nconst CHECK: State = 1\nconst DIRTY: State = 2\nconst DISPOSED: State = 3\n\n/** Equality comparator used to decide whether a value actually changed. */\nexport type EqualsFn<T> = (a: T, b: T) => boolean\n\n// Default comparator: `Object.is`, matching context `select()` so the whole\n// package shares one semantics. Unlike `===`, this treats `NaN` as equal to\n// itself (so `set(NaN)` after `NaN` does not re-notify) and `-0`/`+0` as\n// different — the conventional choice for signal libraries.\nconst equalsDefault = (a: unknown, b: unknown): boolean => Object.is(a, b)\n\n/**\n * The reactive graph is intentionally type-erased: a node may observe, and be\n * observed by, computations of unrelated value types. Internal graph links use\n * this alias; the public API (`Signal<T>` / `Memo<T>` / `Accessor<T>`) stays\n * fully typed.\n */\n// biome-ignore lint/suspicious/noExplicitAny: type-erased reactive graph links\ntype AnyComputation = Computation<any>\n\n// ---------------------------------------------------------------------------\n// Globals (tracking + scheduling)\n// ---------------------------------------------------------------------------\n\n/** The computation currently executing, used for automatic dependency tracking. */\nlet currentObserver: AnyComputation | null = null\n/** The active disposal scope for onCleanup / child registration. */\nlet currentOwner: OwnerNode | null = null\n/** Outstanding `batch()` nesting depth; effects flush when this returns to 0. */\nlet batchDepth = 0\n/** Effects marked stale and awaiting a flush. */\nconst effectQueue: AnyComputation[] = []\n/** Guard against re-entrant flushes. */\nlet flushing = false\n/** Safety valve against accidental infinite reactive loops. */\nconst MAX_FLUSH_ITERATIONS = 100_000\n\n/** @internal Test-only handle to a node behind an accessor. Not public API. */\nexport const NODE: unique symbol = Symbol('mindees.reactive.node')\n\ninterface WithNode<T> {\n [NODE]: Computation<T>\n}\n\n// ---------------------------------------------------------------------------\n// Computation: the unit of reactivity (signal, computed, or effect)\n// ---------------------------------------------------------------------------\n\nclass Computation<T> implements OwnerNode {\n value: T\n fn: (() => T) | null\n state: State\n sources: AnyComputation[] | null = null\n observers: AnyComputation[] | null = null\n owned: AnyComputation[] | null = null\n cleanups: Array<() => void> | null = null\n equals: EqualsFn<T> | false\n readonly isEffect: boolean\n /**\n * Whether {@link value} holds a real computed result yet. Derivations start\n * uninitialized (their initial `value` is a placeholder); the first\n * computation must NOT call `equals(oldValue, …)` against that placeholder —\n * a custom comparator would receive `undefined` and could throw.\n */\n private initialized: boolean\n /**\n * True only while this node's own {@link update} is on the stack. Lets\n * {@link markStale} recognize a *self-write* — the body writing a signal the\n * node observes — instead of dropping the mark (the node is already DIRTY).\n */\n private running = false\n /**\n * Set by {@link markStale} when a self-write occurs mid-update. {@link update}'s\n * loop recomputes once more so the node converges on the value it just produced,\n * honoring the contract that a computation reflects its dependencies' latest\n * values. Reset at the start of every pass.\n */\n private restaleRequested = false\n\n constructor(value: T, fn: (() => T) | null, equals: EqualsFn<T> | false, isEffect: boolean) {\n this.value = value\n this.fn = fn\n this.equals = equals\n this.isEffect = isEffect\n // Signals (no fn) start CLEAN and already hold a real value; derivations\n // start DIRTY (compute lazily) and uninitialized.\n this.state = fn ? DIRTY : CLEAN\n this.initialized = fn === null\n }\n\n /** Read the current value, tracking a dependency if a computation is running. */\n read(): T {\n if (this.state === DISPOSED) return this.value\n if (currentObserver) link(currentObserver, this)\n if (this.fn) this.updateIfNecessary()\n return this.value\n }\n\n /** Write a new value (signals only); pushes staleness to observers. */\n write(value: T): T {\n if (this.equals !== false && this.equals(this.value, value)) return this.value\n this.value = value\n if (this.observers) {\n for (const o of this.observers) o.markStale(DIRTY)\n }\n if (batchDepth === 0) flushEffects()\n return value\n }\n\n /** Color this node (and, transitively, its observers) as stale. */\n markStale(state: State): void {\n // Self-write: this node is being marked stale while its own update() is\n // running (its body just wrote a signal it observes). It is already DIRTY, so\n // the gate below would silently drop the mark and the change would be lost.\n // Instead request one more recompute pass (handled by update()'s loop); don't\n // re-propagate here — the re-run will, once it produces a new value.\n if (this.running) {\n this.restaleRequested = true\n return\n }\n if (this.state < state) {\n const wasClean = this.state === CLEAN\n this.state = state\n if (this.isEffect && wasClean) effectQueue.push(this)\n if (this.observers) {\n for (const o of this.observers) o.markStale(CHECK)\n }\n }\n }\n\n /** Bring this node up to date, recomputing only if a source truly changed. */\n updateIfNecessary(): void {\n if (this.state === CLEAN || this.state === DISPOSED) return\n if (this.state === CHECK && this.sources) {\n for (const src of this.sources) {\n src.updateIfNecessary()\n if (this.state === DIRTY) break\n }\n }\n try {\n if (this.state === DIRTY) this.update()\n } finally {\n // Always settle to CLEAN (unless disposed) even if update() — the body or a\n // child cleanup — threw. Otherwise the node would stay DIRTY forever and\n // markStale's wasClean gate would never re-queue it (a permanent zombie).\n // Sources read before the throw are re-linked, so a later change recovers it.\n if (this.state !== DISPOSED) this.state = CLEAN\n }\n }\n\n /**\n * Recompute the derivation, re-tracking dependencies and notifying observers.\n *\n * Runs in a bounded loop. If the body writes a signal it itself observes (a\n * self-write), {@link markStale} sets {@link restaleRequested} rather than the\n * mark being lost, and we recompute again so the node converges on the value it\n * just produced. The loop is capped by {@link MAX_FLUSH_ITERATIONS} so a\n * non-terminating self-writer (e.g. `effect(() => a.set(a() + 1))`) throws\n * instead of hanging. A prior-run cleanup that throws during teardown must not\n * abort the re-track/recompute (that would strand the node's children and\n * dynamic deps); its error is captured and rethrown only after the node has\n * rebuilt a consistent graph.\n */\n private update(): void {\n const oldValue = this.value\n let cleanupError: unknown\n let hasCleanupError = false\n let iterations = 0\n this.running = true\n try {\n do {\n this.restaleRequested = false\n try {\n disposeChildren(this)\n } catch (err) {\n if (!hasCleanupError) {\n cleanupError = err\n hasCleanupError = true\n }\n }\n unlinkSources(this)\n\n const prevObserver = currentObserver\n const prevOwner = currentOwner\n currentObserver = this\n currentOwner = this\n try {\n // biome-ignore lint/style/noNonNullAssertion: update() only runs for derivations (fn != null).\n this.value = this.fn!()\n } finally {\n currentObserver = prevObserver\n currentOwner = prevOwner\n }\n\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n this.restaleRequested = false\n throw new Error(\n 'MindeesNative: potential infinite reactive loop detected — a computation keeps writing a signal it reads.',\n )\n }\n } while (this.restaleRequested)\n } finally {\n this.running = false\n }\n\n // On the first computation there is no prior value to compare against, so\n // the result is always \"changed\". Afterwards, apply the equality check\n // (unless equals is false, meaning \"always changed\").\n const wasInitialized = this.initialized\n this.initialized = true\n const changed = !wasInitialized || this.equals === false || !this.equals(oldValue, this.value)\n if (changed && this.observers) {\n // Observers are already CHECK from the original push; promote them to DIRTY\n // so the in-flight pull recomputes them.\n for (const o of this.observers) {\n o.state = DIRTY\n }\n }\n\n // The graph is consistent again; now surface any error a previous-run cleanup\n // threw during teardown (the body still re-ran, so children/deps are rebuilt).\n if (hasCleanupError) throw cleanupError\n }\n}\n\n// ---------------------------------------------------------------------------\n// Graph maintenance\n// ---------------------------------------------------------------------------\n\nfunction link(observer: AnyComputation, source: AnyComputation): void {\n // Never subscribe a disposed observer — e.g. a node that disposed itself\n // mid-run and then read another signal. The subscription would leak: nothing\n // tears down a DISPOSED node again.\n if (observer.state === DISPOSED) return\n if (observer.sources === null) observer.sources = []\n const sources = observer.sources\n if (!sources.includes(source)) {\n sources.push(source)\n if (source.observers === null) source.observers = []\n source.observers.push(observer)\n }\n}\n\nfunction unlinkSources(node: AnyComputation): void {\n if (!node.sources) return\n for (const src of node.sources) {\n const obs = src.observers\n if (!obs) continue\n const idx = obs.indexOf(node)\n if (idx >= 0) {\n const last = obs.pop()\n if (last && idx < obs.length) obs[idx] = last\n }\n }\n node.sources = null\n}\n\nfunction disposeChildren(owner: OwnerNode): void {\n // Dispose every owned child AND run every cleanup even if some throw, so a\n // single faulty child/cleanup can't strand the rest or leak observers. `owned`\n // is nulled up front so a throw can't leave a half-disposed array behind.\n // Failures are collected and surfaced together afterward.\n const errors: unknown[] = []\n if (owner.owned) {\n const owned = owner.owned\n owner.owned = null\n for (const child of owned) {\n try {\n disposeComputation(child)\n } catch (err) {\n errors.push(err)\n }\n }\n }\n if (owner.cleanups) {\n const cleanups = owner.cleanups\n owner.cleanups = null\n for (const c of cleanups) {\n try {\n c()\n } catch (err) {\n errors.push(err)\n }\n }\n }\n if (errors.length === 1) throw errors[0]\n if (errors.length > 1) throw new AggregateError(errors, 'disposal threw')\n}\n\nfunction disposeComputation(node: AnyComputation): void {\n if (node.state === DISPOSED) return\n // If a node disposes itself mid-run, stop tracking and adopting onto it for the\n // rest of the (now-aborted) body: a later tracked read would otherwise\n // re-subscribe this DISPOSED node, and onCleanup/adopt would register work on a\n // dead scope — none of which is ever torn down again (a leak). Clearing the\n // globals makes read()/onCleanup/adopt no-op for the remainder of the body;\n // update()'s finally restores the previous owner afterward.\n if (node === currentObserver) currentObserver = null\n if (node === currentOwner) currentOwner = null\n try {\n disposeChildren(node)\n } finally {\n // Always fully unlink + mark disposed, even if a descendant cleanup threw,\n // so this node never leaks as a subscribed zombie. The error (if any) still\n // propagates to the caller, which aggregates it across siblings.\n unlinkSources(node)\n node.observers = null\n node.state = DISPOSED\n }\n}\n\nfunction adopt(node: AnyComputation): void {\n if (!currentOwner) return\n if (currentOwner.owned === null) currentOwner.owned = []\n currentOwner.owned.push(node)\n}\n\n// ---------------------------------------------------------------------------\n// Effect scheduling\n// ---------------------------------------------------------------------------\n\nfunction flushEffects(): void {\n if (flushing) return\n flushing = true\n // Isolate each effect: one throwing effect must not abort the flush or strand\n // the effects queued after it (each effect also self-recovers to CLEAN via\n // updateIfNecessary's finally). Errors are collected and surfaced after drain.\n const errors: unknown[] = []\n try {\n let i = 0\n let iterations = 0\n while (i < effectQueue.length) {\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n effectQueue.length = 0\n throw new Error(\n 'MindeesNative: potential infinite reactive loop detected while flushing effects.',\n )\n }\n const e = effectQueue[i]\n i++\n if (e && e.state !== CLEAN && e.state !== DISPOSED) {\n try {\n e.updateIfNecessary()\n } catch (err) {\n errors.push(err)\n }\n }\n }\n } finally {\n effectQueue.length = 0\n flushing = false\n }\n if (errors.length === 1) throw errors[0]\n if (errors.length > 1) throw new AggregateError(errors, 'effect(s) threw during flush')\n}\n\nfunction attachNode<T, A extends object>(accessor: A, node: Computation<T>): A {\n ;(accessor as A & WithNode<T>)[NODE] = node\n return accessor\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** A read accessor for a derived/reactive value. */\nexport type Accessor<T> = () => T\n\n/** Options accepted by {@link signal}. */\nexport interface SignalOptions<T> {\n /** Custom equality. `false` means \"always notify\" (every write propagates). */\n equals?: EqualsFn<T> | false\n}\n\n/** A writable reactive value: call to read; `.set`/`.update` to write. */\nexport interface Signal<T> {\n /** Read the value (tracks a dependency inside a computation). */\n (): T\n /** Replace the value; returns the new value. */\n set(value: T): T\n /** Update from the previous value; returns the new value. */\n update(fn: (prev: T) => T): T\n /** Read without tracking a dependency. */\n peek(): T\n}\n\n/** Options accepted by {@link computed}. */\nexport interface ComputedOptions<T> {\n /** Custom equality used to decide whether downstream observers re-run. */\n equals?: EqualsFn<T> | false\n}\n\n/** A memoized derived value: call to read; `.peek` to read without tracking. */\nexport interface Memo<T> {\n /** Read the (lazily recomputed) value, tracking a dependency. */\n (): T\n /** Read without tracking a dependency. */\n peek(): T\n}\n\n/**\n * Create a writable reactive value.\n *\n * @example\n * const count = signal(0)\n * count() // read → 0\n * count.set(1) // write\n * count.update(n => n + 1)\n */\nexport function signal<T>(value: T, options?: SignalOptions<T>): Signal<T> {\n const node = new Computation<T>(value, null, options?.equals ?? equalsDefault, false)\n const accessor = (() => node.read()) as Signal<T>\n accessor.set = (v: T) => node.write(v)\n accessor.update = (fn: (prev: T) => T) => node.write(fn(node.value))\n accessor.peek = () => node.value\n return attachNode(accessor, node)\n}\n\n/**\n * Create a memoized derived value. The function re-runs only when one of the\n * reactive values it reads has actually changed, and only when the result is\n * observed (lazy).\n *\n * @example\n * const doubled = computed(() => count() * 2)\n */\nexport function computed<T>(fn: () => T, options?: ComputedOptions<T>): Memo<T> {\n const node = new Computation<T>(undefined as T, fn, options?.equals ?? equalsDefault, false)\n adopt(node)\n const accessor = (() => node.read()) as Memo<T>\n accessor.peek = () => {\n node.updateIfNecessary()\n return node.value\n }\n return attachNode(accessor, node)\n}\n\n/** Alias of {@link computed}. */\nexport const memo = computed\n\n/**\n * Run a side effect that re-runs whenever its reactive dependencies change.\n * Runs once immediately to establish dependencies.\n *\n * To clean up before each re-run and on disposal, either return a cleanup\n * function from the effect, or call {@link onCleanup}. Any non-function return\n * value is ignored (so expression-bodied effects like `() => list.push(x())`\n * are fine).\n *\n * @returns A disposer that stops the effect and runs its cleanups.\n *\n * @example\n * const stop = effect(() => console.log(count()))\n * stop() // unsubscribe\n *\n * @example\n * effect(() => {\n * const id = setInterval(tick, 1000)\n * return () => clearInterval(id) // cleanup\n * })\n */\nexport function effect(fn: () => void): () => void {\n const node = new Computation<void>(\n undefined,\n () => {\n const result: unknown = (fn as () => unknown)()\n if (typeof result === 'function') onCleanup(result as () => void)\n },\n false,\n true,\n )\n adopt(node)\n node.updateIfNecessary()\n return () => disposeComputation(node)\n}\n\n/**\n * Batch multiple writes so dependent effects run once, after the batch. Reads\n * inside a batch still observe the latest written values synchronously.\n */\nexport function batch<T>(fn: () => T): T {\n if (batchDepth > 0) return fn()\n batchDepth++\n try {\n return fn()\n } finally {\n batchDepth--\n flushEffects()\n }\n}\n\n/** Read reactive values without subscribing the current computation to them. */\nexport function untrack<T>(fn: () => T): T {\n const prev = currentObserver\n currentObserver = null\n try {\n return fn()\n } finally {\n currentObserver = prev\n }\n}\n\n/**\n * Register a cleanup to run before the owning computation re-runs and when it\n * is disposed. No-op outside a reactive scope.\n */\nexport function onCleanup(fn: () => void): void {\n if (!currentOwner) return\n if (currentOwner.cleanups === null) currentOwner.cleanups = []\n currentOwner.cleanups.push(fn)\n}\n\n/**\n * Create a non-tracked root scope that owns everything created within it. The\n * scope lives until the provided `dispose` function is called.\n *\n * @example\n * const dispose = createRoot((dispose) => {\n * effect(() => console.log(count()))\n * return dispose\n * })\n * dispose() // tear down the effect\n */\nexport function createRoot<T>(fn: (dispose: () => void) => T): T {\n const root: OwnerNode = { owned: null, cleanups: null }\n const prevObserver = currentObserver\n const prevOwner = currentOwner\n currentObserver = null\n currentOwner = root\n try {\n return fn(() => disposeChildren(root))\n } finally {\n currentObserver = prevObserver\n currentOwner = prevOwner\n }\n}\n\n/** The current owner scope, or `null` outside any reactive scope. */\nexport function getOwner(): Owner | null {\n // OwnerNode → the nominal public Owner. The brand is phantom (never present at\n // runtime), so the only honest way to produce an Owner is through this cast.\n return currentOwner as unknown as Owner | null\n}\n\n/** Run `fn` with `owner` as the active scope (e.g. to re-attach cleanups). */\nexport function runWithOwner<T>(owner: Owner | null, fn: () => T): T {\n const prev = currentOwner\n // `owner` is an opaque public handle; internally it is always an OwnerNode we\n // handed out via getOwner(). This is the one trusted boundary cast.\n currentOwner = owner as unknown as OwnerNode | null\n try {\n return fn()\n } finally {\n currentOwner = prev\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal test helpers (exported from this module only — NOT from the package\n// public entry point). Used to assert white-box invariants like leak-freedom.\n// ---------------------------------------------------------------------------\n\n/** @internal Number of live observers subscribed to the node behind `accessor`. */\nexport function _observerCount(accessor: object): number {\n const node = (accessor as Partial<WithNode<unknown>>)[NODE]\n return node?.observers?.length ?? 0\n}\n\n/** @internal Number of sources the node behind `accessor` depends on. */\nexport function _sourceCount(accessor: object): number {\n const node = (accessor as Partial<WithNode<unknown>>)[NODE]\n return node?.sources?.length ?? 0\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"reactive.js","names":[],"sources":["../../src/reactive/reactive.ts"],"sourcesContent":["/**\n * MindeesNative reactivity — fine-grained, glitch-free, lazy signals.\n *\n * Algorithm: push–pull with graph coloring (`CLEAN` / `CHECK` / `DIRTY`), in the\n * lineage of SolidJS and the \"reactively\" library. A write *pushes* staleness\n * markers through the observer graph; a read *pulls*, recomputing a node only\n * when one of its sources actually changed. This guarantees:\n *\n * - **Glitch freedom** — no observer ever sees an inconsistent intermediate\n * state (the classic diamond dependency recomputes its consumer exactly once).\n * - **No redundant recomputation** — a node recomputes at most once per change,\n * and an equal recomputation does not propagate to its observers.\n * - **Deterministic, synchronous propagation** — effects run in a predictable\n * order, batched to the end of the outermost write/batch.\n * - **Complete disposal** — disposing an owner unlinks every subscription, so\n * there are no leaked observers.\n *\n * @module\n */\n\nimport type { Priority, ScheduledTask, Scheduler } from '../scheduler'\n\n// ---------------------------------------------------------------------------\n// Ownership\n// ---------------------------------------------------------------------------\n\n/**\n * @internal Engine-side disposal scope. Computations and roots own the cleanups\n * and child computations created while they are the active owner; disposing an\n * owner tears all of them down. This concrete shape stays internal — see the\n * public {@link Owner} opaque handle.\n */\ninterface OwnerNode {\n /** Child computations created while this owner was active. */\n owned: AnyComputation[] | null\n /** Cleanup callbacks registered via {@link onCleanup}. */\n cleanups: Array<() => void> | null\n}\n\n/** @internal Phantom brand making {@link Owner} nominal — see below. */\ndeclare const OWNER_BRAND: unique symbol\n\n/**\n * An opaque disposal-scope handle. Obtain one with {@link getOwner} and re-enter\n * it with {@link runWithOwner}. Its internal shape — the reactive graph nodes it\n * owns — is intentionally not part of the public type surface, so the type-erased\n * {@link Computation} graph never leaks (no `any`, no internal mutable fields)\n * into consumers' types. Treat it as a token: hold it, pass it back; do not reach\n * inside it.\n *\n * It is **nominal** (branded with a private phantom symbol) so a structural\n * object literal — e.g. `{}` — is *not* assignable to it. Only a value handed out\n * by {@link getOwner} is a valid `Owner`; this prevents a fabricated owner from\n * flowing through {@link runWithOwner} into `onCleanup`/`adopt` and crashing on a\n * missing `owned`/`cleanups` field.\n */\nexport interface Owner {\n /** @internal Phantom brand — never present at runtime; blocks fabrication. */\n readonly [OWNER_BRAND]: never\n}\n\n// ---------------------------------------------------------------------------\n// Node state\n// ---------------------------------------------------------------------------\n\ntype State = 0 | 1 | 2 | 3\nconst CLEAN: State = 0\nconst CHECK: State = 1\nconst DIRTY: State = 2\nconst DISPOSED: State = 3\n\n/** Equality comparator used to decide whether a value actually changed. */\nexport type EqualsFn<T> = (a: T, b: T) => boolean\n\n// Default comparator: `Object.is`, matching context `select()` so the whole\n// package shares one semantics. Unlike `===`, this treats `NaN` as equal to\n// itself (so `set(NaN)` after `NaN` does not re-notify) and `-0`/`+0` as\n// different — the conventional choice for signal libraries.\nconst equalsDefault = (a: unknown, b: unknown): boolean => Object.is(a, b)\n\n/**\n * The reactive graph is intentionally type-erased: a node may observe, and be\n * observed by, computations of unrelated value types. Internal graph links use\n * this alias; the public API (`Signal<T>` / `Memo<T>` / `Accessor<T>`) stays\n * fully typed.\n */\n// biome-ignore lint/suspicious/noExplicitAny: type-erased reactive graph links\ntype AnyComputation = Computation<any>\n\n// ---------------------------------------------------------------------------\n// Globals (tracking + scheduling)\n// ---------------------------------------------------------------------------\n\n/** The computation currently executing, used for automatic dependency tracking. */\nlet currentObserver: AnyComputation | null = null\n/** The active disposal scope for onCleanup / child registration. */\nlet currentOwner: OwnerNode | null = null\n/** Outstanding `batch()` nesting depth; effects flush when this returns to 0. */\nlet batchDepth = 0\n/** Effects marked stale and awaiting a flush. */\nconst effectQueue: AnyComputation[] = []\n/** Guard against re-entrant flushes. */\nlet flushing = false\n/** Safety valve against accidental infinite reactive loops. */\nconst MAX_FLUSH_ITERATIONS = 100_000\n\n/**\n * The scheduler that `'normal'`-lane effects defer through. `null` by default — and while it is null\n * EVERY effect (including `priority: 'normal'`) flushes synchronously, so the sync default is\n * unchanged for all of SSR + tests until a host opts in. Set once at app bootstrap.\n */\nlet reactiveScheduler: Scheduler | null = null\n/** Monotonic counter for default `'normal'`-lane dedup keys. */\nlet effectKeySeq = 0\n/** >0 while inside a {@link startTransition}; effects staled during it defer (when a scheduler exists). */\nlet transitionDepth = 0\n/** Sync effects staled inside the current transition — treated as deferred for THIS drain only. */\nconst transitionTagged = new Set<AnyComputation>()\n\n/**\n * Inject (or clear) the {@link Scheduler} that `effect(fn, { priority: 'normal' })` defers through.\n * With no scheduler (the default), `'normal'`-lane effects flush synchronously — so behavior is\n * identical to today until a host wires one in. Pass `null` to detach.\n */\nexport function setReactiveScheduler(scheduler: Scheduler | null): void {\n reactiveScheduler = scheduler\n}\n\n/** @internal Test-only handle to a node behind an accessor. Not public API. */\nexport const NODE: unique symbol = Symbol('mindees.reactive.node')\n\ninterface WithNode<T> {\n [NODE]: Computation<T>\n}\n\n// ---------------------------------------------------------------------------\n// Computation: the unit of reactivity (signal, computed, or effect)\n// ---------------------------------------------------------------------------\n\nclass Computation<T> implements OwnerNode {\n value: T\n fn: (() => T) | null\n state: State\n sources: AnyComputation[] | null = null\n observers: AnyComputation[] | null = null\n owned: AnyComputation[] | null = null\n cleanups: Array<() => void> | null = null\n equals: EqualsFn<T> | false\n readonly isEffect: boolean\n /**\n * Flush lane. `'sync'` (the default for every signal/computed and every plain `effect`) flushes\n * inline exactly as before. Only `effect(fn, { priority: 'normal' })` sets `'normal'`, and even\n * then it only defers when a scheduler is injected via {@link setReactiveScheduler} — otherwise it\n * falls back to synchronous flush. This keeps the synchronous default provably untouched.\n */\n lane: Priority = 'sync'\n /** A pending scheduled flush for a `'normal'`-lane effect (cancelled on disposal). */\n pendingTask: ScheduledTask | null = null\n /** Scheduler dedup key for a `'normal'`-lane effect (so rapid re-stales coalesce). */\n schedKey: string | undefined\n /**\n * Whether {@link value} holds a real computed result yet. Derivations start\n * uninitialized (their initial `value` is a placeholder); the first\n * computation must NOT call `equals(oldValue, …)` against that placeholder —\n * a custom comparator would receive `undefined` and could throw.\n */\n private initialized: boolean\n /**\n * True only while this node's own {@link update} is on the stack. Lets\n * {@link markStale} recognize a *self-write* — the body writing a signal the\n * node observes — instead of dropping the mark (the node is already DIRTY).\n */\n private running = false\n /**\n * Set by {@link markStale} when a self-write occurs mid-update. {@link update}'s\n * loop recomputes once more so the node converges on the value it just produced,\n * honoring the contract that a computation reflects its dependencies' latest\n * values. Reset at the start of every pass.\n */\n private restaleRequested = false\n\n constructor(value: T, fn: (() => T) | null, equals: EqualsFn<T> | false, isEffect: boolean) {\n this.value = value\n this.fn = fn\n this.equals = equals\n this.isEffect = isEffect\n // Signals (no fn) start CLEAN and already hold a real value; derivations\n // start DIRTY (compute lazily) and uninitialized.\n this.state = fn ? DIRTY : CLEAN\n this.initialized = fn === null\n }\n\n /** Read the current value, tracking a dependency if a computation is running. */\n read(): T {\n if (this.state === DISPOSED) return this.value\n if (currentObserver) link(currentObserver, this)\n if (this.fn) this.updateIfNecessary()\n return this.value\n }\n\n /** Write a new value (signals only); pushes staleness to observers. */\n write(value: T): T {\n if (this.equals !== false && this.equals(this.value, value)) return this.value\n this.value = value\n if (this.observers) {\n for (const o of this.observers) o.markStale(DIRTY)\n }\n if (batchDepth === 0) flushEffects()\n return value\n }\n\n /** Color this node (and, transitively, its observers) as stale. */\n markStale(state: State): void {\n // Self-write: this node is being marked stale while its own update() is\n // running (its body just wrote a signal it observes). It is already DIRTY, so\n // the gate below would silently drop the mark and the change would be lost.\n // Instead request one more recompute pass (handled by update()'s loop); don't\n // re-propagate here — the re-run will, once it produces a new value.\n if (this.running) {\n this.restaleRequested = true\n return\n }\n if (this.state < state) {\n const wasClean = this.state === CLEAN\n this.state = state\n if (this.isEffect && wasClean) {\n effectQueue.push(this)\n // Inside a startTransition (with a scheduler), tag a SYNC effect so this drain defers it —\n // without permanently changing its lane. No-op on every default path (transitionDepth 0).\n if (transitionDepth > 0 && reactiveScheduler && this.lane === 'sync') {\n transitionTagged.add(this)\n }\n }\n if (this.observers) {\n for (const o of this.observers) o.markStale(CHECK)\n }\n }\n }\n\n /** Bring this node up to date, recomputing only if a source truly changed. */\n updateIfNecessary(): void {\n if (this.state === CLEAN || this.state === DISPOSED) return\n if (this.state === CHECK && this.sources) {\n for (const src of this.sources) {\n src.updateIfNecessary()\n if (this.state === DIRTY) break\n }\n }\n try {\n if (this.state === DIRTY) this.update()\n } finally {\n // Always settle to CLEAN (unless disposed) even if update() — the body or a\n // child cleanup — threw. Otherwise the node would stay DIRTY forever and\n // markStale's wasClean gate would never re-queue it (a permanent zombie).\n // Sources read before the throw are re-linked, so a later change recovers it.\n if (this.state !== DISPOSED) this.state = CLEAN\n }\n }\n\n /**\n * Recompute the derivation, re-tracking dependencies and notifying observers.\n *\n * Runs in a bounded loop. If the body writes a signal it itself observes (a\n * self-write), {@link markStale} sets {@link restaleRequested} rather than the\n * mark being lost, and we recompute again so the node converges on the value it\n * just produced. The loop is capped by {@link MAX_FLUSH_ITERATIONS} so a\n * non-terminating self-writer (e.g. `effect(() => a.set(a() + 1))`) throws\n * instead of hanging. A prior-run cleanup that throws during teardown must not\n * abort the re-track/recompute (that would strand the node's children and\n * dynamic deps); its error is captured and rethrown only after the node has\n * rebuilt a consistent graph.\n */\n private update(): void {\n const oldValue = this.value\n let cleanupError: unknown\n let hasCleanupError = false\n let iterations = 0\n this.running = true\n try {\n do {\n this.restaleRequested = false\n try {\n disposeChildren(this)\n } catch (err) {\n if (!hasCleanupError) {\n cleanupError = err\n hasCleanupError = true\n }\n }\n unlinkSources(this)\n\n const prevObserver = currentObserver\n const prevOwner = currentOwner\n currentObserver = this\n currentOwner = this\n try {\n // biome-ignore lint/style/noNonNullAssertion: update() only runs for derivations (fn != null).\n this.value = this.fn!()\n } finally {\n currentObserver = prevObserver\n currentOwner = prevOwner\n }\n\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n this.restaleRequested = false\n throw new Error(\n 'MindeesNative: potential infinite reactive loop detected — a computation keeps writing a signal it reads.',\n )\n }\n } while (this.restaleRequested)\n } finally {\n this.running = false\n }\n\n // On the first computation there is no prior value to compare against, so\n // the result is always \"changed\". Afterwards, apply the equality check\n // (unless equals is false, meaning \"always changed\").\n const wasInitialized = this.initialized\n this.initialized = true\n const changed = !wasInitialized || this.equals === false || !this.equals(oldValue, this.value)\n if (changed && this.observers) {\n // Observers are already CHECK from the original push; promote them to DIRTY\n // so the in-flight pull recomputes them.\n for (const o of this.observers) {\n o.state = DIRTY\n }\n }\n\n // The graph is consistent again; now surface any error a previous-run cleanup\n // threw during teardown (the body still re-ran, so children/deps are rebuilt).\n if (hasCleanupError) throw cleanupError\n }\n}\n\n// ---------------------------------------------------------------------------\n// Graph maintenance\n// ---------------------------------------------------------------------------\n\nfunction link(observer: AnyComputation, source: AnyComputation): void {\n // Never subscribe a disposed observer — e.g. a node that disposed itself\n // mid-run and then read another signal. The subscription would leak: nothing\n // tears down a DISPOSED node again.\n if (observer.state === DISPOSED) return\n if (observer.sources === null) observer.sources = []\n const sources = observer.sources\n if (!sources.includes(source)) {\n sources.push(source)\n if (source.observers === null) source.observers = []\n source.observers.push(observer)\n }\n}\n\nfunction unlinkSources(node: AnyComputation): void {\n if (!node.sources) return\n for (const src of node.sources) {\n const obs = src.observers\n if (!obs) continue\n const idx = obs.indexOf(node)\n if (idx >= 0) {\n const last = obs.pop()\n if (last && idx < obs.length) obs[idx] = last\n }\n }\n node.sources = null\n}\n\nfunction disposeChildren(owner: OwnerNode): void {\n // Dispose every owned child AND run every cleanup even if some throw, so a\n // single faulty child/cleanup can't strand the rest or leak observers. `owned`\n // is nulled up front so a throw can't leave a half-disposed array behind.\n // Failures are collected and surfaced together afterward.\n const errors: unknown[] = []\n if (owner.owned) {\n const owned = owner.owned\n owner.owned = null\n for (const child of owned) {\n try {\n disposeComputation(child)\n } catch (err) {\n errors.push(err)\n }\n }\n }\n if (owner.cleanups) {\n const cleanups = owner.cleanups\n owner.cleanups = null\n for (const c of cleanups) {\n try {\n c()\n } catch (err) {\n errors.push(err)\n }\n }\n }\n if (errors.length === 1) throw errors[0]\n if (errors.length > 1) throw new AggregateError(errors, 'disposal threw')\n}\n\nfunction disposeComputation(node: AnyComputation): void {\n if (node.state === DISPOSED) return\n // If a node disposes itself mid-run, stop tracking and adopting onto it for the\n // rest of the (now-aborted) body: a later tracked read would otherwise\n // re-subscribe this DISPOSED node, and onCleanup/adopt would register work on a\n // dead scope — none of which is ever torn down again (a leak). Clearing the\n // globals makes read()/onCleanup/adopt no-op for the remainder of the body;\n // update()'s finally restores the previous owner afterward.\n if (node === currentObserver) currentObserver = null\n if (node === currentOwner) currentOwner = null\n try {\n disposeChildren(node)\n } finally {\n // Always fully unlink + mark disposed, even if a descendant cleanup threw,\n // so this node never leaks as a subscribed zombie. The error (if any) still\n // propagates to the caller, which aggregates it across siblings.\n unlinkSources(node)\n node.observers = null\n node.state = DISPOSED\n // Cancel a pending deferred flush so a torn-down effect never runs against a dead graph.\n // (Always null on the synchronous default path — zero behavior change there.)\n if (node.pendingTask) {\n node.pendingTask.cancel()\n node.pendingTask = null\n }\n }\n}\n\nfunction adopt(node: AnyComputation): void {\n if (!currentOwner) return\n if (currentOwner.owned === null) currentOwner.owned = []\n currentOwner.owned.push(node)\n}\n\n// ---------------------------------------------------------------------------\n// Effect scheduling\n// ---------------------------------------------------------------------------\n\nfunction flushEffects(): void {\n if (flushing) return\n flushing = true\n // Isolate each effect: one throwing effect must not abort the flush or strand\n // the effects queued after it (each effect also self-recovers to CLEAN via\n // updateIfNecessary's finally). Errors are collected and surfaced after drain.\n const errors: unknown[] = []\n try {\n let i = 0\n let iterations = 0\n while (i < effectQueue.length) {\n if (++iterations > MAX_FLUSH_ITERATIONS) {\n effectQueue.length = 0\n throw new Error(\n 'MindeesNative: potential infinite reactive loop detected while flushing effects.',\n )\n }\n const e = effectQueue[i]\n i++\n if (e && e.state !== CLEAN && e.state !== DISPOSED) {\n // Defer when the effect's own lane is 'normal', OR it was staled inside a startTransition\n // (tagged for THIS drain only) — but only if a scheduler is injected. Otherwise sync.\n if (reactiveScheduler && (e.lane === 'normal' || transitionTagged.has(e))) {\n // Deferred lane: hand the flush to the scheduler under a stable key, so rapid re-stales\n // coalesce (latest wins) and the body runs later — reading the LATEST values at run time\n // (updateIfNecessary recomputes sources in order), so glitch-freedom is preserved.\n const node = e\n const sched = reactiveScheduler\n // A transition-tagged sync effect has no key yet; mint a stable one so its re-stales coalesce.\n if (node.schedKey === undefined) node.schedKey = `mindees:effect:${effectKeySeq++}`\n node.pendingTask = sched.schedule(\n () => {\n node.pendingTask = null\n if (node.state !== CLEAN && node.state !== DISPOSED) node.updateIfNecessary()\n },\n { priority: 'normal', key: node.schedKey },\n )\n } else {\n // Synchronous lane — byte-identical to the pre-scheduler behavior (and the path every\n // existing test + SSR takes, since `lane` is 'sync' and/or no scheduler is injected).\n try {\n e.updateIfNecessary()\n } catch (err) {\n errors.push(err)\n }\n }\n }\n }\n } finally {\n effectQueue.length = 0\n transitionTagged.clear() // transition tags apply only to the drain that observed them\n flushing = false\n }\n if (errors.length === 1) throw errors[0]\n if (errors.length > 1) throw new AggregateError(errors, 'effect(s) threw during flush')\n}\n\nfunction attachNode<T, A extends object>(accessor: A, node: Computation<T>): A {\n ;(accessor as A & WithNode<T>)[NODE] = node\n return accessor\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** A read accessor for a derived/reactive value. */\nexport type Accessor<T> = () => T\n\n/** Options accepted by {@link signal}. */\nexport interface SignalOptions<T> {\n /** Custom equality. `false` means \"always notify\" (every write propagates). */\n equals?: EqualsFn<T> | false\n}\n\n/** A writable reactive value: call to read; `.set`/`.update` to write. */\nexport interface Signal<T> {\n /** Read the value (tracks a dependency inside a computation). */\n (): T\n /** Replace the value; returns the new value. */\n set(value: T): T\n /** Update from the previous value; returns the new value. */\n update(fn: (prev: T) => T): T\n /** Read without tracking a dependency. */\n peek(): T\n}\n\n/** Options accepted by {@link computed}. */\nexport interface ComputedOptions<T> {\n /** Custom equality used to decide whether downstream observers re-run. */\n equals?: EqualsFn<T> | false\n}\n\n/** A memoized derived value: call to read; `.peek` to read without tracking. */\nexport interface Memo<T> {\n /** Read the (lazily recomputed) value, tracking a dependency. */\n (): T\n /** Read without tracking a dependency. */\n peek(): T\n}\n\n/**\n * Create a writable reactive value.\n *\n * @example\n * const count = signal(0)\n * count() // read → 0\n * count.set(1) // write\n * count.update(n => n + 1)\n */\nexport function signal<T>(value: T, options?: SignalOptions<T>): Signal<T> {\n const node = new Computation<T>(value, null, options?.equals ?? equalsDefault, false)\n const accessor = (() => node.read()) as Signal<T>\n accessor.set = (v: T) => node.write(v)\n accessor.update = (fn: (prev: T) => T) => node.write(fn(node.value))\n accessor.peek = () => node.value\n return attachNode(accessor, node)\n}\n\n/**\n * Create a memoized derived value. The function re-runs only when one of the\n * reactive values it reads has actually changed, and only when the result is\n * observed (lazy).\n *\n * @example\n * const doubled = computed(() => count() * 2)\n */\nexport function computed<T>(fn: () => T, options?: ComputedOptions<T>): Memo<T> {\n const node = new Computation<T>(undefined as T, fn, options?.equals ?? equalsDefault, false)\n adopt(node)\n const accessor = (() => node.read()) as Memo<T>\n accessor.peek = () => {\n node.updateIfNecessary()\n return node.value\n }\n return attachNode(accessor, node)\n}\n\n/** Alias of {@link computed}. */\nexport const memo = computed\n\n/**\n * Run a side effect that re-runs whenever its reactive dependencies change.\n * Runs once immediately to establish dependencies.\n *\n * To clean up before each re-run and on disposal, either return a cleanup\n * function from the effect, or call {@link onCleanup}. Any non-function return\n * value is ignored (so expression-bodied effects like `() => list.push(x())`\n * are fine).\n *\n * @returns A disposer that stops the effect and runs its cleanups.\n *\n * @example\n * const stop = effect(() => console.log(count()))\n * stop() // unsubscribe\n *\n * @example\n * effect(() => {\n * const id = setInterval(tick, 1000)\n * return () => clearInterval(id) // cleanup\n * })\n */\n/** Options for {@link effect}. */\nexport interface EffectOptions {\n /**\n * `'sync'` (default) flushes the effect inline on every change — the synchronous, glitch-free\n * behavior. `'normal'` defers the effect through the injected {@link setReactiveScheduler scheduler}\n * (interaction priority / deferred heavy work); with no scheduler it falls back to synchronous.\n */\n priority?: Priority\n}\n\nexport function effect(fn: () => void, options?: EffectOptions): () => void {\n const node = new Computation<void>(\n undefined,\n () => {\n const result: unknown = (fn as () => unknown)()\n if (typeof result === 'function') onCleanup(result as () => void)\n },\n false,\n true,\n )\n // Opt into the deferred lane. `effect(fn)` and `effect(fn, { priority: 'sync' })` are identical to\n // before (synchronous flush). `'normal'` only defers once a scheduler is injected.\n if (options?.priority === 'normal') {\n node.lane = 'normal'\n // ALWAYS a unique per-node key: this coalesces THIS effect's own rapid re-stales (latest wins)\n // without ever sharing a scheduler entry with another effect (which would cross-cancel them).\n node.schedKey = `mindees:effect:${effectKeySeq++}`\n }\n adopt(node)\n node.updateIfNecessary() // first run is ALWAYS synchronous (establishes deps + initial paint)\n return () => disposeComputation(node)\n}\n\n/**\n * Apply the writes in `fn` as a low-priority **transition**: the writes take effect immediately\n * (reads inside/after see the latest values), but the effects they invalidate are **deferred**\n * through the injected {@link setReactiveScheduler scheduler} instead of running synchronously — so a\n * heavy re-render triggered by, say, a keystroke doesn't block the interaction. With no scheduler\n * injected, this is a plain synchronous batch (no deferral) — safe for SSR/tests.\n *\n * @example\n * input.set(value) // urgent: the field updates now\n * startTransition(() => query.set(value)) // the expensive results re-render can lag\n */\nexport function startTransition(fn: () => void): void {\n transitionDepth++\n try {\n batch(fn) // coalesce the transition's writes into one flush; effects staled in it get tagged\n } finally {\n transitionDepth--\n }\n}\n\n/**\n * A **deferred view** of `source`: it tracks `source` on the scheduler's low-priority lane, so under\n * sustained updates it lags behind the live value (the React `useDeferredValue` pattern — show stale\n * results while the latest are computed). With no scheduler injected it mirrors `source`\n * synchronously (no lag), so SSR/tests see the live value. Must be created inside an owner.\n */\nexport function deferred<T>(source: Accessor<T>): Accessor<T> {\n const out = signal(source())\n effect(() => out.set(source()), { priority: 'normal' })\n return () => out()\n}\n\n/**\n * Batch multiple writes so dependent effects run once, after the batch. Reads\n * inside a batch still observe the latest written values synchronously.\n */\nexport function batch<T>(fn: () => T): T {\n if (batchDepth > 0) return fn()\n batchDepth++\n try {\n return fn()\n } finally {\n batchDepth--\n flushEffects()\n }\n}\n\n/** Read reactive values without subscribing the current computation to them. */\nexport function untrack<T>(fn: () => T): T {\n const prev = currentObserver\n currentObserver = null\n try {\n return fn()\n } finally {\n currentObserver = prev\n }\n}\n\n/**\n * Register a cleanup to run before the owning computation re-runs and when it\n * is disposed. No-op outside a reactive scope.\n */\nexport function onCleanup(fn: () => void): void {\n if (!currentOwner) return\n if (currentOwner.cleanups === null) currentOwner.cleanups = []\n currentOwner.cleanups.push(fn)\n}\n\n/**\n * Create a non-tracked root scope that owns everything created within it. The\n * scope lives until the provided `dispose` function is called.\n *\n * @example\n * const dispose = createRoot((dispose) => {\n * effect(() => console.log(count()))\n * return dispose\n * })\n * dispose() // tear down the effect\n */\nexport function createRoot<T>(fn: (dispose: () => void) => T): T {\n const root: OwnerNode = { owned: null, cleanups: null }\n const prevObserver = currentObserver\n const prevOwner = currentOwner\n currentObserver = null\n currentOwner = root\n try {\n return fn(() => disposeChildren(root))\n } finally {\n currentObserver = prevObserver\n currentOwner = prevOwner\n }\n}\n\n/** The current owner scope, or `null` outside any reactive scope. */\nexport function getOwner(): Owner | null {\n // OwnerNode → the nominal public Owner. The brand is phantom (never present at\n // runtime), so the only honest way to produce an Owner is through this cast.\n return currentOwner as unknown as Owner | null\n}\n\n/** Run `fn` with `owner` as the active scope (e.g. to re-attach cleanups). */\nexport function runWithOwner<T>(owner: Owner | null, fn: () => T): T {\n const prev = currentOwner\n // `owner` is an opaque public handle; internally it is always an OwnerNode we\n // handed out via getOwner(). This is the one trusted boundary cast.\n currentOwner = owner as unknown as OwnerNode | null\n try {\n return fn()\n } finally {\n currentOwner = prev\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal test helpers (exported from this module only — NOT from the package\n// public entry point). Used to assert white-box invariants like leak-freedom.\n// ---------------------------------------------------------------------------\n\n/** @internal Number of live observers subscribed to the node behind `accessor`. */\nexport function _observerCount(accessor: object): number {\n const node = (accessor as Partial<WithNode<unknown>>)[NODE]\n return node?.observers?.length ?? 0\n}\n\n/** @internal Number of sources the node behind `accessor` depends on. */\nexport function _sourceCount(accessor: object): number {\n const node = (accessor as Partial<WithNode<unknown>>)[NODE]\n return node?.sources?.length ?? 0\n}\n"],"mappings":";AAkEA,MAAM,QAAe;AACrB,MAAM,QAAe;AACrB,MAAM,QAAe;AACrB,MAAM,WAAkB;AASxB,MAAM,iBAAiB,GAAY,MAAwB,OAAO,GAAG,GAAG,CAAC;;AAgBzE,IAAI,kBAAyC;;AAE7C,IAAI,eAAiC;;AAErC,IAAI,aAAa;;AAEjB,MAAM,cAAgC,CAAC;;AAEvC,IAAI,WAAW;;AAEf,MAAM,uBAAuB;;;;;;AAO7B,IAAI,oBAAsC;;AAE1C,IAAI,eAAe;;AAEnB,IAAI,kBAAkB;;AAEtB,MAAM,mCAAmB,IAAI,IAAoB;;;;;;AAOjD,SAAgB,qBAAqB,WAAmC;CACtE,oBAAoB;AACtB;;AAGA,MAAa,OAAsB,OAAO,uBAAuB;AAUjE,IAAM,cAAN,MAA0C;CACxC;CACA;CACA;CACA,UAAmC;CACnC,YAAqC;CACrC,QAAiC;CACjC,WAAqC;CACrC;CACA;;;;;;;CAOA,OAAiB;;CAEjB,cAAoC;;CAEpC;;;;;;;CAOA;;;;;;CAMA,UAAkB;;;;;;;CAOlB,mBAA2B;CAE3B,YAAY,OAAU,IAAsB,QAA6B,UAAmB;EAC1F,KAAK,QAAQ;EACb,KAAK,KAAK;EACV,KAAK,SAAS;EACd,KAAK,WAAW;EAGhB,KAAK,QAAQ,KAAK,QAAQ;EAC1B,KAAK,cAAc,OAAO;CAC5B;;CAGA,OAAU;EACR,IAAI,KAAK,UAAU,UAAU,OAAO,KAAK;EACzC,IAAI,iBAAiB,KAAK,iBAAiB,IAAI;EAC/C,IAAI,KAAK,IAAI,KAAK,kBAAkB;EACpC,OAAO,KAAK;CACd;;CAGA,MAAM,OAAa;EACjB,IAAI,KAAK,WAAW,SAAS,KAAK,OAAO,KAAK,OAAO,KAAK,GAAG,OAAO,KAAK;EACzE,KAAK,QAAQ;EACb,IAAI,KAAK,WACP,KAAK,MAAM,KAAK,KAAK,WAAW,EAAE,UAAU,KAAK;EAEnD,IAAI,eAAe,GAAG,aAAa;EACnC,OAAO;CACT;;CAGA,UAAU,OAAoB;EAM5B,IAAI,KAAK,SAAS;GAChB,KAAK,mBAAmB;GACxB;EACF;EACA,IAAI,KAAK,QAAQ,OAAO;GACtB,MAAM,WAAW,KAAK,UAAU;GAChC,KAAK,QAAQ;GACb,IAAI,KAAK,YAAY,UAAU;IAC7B,YAAY,KAAK,IAAI;IAGrB,IAAI,kBAAkB,KAAK,qBAAqB,KAAK,SAAS,QAC5D,iBAAiB,IAAI,IAAI;GAE7B;GACA,IAAI,KAAK,WACP,KAAK,MAAM,KAAK,KAAK,WAAW,EAAE,UAAU,KAAK;EAErD;CACF;;CAGA,oBAA0B;EACxB,IAAI,KAAK,UAAU,SAAS,KAAK,UAAU,UAAU;EACrD,IAAI,KAAK,UAAU,SAAS,KAAK,SAC/B,KAAK,MAAM,OAAO,KAAK,SAAS;GAC9B,IAAI,kBAAkB;GACtB,IAAI,KAAK,UAAU,OAAO;EAC5B;EAEF,IAAI;GACF,IAAI,KAAK,UAAU,OAAO,KAAK,OAAO;EACxC,UAAU;GAKR,IAAI,KAAK,UAAU,UAAU,KAAK,QAAQ;EAC5C;CACF;;;;;;;;;;;;;;CAeA,SAAuB;EACrB,MAAM,WAAW,KAAK;EACtB,IAAI;EACJ,IAAI,kBAAkB;EACtB,IAAI,aAAa;EACjB,KAAK,UAAU;EACf,IAAI;GACF,GAAG;IACD,KAAK,mBAAmB;IACxB,IAAI;KACF,gBAAgB,IAAI;IACtB,SAAS,KAAK;KACZ,IAAI,CAAC,iBAAiB;MACpB,eAAe;MACf,kBAAkB;KACpB;IACF;IACA,cAAc,IAAI;IAElB,MAAM,eAAe;IACrB,MAAM,YAAY;IAClB,kBAAkB;IAClB,eAAe;IACf,IAAI;KAEF,KAAK,QAAQ,KAAK,GAAI;IACxB,UAAU;KACR,kBAAkB;KAClB,eAAe;IACjB;IAEA,IAAI,EAAE,aAAa,sBAAsB;KACvC,KAAK,mBAAmB;KACxB,MAAM,IAAI,MACR,2GACF;IACF;GACF,SAAS,KAAK;EAChB,UAAU;GACR,KAAK,UAAU;EACjB;EAKA,MAAM,iBAAiB,KAAK;EAC5B,KAAK,cAAc;EAEnB,KADgB,CAAC,kBAAkB,KAAK,WAAW,SAAS,CAAC,KAAK,OAAO,UAAU,KAAK,KAAK,MAC9E,KAAK,WAGlB,KAAK,MAAM,KAAK,KAAK,WACnB,EAAE,QAAQ;EAMd,IAAI,iBAAiB,MAAM;CAC7B;AACF;AAMA,SAAS,KAAK,UAA0B,QAA8B;CAIpE,IAAI,SAAS,UAAU,UAAU;CACjC,IAAI,SAAS,YAAY,MAAM,SAAS,UAAU,CAAC;CACnD,MAAM,UAAU,SAAS;CACzB,IAAI,CAAC,QAAQ,SAAS,MAAM,GAAG;EAC7B,QAAQ,KAAK,MAAM;EACnB,IAAI,OAAO,cAAc,MAAM,OAAO,YAAY,CAAC;EACnD,OAAO,UAAU,KAAK,QAAQ;CAChC;AACF;AAEA,SAAS,cAAc,MAA4B;CACjD,IAAI,CAAC,KAAK,SAAS;CACnB,KAAK,MAAM,OAAO,KAAK,SAAS;EAC9B,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK;EACV,MAAM,MAAM,IAAI,QAAQ,IAAI;EAC5B,IAAI,OAAO,GAAG;GACZ,MAAM,OAAO,IAAI,IAAI;GACrB,IAAI,QAAQ,MAAM,IAAI,QAAQ,IAAI,OAAO;EAC3C;CACF;CACA,KAAK,UAAU;AACjB;AAEA,SAAS,gBAAgB,OAAwB;CAK/C,MAAM,SAAoB,CAAC;CAC3B,IAAI,MAAM,OAAO;EACf,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ;EACd,KAAK,MAAM,SAAS,OAClB,IAAI;GACF,mBAAmB,KAAK;EAC1B,SAAS,KAAK;GACZ,OAAO,KAAK,GAAG;EACjB;CAEJ;CACA,IAAI,MAAM,UAAU;EAClB,MAAM,WAAW,MAAM;EACvB,MAAM,WAAW;EACjB,KAAK,MAAM,KAAK,UACd,IAAI;GACF,EAAE;EACJ,SAAS,KAAK;GACZ,OAAO,KAAK,GAAG;EACjB;CAEJ;CACA,IAAI,OAAO,WAAW,GAAG,MAAM,OAAO;CACtC,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,eAAe,QAAQ,gBAAgB;AAC1E;AAEA,SAAS,mBAAmB,MAA4B;CACtD,IAAI,KAAK,UAAU,UAAU;CAO7B,IAAI,SAAS,iBAAiB,kBAAkB;CAChD,IAAI,SAAS,cAAc,eAAe;CAC1C,IAAI;EACF,gBAAgB,IAAI;CACtB,UAAU;EAIR,cAAc,IAAI;EAClB,KAAK,YAAY;EACjB,KAAK,QAAQ;EAGb,IAAI,KAAK,aAAa;GACpB,KAAK,YAAY,OAAO;GACxB,KAAK,cAAc;EACrB;CACF;AACF;AAEA,SAAS,MAAM,MAA4B;CACzC,IAAI,CAAC,cAAc;CACnB,IAAI,aAAa,UAAU,MAAM,aAAa,QAAQ,CAAC;CACvD,aAAa,MAAM,KAAK,IAAI;AAC9B;AAMA,SAAS,eAAqB;CAC5B,IAAI,UAAU;CACd,WAAW;CAIX,MAAM,SAAoB,CAAC;CAC3B,IAAI;EACF,IAAI,IAAI;EACR,IAAI,aAAa;EACjB,OAAO,IAAI,YAAY,QAAQ;GAC7B,IAAI,EAAE,aAAa,sBAAsB;IACvC,YAAY,SAAS;IACrB,MAAM,IAAI,MACR,kFACF;GACF;GACA,MAAM,IAAI,YAAY;GACtB;GACA,IAAI,KAAK,EAAE,UAAU,SAAS,EAAE,UAAU,UAGxC,IAAI,sBAAsB,EAAE,SAAS,YAAY,iBAAiB,IAAI,CAAC,IAAI;IAIzE,MAAM,OAAO;IACb,MAAM,QAAQ;IAEd,IAAI,KAAK,aAAa,KAAA,GAAW,KAAK,WAAW,kBAAkB;IACnE,KAAK,cAAc,MAAM,eACjB;KACJ,KAAK,cAAc;KACnB,IAAI,KAAK,UAAU,SAAS,KAAK,UAAU,UAAU,KAAK,kBAAkB;IAC9E,GACA;KAAE,UAAU;KAAU,KAAK,KAAK;IAAS,CAC3C;GACF,OAGE,IAAI;IACF,EAAE,kBAAkB;GACtB,SAAS,KAAK;IACZ,OAAO,KAAK,GAAG;GACjB;EAGN;CACF,UAAU;EACR,YAAY,SAAS;EACrB,iBAAiB,MAAM;EACvB,WAAW;CACb;CACA,IAAI,OAAO,WAAW,GAAG,MAAM,OAAO;CACtC,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,eAAe,QAAQ,8BAA8B;AACxF;AAEA,SAAS,WAAgC,UAAa,MAAyB;CAC5E,SAA8B,QAAQ;CACvC,OAAO;AACT;;;;;;;;;;AAkDA,SAAgB,OAAU,OAAU,SAAuC;CACzE,MAAM,OAAO,IAAI,YAAe,OAAO,MAAM,SAAS,UAAU,eAAe,KAAK;CACpF,MAAM,kBAAkB,KAAK,KAAK;CAClC,SAAS,OAAO,MAAS,KAAK,MAAM,CAAC;CACrC,SAAS,UAAU,OAAuB,KAAK,MAAM,GAAG,KAAK,KAAK,CAAC;CACnE,SAAS,aAAa,KAAK;CAC3B,OAAO,WAAW,UAAU,IAAI;AAClC;;;;;;;;;AAUA,SAAgB,SAAY,IAAa,SAAuC;CAC9E,MAAM,OAAO,IAAI,YAAe,KAAA,GAAgB,IAAI,SAAS,UAAU,eAAe,KAAK;CAC3F,MAAM,IAAI;CACV,MAAM,kBAAkB,KAAK,KAAK;CAClC,SAAS,aAAa;EACpB,KAAK,kBAAkB;EACvB,OAAO,KAAK;CACd;CACA,OAAO,WAAW,UAAU,IAAI;AAClC;;AAGA,MAAa,OAAO;AAiCpB,SAAgB,OAAO,IAAgB,SAAqC;CAC1E,MAAM,OAAO,IAAI,YACf,KAAA,SACM;EACJ,MAAM,SAAmB,GAAqB;EAC9C,IAAI,OAAO,WAAW,YAAY,UAAU,MAAoB;CAClE,GACA,OACA,IACF;CAGA,IAAI,SAAS,aAAa,UAAU;EAClC,KAAK,OAAO;EAGZ,KAAK,WAAW,kBAAkB;CACpC;CACA,MAAM,IAAI;CACV,KAAK,kBAAkB;CACvB,aAAa,mBAAmB,IAAI;AACtC;;;;;;;;;;;;AAaA,SAAgB,gBAAgB,IAAsB;CACpD;CACA,IAAI;EACF,MAAM,EAAE;CACV,UAAU;EACR;CACF;AACF;;;;;;;AAQA,SAAgB,SAAY,QAAkC;CAC5D,MAAM,MAAM,OAAO,OAAO,CAAC;CAC3B,aAAa,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,UAAU,SAAS,CAAC;CACtD,aAAa,IAAI;AACnB;;;;;AAMA,SAAgB,MAAS,IAAgB;CACvC,IAAI,aAAa,GAAG,OAAO,GAAG;CAC9B;CACA,IAAI;EACF,OAAO,GAAG;CACZ,UAAU;EACR;EACA,aAAa;CACf;AACF;;AAGA,SAAgB,QAAW,IAAgB;CACzC,MAAM,OAAO;CACb,kBAAkB;CAClB,IAAI;EACF,OAAO,GAAG;CACZ,UAAU;EACR,kBAAkB;CACpB;AACF;;;;;AAMA,SAAgB,UAAU,IAAsB;CAC9C,IAAI,CAAC,cAAc;CACnB,IAAI,aAAa,aAAa,MAAM,aAAa,WAAW,CAAC;CAC7D,aAAa,SAAS,KAAK,EAAE;AAC/B;;;;;;;;;;;;AAaA,SAAgB,WAAc,IAAmC;CAC/D,MAAM,OAAkB;EAAE,OAAO;EAAM,UAAU;CAAK;CACtD,MAAM,eAAe;CACrB,MAAM,YAAY;CAClB,kBAAkB;CAClB,eAAe;CACf,IAAI;EACF,OAAO,SAAS,gBAAgB,IAAI,CAAC;CACvC,UAAU;EACR,kBAAkB;EAClB,eAAe;CACjB;AACF;;AAGA,SAAgB,WAAyB;CAGvC,OAAO;AACT;;AAGA,SAAgB,aAAgB,OAAqB,IAAgB;CACnE,MAAM,OAAO;CAGb,eAAe;CACf,IAAI;EACF,OAAO,GAAG;CACZ,UAAU;EACR,eAAe;CACjB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","names":[],"sources":["../../src/scheduler/scheduler.ts"],"mappings":";;AAmBA;;;;AAAoB;AAGpB;;;;AAAgB;AAGhB;;;;;;;KANY,QAAA;AAaP;AAAA,KAVO,IAAA;;UAGK,eAAA;EAaf;EAXA,QAAA,GAAW,QAAQ;EAsBJ;;;;EAjBf,GAAA;AAAA;;UAIe,aAAA;EAsBoB;EApBnC,MAAA;EAiCW;EAAA,SA/BF,OAAO;AAAA;;UASD,gBAAA;EAqCgB;;;;EAhC/B,OAAA,IAAW,KAAA;EAmBM;;;EAfjB,iBAAA,IAAqB,EAAA;AAAA;;;;cAaV,SAAA;EAAA,iBACM,IAAA;EAAA,iBACA,MAAA;EAAA,iBACA,KAAA;EAAA,QACT,eAAA;EAAA,QACA,QAAA;EAAA,iBACS,OAAA;EAAA,iBACA,iBAAA;cAEL,OAAA,GAAU,gBAAA;EAuDd;EAjDR,QAAA,CAAS,IAAA,EAAM,IAAA,EAAM,OAAA,GAAU,eAAA,GAAkB,aAAA;EAwFzC;EAnER,SAAA;EAyEkB;EAAA,IApDd,IAAA;EAAA,QAOI,YAAA;EAAA,QASA,GAAA;;;;;;;AAkD4D;UApB5D,QAAA;EAAA,QAMA,UAAA;AAAA;;iBAcM,eAAA,CAAgB,OAAA,GAAU,gBAAA,GAAmB,SAAS"}
1
+ {"version":3,"file":"scheduler.d.ts","names":[],"sources":["../../src/scheduler/scheduler.ts"],"mappings":";;AAmBA;;;;AAAoB;AAGpB;;;;AAAgB;AAGhB;;;;;;;KANY,QAAA;AAaP;AAAA,KAVO,IAAA;;UAGK,eAAA;EAiBf;EAfA,QAAA,GAAW,QAAQ;EA0BJ;;;;EArBf,GAAA;AAAA;;UAQe,aAAA;EAsBoB;EApBnC,MAAA;EAiCW;EAAA,SA/BF,OAAO;AAAA;;UASD,gBAAA;EAqCgB;;;;EAhC/B,OAAA,IAAW,KAAA;EAmBM;;;EAfjB,iBAAA,IAAqB,EAAA;AAAA;;;;cAaV,SAAA;EAAA,iBACM,IAAA;EAAA,iBACA,MAAA;EAAA,iBACA,KAAA;EAAA,QACT,eAAA;EAAA,QACA,QAAA;EAAA,iBACS,OAAA;EAAA,iBACA,iBAAA;cAEL,OAAA,GAAU,gBAAA;EAsEd;EAhER,QAAA,CAAS,IAAA,EAAM,IAAA,EAAM,OAAA,GAAU,eAAA,GAAkB,aAAA;EAuGzC;EAlFR,SAAA;EAwFkB;EAAA,IApDd,IAAA;EAAA,QAOI,YAAA;EAAA,QASA,GAAA;;;;;;;AAkD4D;UApB5D,QAAA;EAAA,QAMA,UAAA;AAAA;;iBAcM,eAAA,CAAgB,OAAA,GAAU,gBAAA,GAAmB,SAAS"}