@vielzeug/ripple 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +9 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_error-utils.cjs +2 -0
- package/dist/_error-utils.cjs.map +1 -0
- package/dist/_error-utils.d.ts +24 -0
- package/dist/_error-utils.d.ts.map +1 -0
- package/dist/_error-utils.js +20 -0
- package/dist/_error-utils.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +7 -0
- package/dist/async-computed.cjs +2 -0
- package/dist/async-computed.cjs.map +1 -0
- package/dist/async-computed.d.ts +36 -0
- package/dist/async-computed.d.ts.map +1 -0
- package/dist/async-computed.js +58 -0
- package/dist/async-computed.js.map +1 -0
- package/dist/computed.cjs +2 -0
- package/dist/computed.cjs.map +1 -0
- package/dist/computed.d.ts +26 -0
- package/dist/computed.d.ts.map +1 -0
- package/dist/computed.js +113 -0
- package/dist/computed.js.map +1 -0
- package/dist/devtools-hook.cjs +2 -0
- package/dist/devtools-hook.cjs.map +1 -0
- package/dist/devtools-hook.d.ts +4 -0
- package/dist/devtools-hook.d.ts.map +1 -0
- package/dist/devtools-hook.js +8 -0
- package/dist/devtools-hook.js.map +1 -0
- package/dist/devtools.d.ts +39 -0
- package/dist/devtools.d.ts.map +1 -0
- package/dist/effect.cjs +2 -0
- package/dist/effect.cjs.map +1 -0
- package/dist/effect.d.ts +104 -0
- package/dist/effect.d.ts.map +1 -0
- package/dist/effect.js +173 -0
- package/dist/effect.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/reactive-base.cjs +2 -0
- package/dist/reactive-base.cjs.map +1 -0
- package/dist/reactive-base.d.ts +60 -0
- package/dist/reactive-base.d.ts.map +1 -0
- package/dist/reactive-base.js +56 -0
- package/dist/reactive-base.js.map +1 -0
- package/dist/ripple.cjs +2 -0
- package/dist/ripple.cjs.map +1 -0
- package/dist/ripple.iife.js +2 -0
- package/dist/ripple.iife.js.map +1 -0
- package/dist/ripple.js +2 -0
- package/dist/ripple.js.map +1 -0
- package/dist/scheduling.cjs +2 -0
- package/dist/scheduling.cjs.map +1 -0
- package/dist/scheduling.d.ts +5 -0
- package/dist/scheduling.d.ts.map +1 -0
- package/dist/scheduling.js +57 -0
- package/dist/scheduling.js.map +1 -0
- package/dist/signal.cjs +2 -0
- package/dist/signal.cjs.map +1 -0
- package/dist/signal.d.ts +24 -0
- package/dist/signal.d.ts.map +1 -0
- package/dist/signal.js +54 -0
- package/dist/signal.js.map +1 -0
- package/dist/src/devtools.cjs +2 -0
- package/dist/src/devtools.cjs.map +1 -0
- package/dist/src/devtools.js +36 -0
- package/dist/src/devtools.js.map +1 -0
- package/dist/src/ssr/index.cjs +2 -0
- package/dist/src/ssr/index.cjs.map +1 -0
- package/dist/src/ssr/index.js +38 -0
- package/dist/src/ssr/index.js.map +1 -0
- package/dist/ssr/index.d.ts +56 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/store-history.cjs +2 -0
- package/dist/store-history.cjs.map +1 -0
- package/dist/store-history.d.ts +42 -0
- package/dist/store-history.d.ts.map +1 -0
- package/dist/store-history.js +60 -0
- package/dist/store-history.js.map +1 -0
- package/dist/store.cjs +2 -0
- package/dist/store.cjs.map +1 -0
- package/dist/store.d.ts +45 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +204 -0
- package/dist/store.js.map +1 -0
- package/dist/subscription.cjs +2 -0
- package/dist/subscription.cjs.map +1 -0
- package/dist/subscription.d.ts +22 -0
- package/dist/subscription.d.ts.map +1 -0
- package/dist/subscription.js +47 -0
- package/dist/subscription.js.map +1 -0
- package/dist/symbols.cjs +2 -0
- package/dist/symbols.cjs.map +1 -0
- package/dist/symbols.d.ts +6 -0
- package/dist/symbols.d.ts.map +1 -0
- package/dist/symbols.js +6 -0
- package/dist/symbols.js.map +1 -0
- package/dist/tracking.cjs +2 -0
- package/dist/tracking.cjs.map +1 -0
- package/dist/tracking.d.ts +82 -0
- package/dist/tracking.d.ts.map +1 -0
- package/dist/tracking.js +76 -0
- package/dist/tracking.js.map +1 -0
- package/dist/types.d.ts +315 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utilities.cjs +2 -0
- package/dist/utilities.cjs.map +1 -0
- package/dist/utilities.d.ts +55 -0
- package/dist/utilities.d.ts.map +1 -0
- package/dist/utilities.js +25 -0
- package/dist/utilities.js.map +1 -0
- package/package.json +52 -0
package/dist/tracking.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/tracking.ts
|
|
2
|
+
var e = 0, t = () => ++e, n = () => e, r = () => ({
|
|
3
|
+
activeDirty: "a",
|
|
4
|
+
batchDepth: 0,
|
|
5
|
+
dirtyWithEffectSubsA: /* @__PURE__ */ new Set(),
|
|
6
|
+
dirtyWithEffectSubsB: /* @__PURE__ */ new Set(),
|
|
7
|
+
pendingSubscribers: /* @__PURE__ */ new Set()
|
|
8
|
+
}), i = {
|
|
9
|
+
scheduling: r(),
|
|
10
|
+
scopeCleanups: null,
|
|
11
|
+
tracking: null
|
|
12
|
+
}, a = null, o = () => a === null ? i : a.get(), s = () => o().scheduling, c = () => a !== null, l = () => o().tracking, u = (e, t) => {
|
|
13
|
+
if (a !== null) {
|
|
14
|
+
let n = a.get();
|
|
15
|
+
return a.run({
|
|
16
|
+
...n,
|
|
17
|
+
tracking: e
|
|
18
|
+
}, t);
|
|
19
|
+
}
|
|
20
|
+
let n = i;
|
|
21
|
+
i = {
|
|
22
|
+
...i,
|
|
23
|
+
tracking: e
|
|
24
|
+
};
|
|
25
|
+
try {
|
|
26
|
+
return t();
|
|
27
|
+
} finally {
|
|
28
|
+
i = n;
|
|
29
|
+
}
|
|
30
|
+
}, d = (e, t) => {
|
|
31
|
+
if (a !== null) {
|
|
32
|
+
let n = a.get();
|
|
33
|
+
return a.run({
|
|
34
|
+
...n,
|
|
35
|
+
scopeCleanups: e
|
|
36
|
+
}, t);
|
|
37
|
+
}
|
|
38
|
+
let n = i;
|
|
39
|
+
i = {
|
|
40
|
+
...i,
|
|
41
|
+
scopeCleanups: e
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
return t();
|
|
45
|
+
} finally {
|
|
46
|
+
i = n;
|
|
47
|
+
}
|
|
48
|
+
}, f = () => o().scopeCleanups, p = (e) => {
|
|
49
|
+
let t = l();
|
|
50
|
+
t?.kind === "effect" ? t.cleanups.push(e) : f()?.push(e);
|
|
51
|
+
}, m = (e) => {
|
|
52
|
+
let t = a;
|
|
53
|
+
return a = e, t;
|
|
54
|
+
}, h = (e, t) => {
|
|
55
|
+
let n = l();
|
|
56
|
+
return n === null ? t() : u({
|
|
57
|
+
...n,
|
|
58
|
+
sourceObserver: e
|
|
59
|
+
}, t);
|
|
60
|
+
}, g = (e) => u(null, e), _ = (e) => {
|
|
61
|
+
let t = l();
|
|
62
|
+
if (t !== null) {
|
|
63
|
+
if (t.sourceObserver?.(e), t.kind === "computed") t.depCollector.push({
|
|
64
|
+
source: e,
|
|
65
|
+
version: e.version
|
|
66
|
+
});
|
|
67
|
+
else if (t.kind === "effect") {
|
|
68
|
+
let n = t.effect;
|
|
69
|
+
e.addEffectSub(n), t.subscriptions.add(() => e.removeEffectSub(n)), t.deps.set(e, e.version);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
//#endregion
|
|
74
|
+
export { m as _installContextHook, p as autoRegisterDisposal, r as createSchedulingState, n as getRevision, s as getSchedulingState, f as getScopeCleanups, l as getTracking, c as hasContextHook, t as tickRevision, _ as trackSource, g as untrack, d as withScopeCleanups, h as withSourceObserver, u as withTracking };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=tracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracking.js","names":[],"sources":["../src/tracking.ts"],"sourcesContent":["import type { ComputedBase, ReactiveBase } from './reactive-base';\nimport type { CleanupFn, Subscriber } from './types';\n\n// ── Global revision clock ─────────────────────────────────────────────────────\n//\n// Monotonically-increasing counter incremented on every signal write.\n// ComputedImpl records the clock value after each successful recompute and uses\n// it as an O(1) \"nothing has changed globally\" fast-path check in refreshIfDirty.\n\nlet globalRevision = 0;\n\nexport const tickRevision = (): number => ++globalRevision;\nexport const getRevision = (): number => globalRevision;\n\n// ── Internal types ────────────────────────────────────────────────────────────\n\nexport type DepEntry = {\n source: ReactiveBase<unknown>;\n version: number;\n};\n\n/** Called by trackSource to observe each reactive source accessed during a tracked run. */\nexport type SourceObserver = (source: ReactiveBase<unknown>) => void;\n\n// TrackingCtx carries both dep-collection state AND an optional sourceObserver.\n// Putting the observer inside the context (R12) scopes it to the specific effect/computed\n// run rather than making it a process-wide global — nested computed recomputes use their\n// own context (no observer), so the debugEffect pattern works without identity checks.\n// sourceObserver is shared across both branches and lives outside the discriminant union.\nexport type TrackingCtx = {\n sourceObserver?: SourceObserver;\n} & (\n | {\n computed: ComputedBase<unknown>;\n depCollector: DepEntry[];\n kind: 'computed';\n }\n | {\n cleanups: CleanupFn[];\n deps: Map<ReactiveBase<unknown>, number>;\n effect: Subscriber;\n kind: 'effect';\n subscriptions: Set<CleanupFn>;\n }\n);\n\n// ── Scheduling state ────────────────────────────────────────────────────────\n//\n// Colocated here (rather than in scheduling.ts) so it can be a field of\n// ExecutionContext without a runtime circular import between tracking.ts and\n// scheduling.ts — scheduling.ts only needs `getSchedulingState()` and the\n// `SchedulingState` type (type-only import, erased at compile time).\n//\n// Isolating this per-request (via the SSR hook) closes the documented gap where\n// concurrent SSR requests share one flush queue: `batchDepth`, `pendingSubscribers`,\n// and the dirty-computed sets are the only scheduling fields that can observably\n// leak across requests (they persist across `await` boundaries via `batch()`\n// spanning shared module-level signals). The propagation epoch/stack in\n// scheduling.ts stay module-level scratch memory — they're only touched within a\n// single synchronous call stack, which JS's run-to-completion model already isolates.\n\nexport type SchedulingState = {\n activeDirty: 'a' | 'b';\n batchDepth: number;\n readonly dirtyWithEffectSubsA: Set<ComputedBase<unknown>>;\n readonly dirtyWithEffectSubsB: Set<ComputedBase<unknown>>;\n readonly pendingSubscribers: Set<Subscriber>;\n};\n\nexport const createSchedulingState = (): SchedulingState => ({\n activeDirty: 'a',\n batchDepth: 0,\n dirtyWithEffectSubsA: new Set(),\n dirtyWithEffectSubsB: new Set(),\n pendingSubscribers: new Set(),\n});\n\n// ── ExecutionContext ──────────────────────────────────────────────────────────\n//\n// Unified context replaces two separate globals (_tracking and _scopeStack).\n// Both the dep-tracking context and the innermost scope's cleanup array live here.\n// The SSR hook overrides the entire context per-request — fixing the prior bug\n// where scope cleanups were always a process-wide singleton even with the hook.\n\nexport type ExecutionContext = {\n readonly scheduling: SchedulingState;\n readonly scopeCleanups: CleanupFn[] | null;\n readonly tracking: TrackingCtx | null;\n};\n\nexport type ContextHook = {\n get(): ExecutionContext;\n run<T>(ctx: ExecutionContext, fn: () => T): T;\n};\n\nlet _ctx: ExecutionContext = { scheduling: createSchedulingState(), scopeCleanups: null, tracking: null };\nlet _hook: ContextHook | null = null;\n\nconst getCtx = (): ExecutionContext => (_hook !== null ? _hook.get() : _ctx);\n\n/** Returns the scheduling-state bucket for the active execution context (module-level singleton outside SSR). */\nexport const getSchedulingState = (): SchedulingState => getCtx().scheduling;\n\n/** `true` once an SSR context hook is installed — scheduling state is then request-isolated. */\nexport const hasContextHook = (): boolean => _hook !== null;\n\n// ── Tracking ──────────────────────────────────────────────────────────────────\n\nexport const getTracking = (): TrackingCtx | null => getCtx().tracking;\n\nexport const withTracking = <T>(tracking: TrackingCtx | null, fn: () => T): T => {\n if (_hook !== null) {\n const current = _hook.get();\n\n return _hook.run({ ...current, tracking }, fn);\n }\n\n const prev = _ctx;\n\n _ctx = { ..._ctx, tracking };\n\n try {\n return fn();\n } finally {\n _ctx = prev;\n }\n};\n\n// ── Scope cleanup ─────────────────────────────────────────────────────────────\n\n/**\n * Pushes `cleanups` as the active scope cleanup array for the duration of `fn`.\n * Any `onCleanup()` calls inside `fn` will register into these cleanups.\n * Effects and computed values created inside `fn` are also auto-registered.\n */\nexport const withScopeCleanups = <T>(cleanups: CleanupFn[], fn: () => T): T => {\n if (_hook !== null) {\n const current = _hook.get();\n\n return _hook.run({ ...current, scopeCleanups: cleanups }, fn);\n }\n\n const prev = _ctx;\n\n _ctx = { ..._ctx, scopeCleanups: cleanups };\n\n try {\n return fn();\n } finally {\n _ctx = prev;\n }\n};\n\n/**\n * Returns the cleanup array of the innermost active scope, or `null` if not inside a scope.\n */\nexport const getScopeCleanups = (): CleanupFn[] | null => getCtx().scopeCleanups;\n\n// ── Auto-disposal ───────────────────────────────────────────────────────────────\n//\n// Shared by every primitive that ties its own lifetime to the context it was\n// created in (computed(), resource()): dispose when the enclosing effect re-runs\n// or disposes, or — if not inside an effect — when the enclosing scope disposes.\n// No-op if neither is active (the caller owns disposal directly).\n\n/**\n * Registers `dispose` to run when the enclosing effect re-runs/disposes, or —\n * if there is no enclosing effect — when the enclosing scope disposes.\n */\nexport const autoRegisterDisposal = (dispose: CleanupFn): void => {\n const ctx = getTracking();\n\n if (ctx?.kind === 'effect') {\n ctx.cleanups.push(dispose);\n } else {\n getScopeCleanups()?.push(dispose);\n }\n};\n\n// ── Context hook (for SSR) ────────────────────────────────────────────────────\n\n/**\n * @internal Used only by `/ripple/ssr`.\n * Installs a context hook that overrides both tracking and scope-cleanup access.\n * Returns the previous hook so callers can restore it.\n */\nexport const _installContextHook = (hook: ContextHook | null): ContextHook | null => {\n const prev = _hook;\n\n _hook = hook;\n\n return prev;\n};\n\n// ── Source observer ───────────────────────────────────────────────────────────\n//\n// Observer is now scoped to the active TrackingCtx instead of a process-wide global.\n// This means it only fires for direct deps of the current effect/computed — nested\n// computed recomputes use their own context (no observer) so no identity check needed.\n\n/**\n * Runs `fn` while calling `observer` for every reactive source directly accessed.\n * Used by `debugEffect` to detect which sources changed between runs.\n * No-op if called outside an active tracking context.\n */\nexport const withSourceObserver = <T>(observer: SourceObserver, fn: () => T): T => {\n const current = getTracking();\n\n if (current === null) return fn();\n\n return withTracking({ ...current, sourceObserver: observer }, fn);\n};\n\n// ── untrack ───────────────────────────────────────────────────────────────────\n\n/**\n * Runs `fn` without recording any reactive reads as dependencies of the enclosing\n * effect or computed. Useful when you need to read reactive state \"silently\".\n *\n * @example\n * ```ts\n * effect(() => {\n * const a = count.value; // tracked\n * const b = untrack(() => name.value); // NOT tracked — no re-run when name changes\n * });\n * ```\n */\nexport const untrack = <T>(fn: () => T): T => withTracking(null, fn);\n\n// ── trackSource ───────────────────────────────────────────────────────────────\n//\n// Records `source` as a dependency of the currently active tracking context.\n// For computed contexts: only records the dep entry — addComputedSub is called\n// later by updateDeps() in computed.ts (only for genuinely NEW deps, preventing\n// duplicate WeakRef entries).\n// For effect contexts: immediately subscribes the effect to the source and\n// records the dep for getDependencies().\n\nexport const trackSource = (source: ReactiveBase<unknown>): void => {\n const ctx = getTracking();\n\n if (ctx === null) return;\n\n ctx.sourceObserver?.(source);\n\n if (ctx.kind === 'computed') {\n ctx.depCollector.push({ source, version: source.version });\n } else if (ctx.kind === 'effect') {\n const owner = ctx.effect;\n\n source.addEffectSub(owner);\n ctx.subscriptions.add(() => source.removeEffectSub(owner));\n ctx.deps.set(source, source.version);\n }\n};\n"],"mappings":";AASA,IAAI,IAAiB,GAER,UAA6B,EAAE,GAC/B,UAA4B,GAyD5B,WAAgD;CAC3D,aAAa;CACb,YAAY;CACZ,sCAAsB,IAAI,IAAI;CAC9B,sCAAsB,IAAI,IAAI;CAC9B,oCAAoB,IAAI,IAAI;AAC9B,IAoBI,IAAyB;CAAE,YAAY,EAAsB;CAAG,eAAe;CAAM,UAAU;AAAK,GACpG,IAA4B,MAE1B,UAAkC,MAAU,OAAqB,IAAd,EAAM,IAAI,GAGtD,UAA4C,EAAO,CAAC,CAAC,YAGrD,UAAgC,MAAU,MAI1C,UAAwC,EAAO,CAAC,CAAC,UAEjD,KAAmB,GAA8B,MAAmB;CAC/E,IAAI,MAAU,MAAM;EAClB,IAAM,IAAU,EAAM,IAAI;EAE1B,OAAO,EAAM,IAAI;GAAE,GAAG;GAAS;EAAS,GAAG,CAAE;CAC/C;CAEA,IAAM,IAAO;CAEb,IAAO;EAAE,GAAG;EAAM;CAAS;CAE3B,IAAI;EACF,OAAO,EAAG;CACZ,UAAU;EACR,IAAO;CACT;AACF,GASa,KAAwB,GAAuB,MAAmB;CAC7E,IAAI,MAAU,MAAM;EAClB,IAAM,IAAU,EAAM,IAAI;EAE1B,OAAO,EAAM,IAAI;GAAE,GAAG;GAAS,eAAe;EAAS,GAAG,CAAE;CAC9D;CAEA,IAAM,IAAO;CAEb,IAAO;EAAE,GAAG;EAAM,eAAe;CAAS;CAE1C,IAAI;EACF,OAAO,EAAG;CACZ,UAAU;EACR,IAAO;CACT;AACF,GAKa,UAA6C,EAAO,CAAC,CAAC,eAatD,KAAwB,MAA6B;CAChE,IAAM,IAAM,EAAY;CAExB,AAAI,GAAK,SAAS,WAChB,EAAI,SAAS,KAAK,CAAO,IAEzB,EAAiB,CAAC,EAAE,KAAK,CAAO;AAEpC,GASa,KAAuB,MAAiD;CACnF,IAAM,IAAO;CAIb,OAFA,IAAQ,GAED;AACT,GAaa,KAAyB,GAA0B,MAAmB;CACjF,IAAM,IAAU,EAAY;CAI5B,OAFI,MAAY,OAAa,EAAG,IAEzB,EAAa;EAAE,GAAG;EAAS,gBAAgB;CAAS,GAAG,CAAE;AAClE,GAgBa,KAAc,MAAmB,EAAa,MAAM,CAAE,GAWtD,KAAe,MAAwC;CAClE,IAAM,IAAM,EAAY;CAEpB,UAAQ,MAIZ;MAFA,EAAI,iBAAiB,CAAM,GAEvB,EAAI,SAAS,YACf,EAAI,aAAa,KAAK;GAAE;GAAQ,SAAS,EAAO;EAAQ,CAAC;OACpD,IAAI,EAAI,SAAS,UAAU;GAChC,IAAM,IAAQ,EAAI;GAIlB,AAFA,EAAO,aAAa,CAAK,GACzB,EAAI,cAAc,UAAU,EAAO,gBAAgB,CAAK,CAAC,GACzD,EAAI,KAAK,IAAI,GAAQ,EAAO,OAAO;EACrC;;AACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
export type CleanupFn = () => void;
|
|
2
|
+
export type EffectCallback = () => CleanupFn | void;
|
|
3
|
+
export type AsyncEffectCallback = (signal: AbortSignal, owner: Scope) => Promise<CleanupFn | void>;
|
|
4
|
+
export type EqualityFn<T> = (a: T, b: T) => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Controls when an effect re-runs after a dependency changes.
|
|
7
|
+
* - `'sync'` (default): runs immediately in the same flush.
|
|
8
|
+
* - `'microtask'`: deferred to the next microtask.
|
|
9
|
+
*/
|
|
10
|
+
export type EffectScheduler = 'microtask' | 'sync';
|
|
11
|
+
/** Options accepted by `computed()`. */
|
|
12
|
+
export type ComputedOptions<T> = {
|
|
13
|
+
equals?: EqualityFn<T>;
|
|
14
|
+
name?: string;
|
|
15
|
+
};
|
|
16
|
+
/** Options accepted by `signal()`. */
|
|
17
|
+
export type SignalOptions<T> = {
|
|
18
|
+
equals?: EqualityFn<T>;
|
|
19
|
+
name?: string;
|
|
20
|
+
};
|
|
21
|
+
export type EffectOptions = {
|
|
22
|
+
name?: string;
|
|
23
|
+
scheduler?: EffectScheduler;
|
|
24
|
+
};
|
|
25
|
+
export type EffectAsyncOptions = {
|
|
26
|
+
/** Name used to identify this async effect in DevTools. */
|
|
27
|
+
name?: string;
|
|
28
|
+
onError?: (error: unknown) => void;
|
|
29
|
+
};
|
|
30
|
+
export interface Subscription {
|
|
31
|
+
dispose(): void;
|
|
32
|
+
/** `true` after `dispose()` has been called. */
|
|
33
|
+
readonly disposed: boolean;
|
|
34
|
+
[Symbol.dispose](): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A snapshot of one reactive dependency recorded by an effect.
|
|
38
|
+
* Returned by `EffectHandle.getDependencies()`.
|
|
39
|
+
*/
|
|
40
|
+
export type DepInfo = {
|
|
41
|
+
readonly kind: 'computed' | 'signal';
|
|
42
|
+
readonly name?: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Extended handle returned by `effect()`.
|
|
46
|
+
* Extends `Subscription` with `getDependencies()` for reactive graph introspection.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const handle = effect(() => { console.log(count.value); });
|
|
51
|
+
* console.log(handle.getDependencies()); // [{ name: 'count' }]
|
|
52
|
+
* handle.dispose();
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export interface EffectHandle extends Subscription {
|
|
56
|
+
/**
|
|
57
|
+
* Returns the reactive sources the effect is currently subscribed to.
|
|
58
|
+
* Reflects the deps collected during the last completed run.
|
|
59
|
+
* Returns an empty array after `dispose()`.
|
|
60
|
+
*/
|
|
61
|
+
getDependencies(): ReadonlyArray<DepInfo>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extended async subscription returned by `effectAsync()`.
|
|
65
|
+
* Adds `run()` for structured concurrency — await the current async run before proceeding.
|
|
66
|
+
*/
|
|
67
|
+
export interface AsyncSubscription extends Subscription {
|
|
68
|
+
/** Awaits the current async run without disposing the effect. Resolves immediately if idle. */
|
|
69
|
+
run(): Promise<void>;
|
|
70
|
+
/** ES2024 `await using` compatible async disposal. Stops the effect and awaits full teardown. */
|
|
71
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
export type WatchOptions<T> = {
|
|
74
|
+
equals?: EqualityFn<T>;
|
|
75
|
+
immediate?: boolean;
|
|
76
|
+
name?: string;
|
|
77
|
+
/** Auto-dispose the watch after the first callback invocation. */
|
|
78
|
+
once?: boolean;
|
|
79
|
+
};
|
|
80
|
+
export type ResourceOptions<T> = {
|
|
81
|
+
/** Value exposed via `data` while the first run is loading. */
|
|
82
|
+
initialValue?: T;
|
|
83
|
+
/** Debug name for the internal effect and state signal. */
|
|
84
|
+
name?: string;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Discriminated-union state emitted by a `resource()` signal.
|
|
88
|
+
*
|
|
89
|
+
* - `'loading'` — async factory is in-flight. `data` carries the last fulfilled value (if any).
|
|
90
|
+
* - `'ready'` — factory resolved. `data` is the fulfilled value.
|
|
91
|
+
* - `'error'` — factory rejected. `error` holds the thrown value. `data` carries the last fulfilled value (if any).
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const user = resource(async () => fetchUser(id.value));
|
|
96
|
+
*
|
|
97
|
+
* effect(() => {
|
|
98
|
+
* const s = user.value;
|
|
99
|
+
* if (s.status === 'loading') return showSpinner();
|
|
100
|
+
* if (s.status === 'error') return showError(s.error);
|
|
101
|
+
* renderUser(s.data);
|
|
102
|
+
* });
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export type ResourceState<T> = {
|
|
106
|
+
readonly data?: T;
|
|
107
|
+
readonly status: 'loading';
|
|
108
|
+
} | {
|
|
109
|
+
readonly data: T;
|
|
110
|
+
readonly status: 'ready';
|
|
111
|
+
} | {
|
|
112
|
+
readonly data?: T;
|
|
113
|
+
readonly error: unknown;
|
|
114
|
+
readonly status: 'error';
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Disposable handle returned by `resource()`. Extends `Computed<ResourceState<T>>`
|
|
118
|
+
* with `refresh()` for manually forcing a re-fetch.
|
|
119
|
+
*/
|
|
120
|
+
export interface Resource<T> extends Computed<ResourceState<T>> {
|
|
121
|
+
/**
|
|
122
|
+
* Forces the factory to re-run immediately, aborting any in-flight run —
|
|
123
|
+
* even if no tracked dependency changed. No-op after `dispose()`.
|
|
124
|
+
*/
|
|
125
|
+
refresh(): void;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* A single snapshot entry in `StoreWithHistory`.
|
|
129
|
+
* Carries the frozen state and an optional label for annotated checkpoints.
|
|
130
|
+
*/
|
|
131
|
+
export type HistoryEntry<T> = {
|
|
132
|
+
readonly label?: string;
|
|
133
|
+
readonly state: Readonly<T>;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* The minimal read-only contract for consuming any reactive value.
|
|
137
|
+
* Effects and computed functions read `.value` (tracked) or `peek()` (untracked).
|
|
138
|
+
* Use `subscribe()` for external imperative listeners.
|
|
139
|
+
*/
|
|
140
|
+
export interface Readable<T> {
|
|
141
|
+
/** `true` after the underlying node has been disposed. */
|
|
142
|
+
readonly disposed: boolean;
|
|
143
|
+
/** The debug name assigned at creation time, or `undefined` if unnamed. */
|
|
144
|
+
readonly name?: string;
|
|
145
|
+
peek(): T;
|
|
146
|
+
/**
|
|
147
|
+
* Subscribes a listener to value change notifications.
|
|
148
|
+
* Implementations MUST NOT invoke `listener` synchronously during registration.
|
|
149
|
+
*/
|
|
150
|
+
subscribe(listener: () => void): Subscription;
|
|
151
|
+
readonly value: T;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A disposable derived value. The holder is responsible for calling `dispose()`.
|
|
155
|
+
* Returned by `computed()`, `readonly()`, and `resource()`.
|
|
156
|
+
*/
|
|
157
|
+
export interface Computed<T> extends Readable<T> {
|
|
158
|
+
dispose(): void;
|
|
159
|
+
[Symbol.dispose](): void;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* A writable owned signal. The holder can both read and write `.value`,
|
|
163
|
+
* and is responsible for calling `dispose()` when done.
|
|
164
|
+
*/
|
|
165
|
+
export interface Signal<T> extends Computed<T> {
|
|
166
|
+
value: T;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Extracts the value type at a dot-separated path `P` within object type `T`.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* type City = PathValue<{ user: { address: { city: string } } }, 'user.address.city'>
|
|
173
|
+
* // → string
|
|
174
|
+
*/
|
|
175
|
+
export type PathValue<T, P extends string> = P extends keyof T ? T[P] : P extends `${infer K}.${infer Rest}` ? K extends keyof T ? PathValue<T[K], Rest> : never : never;
|
|
176
|
+
/**
|
|
177
|
+
* A fine-grained reactive store for objects.
|
|
178
|
+
* Extends `Computed<Readonly<T>>` — `store.value` provides a tracked whole-store read.
|
|
179
|
+
*
|
|
180
|
+
* `lens()` is the primary reactive read/write API — it returns a `Signal` for
|
|
181
|
+
* a specific property or nested path and registers fine-grained dependencies.
|
|
182
|
+
* `peek()` returns a non-reactive snapshot (useful for serialization).
|
|
183
|
+
* `subscribe()` fires on any mutation (useful for adapters like `storeWithHistory`).
|
|
184
|
+
*/
|
|
185
|
+
export interface Store<T extends object> extends Computed<Readonly<T>> {
|
|
186
|
+
/**
|
|
187
|
+
* Returns a writable `Signal` scoped to a single property or nested path.
|
|
188
|
+
* Reads register a fine-grained dependency on that property's signal —
|
|
189
|
+
* unrelated patches do NOT re-run effects watching this lens.
|
|
190
|
+
* Lenses are cached — `store.lens('x') === store.lens('x')`.
|
|
191
|
+
*/
|
|
192
|
+
lens<P extends string>(path: P): Signal<PathValue<T, P>>;
|
|
193
|
+
/** Atomic partial update — only changed keys notify their subscribers. */
|
|
194
|
+
patch(partial: Partial<T>): void;
|
|
195
|
+
/**
|
|
196
|
+
* Returns a non-reactive snapshot of the current state.
|
|
197
|
+
* Use for serialization or one-off reads outside reactive contexts.
|
|
198
|
+
*/
|
|
199
|
+
peek(): Readonly<T>;
|
|
200
|
+
/**
|
|
201
|
+
* Replaces the entire store state by passing the current state to `fn` and
|
|
202
|
+
* applying the returned value. Only changed properties trigger downstream effects.
|
|
203
|
+
*/
|
|
204
|
+
replace(fn: (state: Readonly<T>) => T): void;
|
|
205
|
+
/** Resets the store to its initial state. */
|
|
206
|
+
reset(): void;
|
|
207
|
+
/**
|
|
208
|
+
* Subscribes to any store mutation (patch / replace / reset / lens write).
|
|
209
|
+
* Used by external adapters — prefer `store.lens()` for reactive reads.
|
|
210
|
+
*/
|
|
211
|
+
subscribe(listener: () => void): Subscription;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* A lifecycle scope that collects cleanup functions and runs them on dispose.
|
|
215
|
+
* Effects and computeds created inside `scope.run()` auto-register their disposal.
|
|
216
|
+
*/
|
|
217
|
+
export interface Scope {
|
|
218
|
+
/**
|
|
219
|
+
* Registers `fn` to run when this scope is disposed.
|
|
220
|
+
* Throws `RippleDisposedScopeError` if called on an already-disposed scope.
|
|
221
|
+
* Use this from within an effect body to explicitly direct a cleanup into the scope
|
|
222
|
+
* rather than the effect's own cleanup queue.
|
|
223
|
+
*/
|
|
224
|
+
add(fn: CleanupFn): void;
|
|
225
|
+
/** `AbortSignal` that is aborted when `dispose()` is called. Use to tie external lifetimes to this scope. */
|
|
226
|
+
readonly disposalSignal: AbortSignal;
|
|
227
|
+
dispose(): void;
|
|
228
|
+
/** `true` after `dispose()` has been called. */
|
|
229
|
+
readonly disposed: boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Runs `fn` inside this scope's cleanup context.
|
|
232
|
+
* `onCleanup()` calls and resource auto-disposals inside `fn` are registered
|
|
233
|
+
* to this scope when there is no enclosing effect or computed context.
|
|
234
|
+
* Reactive reads inside `fn` are tracked normally against any enclosing effect.
|
|
235
|
+
* Throws `RippleDisposedScopeError` if the scope has already been disposed.
|
|
236
|
+
*/
|
|
237
|
+
run<T>(fn: () => T): T;
|
|
238
|
+
[Symbol.dispose](): void;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* An undo/redo adapter wrapping a `Store<T>`.
|
|
242
|
+
* Extends `Store<T>` directly — all store mutations (`patch`, `replace`, `reset`, `lens`)
|
|
243
|
+
* work on the history adapter without `.store` indirection.
|
|
244
|
+
*
|
|
245
|
+
* History is **explicit** — call `push()` or `pushNamed()` after any mutation you want undoable.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* const h = storeWithHistory({ count: 0 });
|
|
250
|
+
*
|
|
251
|
+
* h.patch({ count: 1 });
|
|
252
|
+
* h.push(); // save a checkpoint
|
|
253
|
+
* h.undo(); // restore to { count: 0 }
|
|
254
|
+
* h.redo(); // restore to { count: 1 }
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
export interface StoreWithHistory<T extends object> extends Store<T> {
|
|
258
|
+
/** `true` when there is at least one snapshot ahead to redo. Reactive — reads inside effects re-run on change. */
|
|
259
|
+
readonly canRedo: boolean;
|
|
260
|
+
/** `true` when there is at least one snapshot to undo to. Reactive — reads inside effects re-run on change. */
|
|
261
|
+
readonly canUndo: boolean;
|
|
262
|
+
/** Returns the history entry at the given index (0 = oldest). */
|
|
263
|
+
historyAt(index: number): HistoryEntry<T> | undefined;
|
|
264
|
+
/** Number of snapshots currently in history. */
|
|
265
|
+
readonly historyLength: number;
|
|
266
|
+
/** Saves the current store state as an explicit undo checkpoint. */
|
|
267
|
+
push(): void;
|
|
268
|
+
/**
|
|
269
|
+
* Saves the current store state as an annotated checkpoint.
|
|
270
|
+
* Use to mark significant transitions (e.g. `'import'`, `'reset'`) so time-travel
|
|
271
|
+
* debuggers can distinguish user-initiated from programmatic mutations.
|
|
272
|
+
*/
|
|
273
|
+
pushNamed(label: string): void;
|
|
274
|
+
/** Move forward one snapshot. No-op when at the most recent checkpoint. */
|
|
275
|
+
redo(): void;
|
|
276
|
+
/** The underlying store — kept as an escape hatch for adapters that need direct store access. */
|
|
277
|
+
readonly store: Store<T>;
|
|
278
|
+
/** Move back one snapshot. No-op when at the oldest checkpoint. */
|
|
279
|
+
undo(): void;
|
|
280
|
+
}
|
|
281
|
+
export type Subscriber = () => void;
|
|
282
|
+
/** Event emitted when a signal's value changes. */
|
|
283
|
+
export type WriteEvent = {
|
|
284
|
+
name: string | undefined;
|
|
285
|
+
newValue: unknown;
|
|
286
|
+
oldValue: unknown;
|
|
287
|
+
};
|
|
288
|
+
/** Event emitted when a computed recomputes, or when an effect runs. */
|
|
289
|
+
export type NamedEvent = {
|
|
290
|
+
name: string | undefined;
|
|
291
|
+
};
|
|
292
|
+
/** Event emitted when a signal, computed, effect, or store is disposed. */
|
|
293
|
+
export type DisposeEvent = {
|
|
294
|
+
kind: 'computed' | 'effect' | 'signal' | 'store';
|
|
295
|
+
name: string | undefined;
|
|
296
|
+
};
|
|
297
|
+
/** Event emitted when a store-level mutation occurs. `path` is populated for `kind: 'lens'`. */
|
|
298
|
+
export type MutateEvent = {
|
|
299
|
+
kind: 'patch' | 'replace' | 'reset' | 'lens';
|
|
300
|
+
name: string | undefined;
|
|
301
|
+
path?: string;
|
|
302
|
+
};
|
|
303
|
+
export type RippleDevToolsHook = {
|
|
304
|
+
/** Called when a computed signal recomputes. */
|
|
305
|
+
compute?(event: NamedEvent): void;
|
|
306
|
+
/** Called when a signal, computed, or effect is disposed. */
|
|
307
|
+
dispose?(event: DisposeEvent): void;
|
|
308
|
+
/** Called when a store-level mutation (patch/replace/reset/lens) occurs. */
|
|
309
|
+
mutate?(event: MutateEvent): void;
|
|
310
|
+
/** Called when an effect starts running. */
|
|
311
|
+
run?(event: NamedEvent): void;
|
|
312
|
+
/** Called when a signal's value changes. */
|
|
313
|
+
write?(event: WriteEvent): void;
|
|
314
|
+
};
|
|
315
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./tracking.cjs"),t=require("./symbols.cjs");var n=e=>({get disposed(){return e.disposed},[t.IS_SIGNAL]:!0,get name(){return e.name},peek(){return e.peek()},subscribe(t){return e.subscribe(t)},get value(){return e.value}}),r=e=>typeof e==`object`&&!!e&&!!e[t.IS_SIGNAL],i=e=>r(e)&&!e[t.IS_COMPUTED]&&!e[t.IS_STORE],a=e=>typeof e==`object`&&!!e&&!!e[t.IS_COMPUTED],o=e=>typeof e==`object`&&!!e&&!!e[t.IS_STORE];exports.isComputed=a,exports.isReactive=r,exports.isSignal=i,exports.isStore=o,exports.readonly=n,exports.untrack=e.untrack;
|
|
2
|
+
//# sourceMappingURL=utilities.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utilities.cjs","names":[],"sources":["../src/utilities.ts"],"sourcesContent":["import type { Computed, Readable, Signal } from './types';\n\nimport { IS_COMPUTED, IS_SIGNAL, IS_STORE } from './symbols';\nimport { untrack } from './tracking';\n\nexport { untrack };\n\n// ── Readonly wrapper ──────────────────────────────────────────────────────────\n//\n// readonly() returns Readable<T> — no dispose() because the wrapper does not\n// own the source. Callers retain ownership and must dispose the source themselves.\n// The [IS_SIGNAL] brand is set so isReactive(readonly(s)) and isSignal(readonly(s))\n// both return true (it is reactive, not IS_COMPUTED, not IS_STORE).\n// [IS_COMPUTED] is intentionally NOT set — the wrapper is not a Computed<T>\n// and does not have dispose().\n\n/**\n * Wraps a reactive value to produce a structurally read-only view.\n * The `value` setter is hidden. Delegates reads directly to the source —\n * no extra reactive graph node, no extra subscription.\n *\n * The caller retains ownership of the source and is responsible for disposing it.\n *\n * @example\n * ```ts\n * const count = signal(0);\n * const readCount = readonly(count);\n * readCount.value; // fine — tracks dep on count\n * // readCount.value = 1; // TypeScript error — Readable has no setter\n * ```\n */\nexport const readonly = <T>(source: Readable<T>): Readable<T> => {\n const wrapper = {\n get disposed(): boolean {\n return source.disposed;\n },\n [IS_SIGNAL]: true as const,\n get name(): string | undefined {\n return source.name;\n },\n peek(): T {\n return source.peek();\n },\n subscribe(listener: () => void) {\n return source.subscribe(listener);\n },\n get value(): T {\n return source.value;\n },\n };\n\n return wrapper as unknown as Readable<T>;\n};\n\n// ── Type guards ───────────────────────────────────────────────────────────────\n\n/**\n * Returns `true` for any reactive value that implements `Readable<T>` — including\n * `signal()`, `computed()`, `store()`, and `readonly()` wrappers.\n *\n * This is the broad \"is this value reactive?\" check. Use `isSignal` for writable-only\n * signals, or `isComputed` to narrow to computed values.\n *\n * @example\n * ```ts\n * isReactive(signal(0)) // true\n * isReactive(computed(() => 1)) // true\n * isReactive(store({ x: 0 })) // true\n * isReactive(readonly(signal(0))) // true\n * isReactive({}) // false\n * ```\n */\nexport const isReactive = <T = unknown>(value: unknown): value is Readable<T> =>\n typeof value === 'object' && value !== null && !!(value as Record<typeof IS_SIGNAL, unknown>)[IS_SIGNAL];\n\n/**\n * Returns `true` only for writable `Signal<T>` values — excludes `computed()`, `store()`,\n * and `readonly()` wrappers.\n *\n * Use `isReactive` for the broad \"is this reactive?\" check.\n *\n * @example\n * ```ts\n * isSignal(signal(0)) // true\n * isSignal(computed(() => 1)) // false — computed excluded\n * isSignal(store({ x: 0 })) // false — store excluded\n * isSignal(readonly(signal(0))) // true — readonly has IS_SIGNAL, not IS_COMPUTED/IS_STORE\n * isSignal({}) // false\n * ```\n */\nexport const isSignal = <T = unknown>(value: unknown): value is Signal<T> =>\n isReactive(value) &&\n !(value as unknown as Record<typeof IS_COMPUTED, unknown>)[IS_COMPUTED] &&\n !(value as unknown as Record<typeof IS_STORE, unknown>)[IS_STORE];\n\nexport const isComputed = <T = unknown>(value: unknown): value is Computed<T> =>\n typeof value === 'object' && value !== null && !!(value as Record<typeof IS_COMPUTED, unknown>)[IS_COMPUTED];\n\nexport const isStore = <T extends object = object>(value: unknown): value is import('./types').Store<T> =>\n typeof value === 'object' && value !== null && !!(value as Record<typeof IS_STORE, unknown>)[IS_STORE];\n"],"mappings":"6DA+BA,IAAa,EAAe,IAoBnB,CAlBL,IAAI,UAAoB,CACtB,OAAO,EAAO,QAChB,GACC,EAAA,WAAY,GACb,IAAI,MAA2B,CAC7B,OAAO,EAAO,IAChB,EACA,MAAU,CACR,OAAO,EAAO,KAAK,CACrB,EACA,UAAU,EAAsB,CAC9B,OAAO,EAAO,UAAU,CAAQ,CAClC,EACA,IAAI,OAAW,CACb,OAAO,EAAO,KAChB,CAGK,GAqBI,EAA2B,GACtC,OAAO,GAAU,YAAY,GAAkB,CAAC,CAAE,EAA4C,EAAA,WAiBnF,EAAyB,GACpC,EAAW,CAAK,GAChB,CAAE,EAAyD,EAAA,cAC3D,CAAE,EAAsD,EAAA,UAE7C,EAA2B,GACtC,OAAO,GAAU,YAAY,GAAkB,CAAC,CAAE,EAA8C,EAAA,aAErF,EAAsC,GACjD,OAAO,GAAU,YAAY,GAAkB,CAAC,CAAE,EAA2C,EAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Computed, Readable, Signal } from './types';
|
|
2
|
+
import { untrack } from './tracking';
|
|
3
|
+
export { untrack };
|
|
4
|
+
/**
|
|
5
|
+
* Wraps a reactive value to produce a structurally read-only view.
|
|
6
|
+
* The `value` setter is hidden. Delegates reads directly to the source —
|
|
7
|
+
* no extra reactive graph node, no extra subscription.
|
|
8
|
+
*
|
|
9
|
+
* The caller retains ownership of the source and is responsible for disposing it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const count = signal(0);
|
|
14
|
+
* const readCount = readonly(count);
|
|
15
|
+
* readCount.value; // fine — tracks dep on count
|
|
16
|
+
* // readCount.value = 1; // TypeScript error — Readable has no setter
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const readonly: <T>(source: Readable<T>) => Readable<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Returns `true` for any reactive value that implements `Readable<T>` — including
|
|
22
|
+
* `signal()`, `computed()`, `store()`, and `readonly()` wrappers.
|
|
23
|
+
*
|
|
24
|
+
* This is the broad "is this value reactive?" check. Use `isSignal` for writable-only
|
|
25
|
+
* signals, or `isComputed` to narrow to computed values.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* isReactive(signal(0)) // true
|
|
30
|
+
* isReactive(computed(() => 1)) // true
|
|
31
|
+
* isReactive(store({ x: 0 })) // true
|
|
32
|
+
* isReactive(readonly(signal(0))) // true
|
|
33
|
+
* isReactive({}) // false
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare const isReactive: <T = unknown>(value: unknown) => value is Readable<T>;
|
|
37
|
+
/**
|
|
38
|
+
* Returns `true` only for writable `Signal<T>` values — excludes `computed()`, `store()`,
|
|
39
|
+
* and `readonly()` wrappers.
|
|
40
|
+
*
|
|
41
|
+
* Use `isReactive` for the broad "is this reactive?" check.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* isSignal(signal(0)) // true
|
|
46
|
+
* isSignal(computed(() => 1)) // false — computed excluded
|
|
47
|
+
* isSignal(store({ x: 0 })) // false — store excluded
|
|
48
|
+
* isSignal(readonly(signal(0))) // true — readonly has IS_SIGNAL, not IS_COMPUTED/IS_STORE
|
|
49
|
+
* isSignal({}) // false
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare const isSignal: <T = unknown>(value: unknown) => value is Signal<T>;
|
|
53
|
+
export declare const isComputed: <T = unknown>(value: unknown) => value is Computed<T>;
|
|
54
|
+
export declare const isStore: <T extends object = object>(value: unknown) => value is import("./types").Store<T>;
|
|
55
|
+
//# sourceMappingURL=utilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG1D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,CAAC;AAWnB;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAG,QAAQ,CAAC,CAAC,CAqB3D,CAAC;AAIF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,GAAG,OAAO,EAAE,OAAO,OAAO,KAAG,KAAK,IAAI,QAAQ,CAAC,CAAC,CAC8B,CAAC;AAE3G;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,GAAG,OAAO,EAAE,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,CAAC,CAGL,CAAC;AAEpE,eAAO,MAAM,UAAU,GAAI,CAAC,GAAG,OAAO,EAAE,OAAO,OAAO,KAAG,KAAK,IAAI,QAAQ,CAAC,CAAC,CACkC,CAAC;AAE/G,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,OAAO,KAAG,KAAK,IAAI,OAAO,SAAS,EAAE,KAAK,CAAC,CAAC,CACE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { untrack as e } from "./tracking.js";
|
|
2
|
+
import { IS_COMPUTED as t, IS_SIGNAL as n, IS_STORE as r } from "./symbols.js";
|
|
3
|
+
//#region src/utilities.ts
|
|
4
|
+
var i = (e) => ({
|
|
5
|
+
get disposed() {
|
|
6
|
+
return e.disposed;
|
|
7
|
+
},
|
|
8
|
+
[n]: !0,
|
|
9
|
+
get name() {
|
|
10
|
+
return e.name;
|
|
11
|
+
},
|
|
12
|
+
peek() {
|
|
13
|
+
return e.peek();
|
|
14
|
+
},
|
|
15
|
+
subscribe(t) {
|
|
16
|
+
return e.subscribe(t);
|
|
17
|
+
},
|
|
18
|
+
get value() {
|
|
19
|
+
return e.value;
|
|
20
|
+
}
|
|
21
|
+
}), a = (e) => typeof e == "object" && !!e && !!e[n], o = (e) => a(e) && !e[t] && !e[r], s = (e) => typeof e == "object" && !!e && !!e[t], c = (e) => typeof e == "object" && !!e && !!e[r];
|
|
22
|
+
//#endregion
|
|
23
|
+
export { s as isComputed, a as isReactive, o as isSignal, c as isStore, i as readonly, e as untrack };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=utilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utilities.js","names":[],"sources":["../src/utilities.ts"],"sourcesContent":["import type { Computed, Readable, Signal } from './types';\n\nimport { IS_COMPUTED, IS_SIGNAL, IS_STORE } from './symbols';\nimport { untrack } from './tracking';\n\nexport { untrack };\n\n// ── Readonly wrapper ──────────────────────────────────────────────────────────\n//\n// readonly() returns Readable<T> — no dispose() because the wrapper does not\n// own the source. Callers retain ownership and must dispose the source themselves.\n// The [IS_SIGNAL] brand is set so isReactive(readonly(s)) and isSignal(readonly(s))\n// both return true (it is reactive, not IS_COMPUTED, not IS_STORE).\n// [IS_COMPUTED] is intentionally NOT set — the wrapper is not a Computed<T>\n// and does not have dispose().\n\n/**\n * Wraps a reactive value to produce a structurally read-only view.\n * The `value` setter is hidden. Delegates reads directly to the source —\n * no extra reactive graph node, no extra subscription.\n *\n * The caller retains ownership of the source and is responsible for disposing it.\n *\n * @example\n * ```ts\n * const count = signal(0);\n * const readCount = readonly(count);\n * readCount.value; // fine — tracks dep on count\n * // readCount.value = 1; // TypeScript error — Readable has no setter\n * ```\n */\nexport const readonly = <T>(source: Readable<T>): Readable<T> => {\n const wrapper = {\n get disposed(): boolean {\n return source.disposed;\n },\n [IS_SIGNAL]: true as const,\n get name(): string | undefined {\n return source.name;\n },\n peek(): T {\n return source.peek();\n },\n subscribe(listener: () => void) {\n return source.subscribe(listener);\n },\n get value(): T {\n return source.value;\n },\n };\n\n return wrapper as unknown as Readable<T>;\n};\n\n// ── Type guards ───────────────────────────────────────────────────────────────\n\n/**\n * Returns `true` for any reactive value that implements `Readable<T>` — including\n * `signal()`, `computed()`, `store()`, and `readonly()` wrappers.\n *\n * This is the broad \"is this value reactive?\" check. Use `isSignal` for writable-only\n * signals, or `isComputed` to narrow to computed values.\n *\n * @example\n * ```ts\n * isReactive(signal(0)) // true\n * isReactive(computed(() => 1)) // true\n * isReactive(store({ x: 0 })) // true\n * isReactive(readonly(signal(0))) // true\n * isReactive({}) // false\n * ```\n */\nexport const isReactive = <T = unknown>(value: unknown): value is Readable<T> =>\n typeof value === 'object' && value !== null && !!(value as Record<typeof IS_SIGNAL, unknown>)[IS_SIGNAL];\n\n/**\n * Returns `true` only for writable `Signal<T>` values — excludes `computed()`, `store()`,\n * and `readonly()` wrappers.\n *\n * Use `isReactive` for the broad \"is this reactive?\" check.\n *\n * @example\n * ```ts\n * isSignal(signal(0)) // true\n * isSignal(computed(() => 1)) // false — computed excluded\n * isSignal(store({ x: 0 })) // false — store excluded\n * isSignal(readonly(signal(0))) // true — readonly has IS_SIGNAL, not IS_COMPUTED/IS_STORE\n * isSignal({}) // false\n * ```\n */\nexport const isSignal = <T = unknown>(value: unknown): value is Signal<T> =>\n isReactive(value) &&\n !(value as unknown as Record<typeof IS_COMPUTED, unknown>)[IS_COMPUTED] &&\n !(value as unknown as Record<typeof IS_STORE, unknown>)[IS_STORE];\n\nexport const isComputed = <T = unknown>(value: unknown): value is Computed<T> =>\n typeof value === 'object' && value !== null && !!(value as Record<typeof IS_COMPUTED, unknown>)[IS_COMPUTED];\n\nexport const isStore = <T extends object = object>(value: unknown): value is import('./types').Store<T> =>\n typeof value === 'object' && value !== null && !!(value as Record<typeof IS_STORE, unknown>)[IS_STORE];\n"],"mappings":";;;AA+BA,IAAa,KAAe,OAoBnB;CAlBL,IAAI,WAAoB;EACtB,OAAO,EAAO;CAChB;EACC,IAAY;CACb,IAAI,OAA2B;EAC7B,OAAO,EAAO;CAChB;CACA,OAAU;EACR,OAAO,EAAO,KAAK;CACrB;CACA,UAAU,GAAsB;EAC9B,OAAO,EAAO,UAAU,CAAQ;CAClC;CACA,IAAI,QAAW;EACb,OAAO,EAAO;CAChB;AAGK,IAqBI,KAA2B,MACtC,OAAO,KAAU,cAAY,KAAkB,CAAC,CAAE,EAA4C,IAiBnF,KAAyB,MACpC,EAAW,CAAK,KAChB,CAAE,EAAyD,MAC3D,CAAE,EAAsD,IAE7C,KAA2B,MACtC,OAAO,KAAU,cAAY,KAAkB,CAAC,CAAE,EAA8C,IAErF,KAAsC,MACjD,OAAO,KAAU,cAAY,KAAkB,CAAC,CAAE,EAA2C"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vielzeug/ripple",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"description": "Fine-grained reactive state — signals, computed values, effects, stores, and reactive scopes",
|
|
9
|
+
"main": "./dist/index.cjs",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"source": "./src/index.ts",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"require": "./dist/index.cjs"
|
|
18
|
+
},
|
|
19
|
+
"./devtools": {
|
|
20
|
+
"source": "./src/devtools.ts",
|
|
21
|
+
"types": "./dist/devtools.d.ts",
|
|
22
|
+
"import": "./dist/devtools.js",
|
|
23
|
+
"require": "./dist/devtools.cjs"
|
|
24
|
+
},
|
|
25
|
+
"./ssr": {
|
|
26
|
+
"source": "./src/ssr/index.ts",
|
|
27
|
+
"types": "./dist/ssr/index.d.ts",
|
|
28
|
+
"import": "./dist/ssr/index.js",
|
|
29
|
+
"require": "./dist/ssr/index.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "vite build && pnpm run build:bundle && pnpm run build:types",
|
|
34
|
+
"build:types": "tsc -p tsconfig.declarations.json",
|
|
35
|
+
"fix": "eslint --fix src",
|
|
36
|
+
"lint": "eslint src",
|
|
37
|
+
"prepublishOnly": "pnpm run build",
|
|
38
|
+
"preview": "vite preview",
|
|
39
|
+
"test": "vitest",
|
|
40
|
+
"build:bundle": "vite build --config vite.bundle.config.ts"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public",
|
|
44
|
+
"registry": "https://registry.npmjs.org/"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^26.1.0",
|
|
48
|
+
"typescript": "~6.0.3",
|
|
49
|
+
"vite": "^8.1.3",
|
|
50
|
+
"vitest": "^4.1.9"
|
|
51
|
+
}
|
|
52
|
+
}
|