@mmstack/primitives 21.2.1 → 21.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/primitives",
3
- "version": "21.2.1",
3
+ "version": "21.2.2",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",
@@ -1,7 +1,94 @@
1
1
  import * as i0 from '@angular/core';
2
- import { ValueEqualityFn, Injector, Signal, Provider, CreateComputedOptions, EffectCleanupRegisterFn, CreateEffectOptions, EffectRef, CreateSignalOptions, WritableSignal, ResourceRef, DestroyRef, ElementRef } from '@angular/core';
2
+ import { InjectionToken, Injector, CreateComputedOptions, Signal, EffectCleanupRegisterFn, CreateEffectOptions, EffectRef, CreateSignalOptions, WritableSignal, Provider, ValueEqualityFn, ResourceRef, DestroyRef, ElementRef } from '@angular/core';
3
3
  import * as _mmstack_primitives from '@mmstack/primitives';
4
4
 
5
+ /**
6
+ * How a pausable primitive decides whether it is currently paused:
7
+ * - omitted (the default) or `true` — read the ambient {@link PAUSED_CONTEXT} (via `injector`, or the
8
+ * current injection context). Reaching for a `pausable*` primitive means you want it pausable, so
9
+ * this is the default; outside an Activity boundary there's no `PAUSED_CONTEXT`, so the primitive is
10
+ * returned unwrapped (never pauses, zero overhead). On the server it never pauses either.
11
+ * - a predicate `() => boolean` — used directly. A `Signal<boolean>` satisfies this (signals are
12
+ * callable), and a plain function works OUTSIDE an injection context.
13
+ * - `false` — the explicit opt-out: the primitive is returned UNWRAPPED (no `linkedSignal`, no gate),
14
+ * i.e. exactly the plain primitive with zero overhead.
15
+ */
16
+ type PauseOption = boolean | (() => boolean);
17
+ type PausableOptions = {
18
+ /** Pause source — see {@link PauseOption}. Defaults to `true` (read the ambient `PAUSED_CONTEXT`). */
19
+ readonly pause?: PauseOption;
20
+ /**
21
+ * Injector used to resolve {@link PAUSED_CONTEXT} when `pause` is `true`/omitted and the primitive
22
+ * is created outside an injection context. Ignored for the `false` / predicate forms.
23
+ */
24
+ readonly injector?: Injector;
25
+ };
26
+ /**
27
+ * @internal Token carrying an app-wide default {@link PauseOption}, set via
28
+ * {@link providePausableOptions}. {@link resolvePause} consults it when the call site didn't
29
+ * specify `pause`, so users can opt every pausable-aware primitive in (or out) from one place.
30
+ */
31
+ declare const PAUSABLE_OPTIONS: InjectionToken<{
32
+ pause?: PauseOption;
33
+ }>;
34
+ /**
35
+ * Provides an app-wide default {@link PauseOption} for every pausable-aware primitive (the public
36
+ * `pausable*` family plus the opt-in integrations like `stored` / `chunked`). A call-site `pause`
37
+ * always wins; this only fills in when the call didn't specify one.
38
+ *
39
+ * @example
40
+ * // Make everything that can pause honour the ambient Activity boundary by default:
41
+ * providePausableOptions({ pause: true })
42
+ */
43
+ declare function providePausableOptions(opt: {
44
+ /** Default pause source for pausable-aware primitives that don't set their own. */
45
+ pause?: PauseOption;
46
+ }): Provider;
47
+ /**
48
+ * Resolve a {@link PauseOption} into a pause predicate, or `null` meaning "do not pause".
49
+ * `null` tells the caller to return the bare primitive — no wrapper is created.
50
+ *
51
+ * - omitted/`true` → the ambient {@link PAUSED_CONTEXT} if an Activity boundary provides one (via
52
+ * `opt.injector` or the current injection context), else `null` (the bare primitive, no allocation).
53
+ * The default, because an explicit `pausable*` call wants to be pausable. An explicit `pause: true`
54
+ * with no boundary dev-warns; the omitted default stays quiet. SSR → `null`.
55
+ * - a function → returned as-is (covers `Signal<boolean>`; usable outside an injection context).
56
+ * SSR → `null` here too, detected via `opt.injector` if given, else a `globalThis.window` probe.
57
+ * - `false` → `null` (the explicit opt-out).
58
+ *
59
+ * Encapsulating this here keeps every pausable primitive's branching identical and in one place.
60
+ */
61
+ declare function resolvePause(opt?: PausableOptions, defaultPause?: PauseOption): (() => boolean) | null;
62
+ /**
63
+ * Like {@link nestedEffect}, but pausable. While paused the effect does NOT run its body — and,
64
+ * crucially, it reads the pause predicate FIRST, so while paused its dependency set collapses to just
65
+ * the predicate (no churn from the real deps); on resume it re-runs and re-tracks. With no `pause`
66
+ * option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false` makes it a plain `nestedEffect`
67
+ * with zero added overhead.
68
+ */
69
+ declare function pausableEffect(effectFn: (registerCleanup: EffectCleanupRegisterFn) => void, options?: CreateEffectOptions & PausableOptions): EffectRef;
70
+ /**
71
+ * Like `signal`, but pausable. While paused, READS hold the last value; writes still land on the
72
+ * underlying signal and surface on resume. Built on the `keepPrevious`/`hold` shape — a
73
+ * `linkedSignal` gated on the pause predicate, with `set`/`update` forwarded to the source signal.
74
+ * `asReadonly()` returns the held (gated) view, so both views of the signal agree while paused.
75
+ * With no `pause` option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false`
76
+ * makes it a plain `signal` — no `linkedSignal` is created.
77
+ *
78
+ * NOTE: while paused, `set(x)` followed by a read returns the *held* (pre-pause) value, not `x` — the
79
+ * write lands on the source and surfaces on resume. That is the "freeze the displayed value while
80
+ * hidden" semantics; do not rely on read-after-write while paused.
81
+ */
82
+ declare function pausableSignal<T>(initialValue: T, options?: CreateSignalOptions<T> & PausableOptions): WritableSignal<T>;
83
+ /**
84
+ * Like `computed`, but pausable. While paused it holds its last value AND does not recompute: the
85
+ * computation's dependencies are not read while paused, so a dependency change can't trigger work —
86
+ * on resume it recomputes and re-tracks. The very first read always computes, to seed a value. With
87
+ * no `pause` option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false` makes it a plain
88
+ * `computed`.
89
+ */
90
+ declare function pausableComputed<T>(computation: () => T, options?: CreateComputedOptions<T> & PausableOptions): Signal<T>;
91
+
5
92
  type CreateChunkedOptions<T> = {
6
93
  /**
7
94
  * The number of items to process in each chunk.
@@ -21,6 +108,12 @@ type CreateChunkedOptions<T> = {
21
108
  * An optional `Injector` to use for the internal effect. This allows the effect to have access to dependency injection if needed.
22
109
  */
23
110
  injector?: Injector;
111
+ /**
112
+ * Opt-in pause: gate the chunk-scheduling effect on an ambient Activity boundary (`true`), a
113
+ * custom predicate, or `false` (default — no pausing). While paused, scheduling stops and resumes
114
+ * from the current chunk on resume. See {@link PauseOption}.
115
+ */
116
+ pause?: PauseOption;
24
117
  };
25
118
  /**
26
119
  * Creates a new `Signal` that processes an array of items in time-sliced chunks. This is useful for handling large lists without blocking the main thread.
@@ -95,72 +188,6 @@ declare function providePaused(source: Signal<boolean>): Provider;
95
188
  */
96
189
  declare function holdUntilReady<T>(target: Signal<T>, ready: () => boolean): Signal<T>;
97
190
 
98
- /**
99
- * How a pausable primitive decides whether it is currently paused:
100
- * - omitted (the default) or `true` — read the ambient {@link PAUSED_CONTEXT} (via `injector`, or the
101
- * current injection context). Reaching for a `pausable*` primitive means you want it pausable, so
102
- * this is the default; outside an Activity boundary there's no `PAUSED_CONTEXT`, so the primitive is
103
- * returned unwrapped (never pauses, zero overhead). On the server it never pauses either.
104
- * - a predicate `() => boolean` — used directly. A `Signal<boolean>` satisfies this (signals are
105
- * callable), and a plain function works OUTSIDE an injection context.
106
- * - `false` — the explicit opt-out: the primitive is returned UNWRAPPED (no `linkedSignal`, no gate),
107
- * i.e. exactly the plain primitive with zero overhead.
108
- */
109
- type PauseOption = boolean | (() => boolean);
110
- type PausableOptions = {
111
- /** Pause source — see {@link PauseOption}. Defaults to `true` (read the ambient `PAUSED_CONTEXT`). */
112
- readonly pause?: PauseOption;
113
- /**
114
- * Injector used to resolve {@link PAUSED_CONTEXT} when `pause` is `true`/omitted and the primitive
115
- * is created outside an injection context. Ignored for the `false` / predicate forms.
116
- */
117
- readonly injector?: Injector;
118
- };
119
- /**
120
- * Resolve a {@link PauseOption} into a pause predicate, or `null` meaning "do not pause".
121
- * `null` tells the caller to return the bare primitive — no wrapper is created.
122
- *
123
- * - omitted/`true` → the ambient {@link PAUSED_CONTEXT} if an Activity boundary provides one (via
124
- * `opt.injector` or the current injection context), else `null` (the bare primitive, no allocation).
125
- * The default, because an explicit `pausable*` call wants to be pausable. An explicit `pause: true`
126
- * with no boundary dev-warns; the omitted default stays quiet. SSR → `null`.
127
- * - a function → returned as-is (covers `Signal<boolean>`; usable outside an injection context).
128
- * SSR → `null` here too, detected via `opt.injector` if given, else a `globalThis.window` probe.
129
- * - `false` → `null` (the explicit opt-out).
130
- *
131
- * Encapsulating this here keeps every pausable primitive's branching identical and in one place.
132
- */
133
- declare function resolvePause(opt?: PausableOptions): (() => boolean) | null;
134
- /**
135
- * Like {@link nestedEffect}, but pausable. While paused the effect does NOT run its body — and,
136
- * crucially, it reads the pause predicate FIRST, so while paused its dependency set collapses to just
137
- * the predicate (no churn from the real deps); on resume it re-runs and re-tracks. With no `pause`
138
- * option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false` makes it a plain `nestedEffect`
139
- * with zero added overhead.
140
- */
141
- declare function pausableEffect(effectFn: (registerCleanup: EffectCleanupRegisterFn) => void, options?: CreateEffectOptions & PausableOptions): EffectRef;
142
- /**
143
- * Like `signal`, but pausable. While paused, READS hold the last value; writes still land on the
144
- * underlying signal and surface on resume. Built on the `keepPrevious`/`hold` shape — a
145
- * `linkedSignal` gated on the pause predicate, with `set`/`update` forwarded to the source signal.
146
- * `asReadonly()` returns the held (gated) view, so both views of the signal agree while paused.
147
- * With no `pause` option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false`
148
- * makes it a plain `signal` — no `linkedSignal` is created.
149
- *
150
- * NOTE: while paused, `set(x)` followed by a read returns the *held* (pre-pause) value, not `x` — the
151
- * write lands on the source and surfaces on resume. That is the "freeze the displayed value while
152
- * hidden" semantics; do not rely on read-after-write while paused.
153
- */
154
- declare function pausableSignal<T>(initialValue: T, options?: CreateSignalOptions<T> & PausableOptions): WritableSignal<T>;
155
- /**
156
- * Like `computed`, but pausable. While paused it holds its last value AND does not recompute: the
157
- * computation's dependencies are not read while paused, so a dependency change can't trigger work —
158
- * on resume it recomputes and re-tracks. The very first read always computes, to seed a value. With
159
- * no `pause` option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false` makes it a plain
160
- * `computed`.
161
- */
162
- declare function pausableComputed<T>(computation: () => T, options?: CreateComputedOptions<T> & PausableOptions): Signal<T>;
163
-
164
191
  /**
165
192
  * Handle for an in-progress transition: a `pending` signal (true while the transition's
166
193
  * resources are in flight) and a `done` promise that resolves once they all settle.
@@ -288,6 +315,12 @@ declare function registerResource<T extends ResourceRef<any>>(res: T, opt?: Regi
288
315
  *
289
316
  * `type` selects what "not ready" means: `'value'` (default) suspends only until a first value lands
290
317
  * then holds through reloads; `'loading'` suspends on every in-flight load (strict suspense).
318
+ *
319
+ * SSR: the server serializes whatever the scope reports at stabilization, so a registered resource
320
+ * must keep the app unstable until it settles or the placeholder is what gets serialized (then
321
+ * flashes/mismatches on hydration). HttpClient-backed resources, httpResource & all of `@mmstack/resource`
322
+ * do this automatically via the HTTP layer's `PendingTasks` + transfer cache. A custom loader (raw
323
+ * `fetch`/promise/timer) must opt in itself: wrap it with `inject(PendingTasks).run(() => promise)`.
291
324
  */
292
325
  declare abstract class SuspenseBoundaryBase {
293
326
  protected readonly scope: _mmstack_primitives.TransitionScope;
@@ -1879,6 +1912,73 @@ type ScreenOrientation = ScreenOrientationState;
1879
1912
  */
1880
1913
  declare function orientation(opt?: string | SensorRunOptions): Signal<ScreenOrientationState>;
1881
1914
 
1915
+ type PointerPoint = {
1916
+ x: number;
1917
+ y: number;
1918
+ };
1919
+ type PointerModifiers = {
1920
+ shift: boolean;
1921
+ alt: boolean;
1922
+ ctrl: boolean;
1923
+ meta: boolean;
1924
+ };
1925
+ type PointerDragState = {
1926
+ /** A gesture is past the activation threshold (distinguishes a drag from a click). */
1927
+ active: boolean;
1928
+ /** Pointer position at the pointerdown that began the gesture. */
1929
+ start: PointerPoint;
1930
+ /** Latest pointer position. */
1931
+ current: PointerPoint;
1932
+ /** `current - start`, computed on the same update as `current` (never torn). */
1933
+ delta: PointerPoint;
1934
+ /** The captured pointer id, or `null` when idle. */
1935
+ pointerId: number | null;
1936
+ /** Modifier keys at the latest update. */
1937
+ modifiers: PointerModifiers;
1938
+ /** Mouse button that started the gesture (`-1` when idle). */
1939
+ button: number;
1940
+ };
1941
+ type PointerDragOptions = SensorRunOptions & {
1942
+ /**
1943
+ * Element that receives `pointerdown`. An `HTMLElement`, `ElementRef`, or a
1944
+ * `Signal` of one (listeners re-attach when it changes). Defaults to the host
1945
+ * `ElementRef`.
1946
+ */
1947
+ target?: HTMLElement | ElementRef<HTMLElement> | Signal<HTMLElement | ElementRef<HTMLElement> | null | undefined>;
1948
+ /** `'client'` (viewport) or `'page'` coordinates. @default 'client' */
1949
+ coordinateSpace?: 'client' | 'page';
1950
+ /** Pixels the pointer must travel before `active` flips true. @default 3 */
1951
+ activationThreshold?: number;
1952
+ /** Throttle (ms) for `current`/`delta` updates. @default 16 */
1953
+ throttle?: number;
1954
+ /** Only start when the pointerdown target matches this selector (delegated handles). */
1955
+ handleSelector?: string;
1956
+ /** Mouse buttons that may start a gesture. @default [0] (primary) */
1957
+ buttons?: number[];
1958
+ };
1959
+ /** A gesture signal with an `unthrottled` view and an imperative `cancel()`. */
1960
+ type PointerDragSignal = Signal<PointerDragState> & {
1961
+ readonly unthrottled: Signal<PointerDragState>;
1962
+ /** Abort the current gesture and reset to idle (e.g. on Escape / programmatically). */
1963
+ cancel: () => void;
1964
+ };
1965
+ /**
1966
+ * Tracks a pointer *gesture* (pointerdown → capture → move → up) as a signal —
1967
+ * the foundation for pointer-based drag/move/resize/marquee on a canvas. Unlike
1968
+ * native HTML5 drag, pointer events fire continuously and coordinates are
1969
+ * reliable. SSR-safe; cleans up its listeners automatically.
1970
+ *
1971
+ * @example
1972
+ * ```ts
1973
+ * const drag = pointerDrag({ activationThreshold: 4 });
1974
+ * const position = computed(() => {
1975
+ * const d = drag();
1976
+ * return d.active ? { x: base.x + d.delta.x, y: base.y + d.delta.y } : base;
1977
+ * });
1978
+ * ```
1979
+ */
1980
+ declare function pointerDrag(opt?: PointerDragOptions): PointerDragSignal;
1981
+
1882
1982
  /**
1883
1983
  * Creates a read-only signal that tracks the page's visibility state.
1884
1984
  *
@@ -2080,6 +2180,10 @@ type SensorTypedOptions = {
2080
2180
  opt: MousePositionOptions;
2081
2181
  returnType: MousePositionSignal;
2082
2182
  };
2183
+ pointerDrag: {
2184
+ opt: PointerDragOptions;
2185
+ returnType: PointerDragSignal;
2186
+ };
2083
2187
  networkStatus: {
2084
2188
  opt: SensorRunOptions;
2085
2189
  returnType: NetworkStatusSignal;
@@ -2164,6 +2268,15 @@ declare function sensor(type: 'elementSize', options?: SensorTypedOptions['eleme
2164
2268
  * @example const pos = sensor('mousePosition', { coordinateSpace: 'page', throttle: 50 });
2165
2269
  */
2166
2270
  declare function sensor(type: 'mousePosition', options?: SensorTypedOptions['mousePosition']['opt']): MousePositionSignal;
2271
+ /**
2272
+ * Creates a sensor signal tracking a pointer drag gesture (down → move → up).
2273
+ * @param type Must be `'pointerDrag'`.
2274
+ * @param options Optional configuration (target, activationThreshold, throttle, …).
2275
+ * @returns A `PointerDragSignal` with `active`/`start`/`current`/`delta`, plus `unthrottled` and `cancel()`.
2276
+ * @see {pointerDrag} for detailed documentation and examples.
2277
+ * @example const drag = sensor('pointerDrag', { activationThreshold: 4 });
2278
+ */
2279
+ declare function sensor(type: 'pointerDrag', options?: SensorTypedOptions['pointerDrag']['opt']): PointerDragSignal;
2167
2280
  /**
2168
2281
  * Creates a sensor signal that tracks the browser's online/offline status.
2169
2282
  * @param type Must be `'networkStatus'`.
@@ -2327,6 +2440,32 @@ type ResolvableTarget = EventTargetLike | Signal<EventTargetLike | null>;
2327
2440
  declare function signalFromEvent<TEvent extends Event>(target: ResolvableTarget, eventName: string, initial: TEvent | null, opt?: SignalFromEventOptions): Signal<TEvent | null>;
2328
2441
  declare function signalFromEvent<TEvent extends Event, U>(target: ResolvableTarget, eventName: string, initial: U, project: (event: TEvent) => U, opt?: SignalFromEventOptions): Signal<U>;
2329
2442
 
2443
+ /**
2444
+ * @internal Runtime brand carrying a store node's lazily-built leaf probe. Exported (like
2445
+ * {@link OPAQUE}) only so the `{ readonly [LEAF]: () => boolean }` brand on the store types is
2446
+ * nameable in the emitted declarations — not part of the supported surface; use {@link isLeaf}.
2447
+ */
2448
+ declare const LEAF: unique symbol;
2449
+ /**
2450
+ * Reports whether a store node is currently a **leaf** — a terminal value the store does not
2451
+ * descend into (a primitive, `Date`, `RegExp`, {@link opaque} object, class instance, or a
2452
+ * `null`/`undefined` hole when vivification is off) rather than a record/array substore.
2453
+ *
2454
+ * Leaf-ness reflects the node's **live** value: the probe is reactive and memoized, so calling
2455
+ * `isLeaf` inside a `computed`/`effect` re-evaluates when the node's shape changes.
2456
+ *
2457
+ * @internal Exposed for advanced/niche interop only — not part of the supported public surface
2458
+ * and may change without a major version bump.
2459
+ *
2460
+ * @example
2461
+ * const s = store({ name: 'Ada', address: { city: 'London' } });
2462
+ * isLeaf(s.name); // true
2463
+ * isLeaf(s.address); // false — a substore
2464
+ */
2465
+ declare function isLeaf<T = unknown>(value: unknown): value is Signal<T> & {
2466
+ readonly [LEAF]: () => boolean;
2467
+ };
2468
+
2330
2469
  /**
2331
2470
  * Runtime marker + compile-time brand for an opaque value. A `const`-declared `Symbol`
2332
2471
  * has a `unique symbol` type, so the same symbol serves as both the property key written
@@ -2360,31 +2499,6 @@ declare function opaque<T extends object>(value: T): Opaque<T>;
2360
2499
  * }
2361
2500
  */
2362
2501
  declare function isOpaque<T = object>(value: unknown): value is Opaque<T>;
2363
- /**
2364
- * @internal Runtime brand carrying a store node's lazily-built leaf probe. Exported (like
2365
- * {@link OPAQUE}) only so the `{ readonly [LEAF]: () => boolean }` brand on the store types is
2366
- * nameable in the emitted declarations — not part of the supported surface; use {@link isLeaf}.
2367
- */
2368
- declare const LEAF: unique symbol;
2369
- /**
2370
- * Reports whether a store node is currently a **leaf** — a terminal value the store does not
2371
- * descend into (a primitive, `Date`, `RegExp`, {@link opaque} object, class instance, or a
2372
- * `null`/`undefined` hole when vivification is off) rather than a record/array substore.
2373
- *
2374
- * Leaf-ness reflects the node's **live** value: the probe is reactive and memoized, so calling
2375
- * `isLeaf` inside a `computed`/`effect` re-evaluates when the node's shape changes.
2376
- *
2377
- * @internal Exposed for advanced/niche interop only — not part of the supported public surface
2378
- * and may change without a major version bump.
2379
- *
2380
- * @example
2381
- * const s = store({ name: 'Ada', address: { city: 'London' } });
2382
- * isLeaf(s.name); // true
2383
- * isLeaf(s.address); // false — a substore
2384
- */
2385
- declare function isLeaf<T = unknown>(value: unknown): value is Signal<T> & {
2386
- readonly [LEAF]: () => boolean;
2387
- };
2388
2502
  /**
2389
2503
  * An object marked via {@link opaque} — the store treats it as an indivisible leaf
2390
2504
  * (like a `Date`), returning it whole instead of deep-proxying its keys.
@@ -2396,16 +2510,27 @@ type Opaque<T> = T & {
2396
2510
  type UnwrapOpaque<T> = T extends {
2397
2511
  readonly [OPAQUE]: true;
2398
2512
  } ? Omit<T, typeof OPAQUE> : T;
2513
+
2399
2514
  type BaseType = string | number | boolean | symbol | bigint | undefined | null | Function | Date | RegExp | {
2400
2515
  readonly [OPAQUE]: true;
2401
2516
  };
2402
2517
  type Key = string | number;
2403
2518
  type AnyRecord = Record<Key, any>;
2404
2519
  /**
2405
- * @internal
2406
- * Validates whether a value is a Signal Store.
2520
+ * @internal Resolves to `true` only for `any`. In a conditional type, `any` distributes across
2521
+ * *both* branches (`unknown | object`), and `unknown | X` collapses to `unknown` — which would
2522
+ * erase a store's property access and `extend`. Guarding on this routes an `any`-typed store to
2523
+ * the full object shape instead.
2407
2524
  */
2408
- declare function isStore<T>(value: unknown): value is SignalStore<T>;
2525
+ type IsAny<T> = 0 extends 1 & T ? true : false;
2526
+ /**
2527
+ * @internal Flattens an intersection (`A & B & C`) into a single object literal so editor
2528
+ * tooltips show the resolved members instead of the raw intersection chain. Display-only —
2529
+ * structurally identical to its input.
2530
+ */
2531
+ type Simplify<T> = {
2532
+ [K in keyof T]: T[K];
2533
+ } & {};
2409
2534
  type SignalArrayStore<T extends any[]> = Signal<T> & {
2410
2535
  readonly [index: number]: SignalStore<T[number]>;
2411
2536
  readonly length: Signal<number>;
@@ -2423,25 +2548,11 @@ type MutableArrayStore<T extends any[]> = MutableSignal<T> & {
2423
2548
  readonly length: Signal<number>;
2424
2549
  [Symbol.iterator](): Iterator<MutableSignalStore<T[number]>>;
2425
2550
  };
2426
- /**
2427
- * @internal Resolves to `true` only for `any`. In a conditional type, `any` distributes across
2428
- * *both* branches (`unknown | object`), and `unknown | X` collapses to `unknown` — which would
2429
- * erase a store's property access and `extend`. Guarding on this routes an `any`-typed store to
2430
- * the full object shape instead.
2431
- */
2432
- type IsAny<T> = 0 extends 1 & T ? true : false;
2433
- /**
2434
- * @internal Flattens an intersection (`A & B & C`) into a single object literal so editor
2435
- * tooltips show the resolved members instead of the raw intersection chain. Display-only —
2436
- * structurally identical to its input.
2437
- */
2438
- type Simplify<T> = {
2439
- [K in keyof T]: T[K];
2440
- } & {};
2441
2551
  /** @internal The object shape of a readonly store: a child store per key, plus `extend`. */
2442
2552
  type SignalStoreObject<T> = Simplify<Readonly<{
2443
2553
  [K in keyof Required<T>]: SignalStore<NonNullable<T>[K]>;
2444
2554
  }> & {
2555
+ /** @deprecated Use the standalone `extendStore(store, …)`; the `extend` key is removed next minor. */
2445
2556
  readonly extend: {
2446
2557
  <L extends AnyRecord>(source: Signal<L>): SignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2447
2558
  <L extends AnyRecord>(props: L): SignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
@@ -2451,6 +2562,7 @@ type SignalStoreObject<T> = Simplify<Readonly<{
2451
2562
  type WritableSignalStoreObject<T> = Simplify<Readonly<{
2452
2563
  [K in keyof Required<T>]: WritableSignalStore<NonNullable<T>[K]>;
2453
2564
  }> & {
2565
+ /** @deprecated Use the standalone `extendStore(store, …)`; the `extend` key is removed next minor. */
2454
2566
  readonly extend: {
2455
2567
  <L extends AnyRecord>(source: WritableSignal<L>): WritableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2456
2568
  <L extends AnyRecord>(props: L): WritableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
@@ -2460,6 +2572,7 @@ type WritableSignalStoreObject<T> = Simplify<Readonly<{
2460
2572
  type MutableSignalStoreObject<T> = Simplify<Readonly<{
2461
2573
  [K in keyof Required<T>]: MutableSignalStore<NonNullable<T>[K]>;
2462
2574
  }> & {
2575
+ /** @deprecated Use the standalone `extendStore(store, …)`; the `extend` key is removed next minor. */
2463
2576
  readonly extend: {
2464
2577
  <L extends AnyRecord>(source: MutableSignal<L>): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2465
2578
  <L extends AnyRecord>(props: L): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
@@ -2478,9 +2591,19 @@ type MutableSignalStore<T> = MutableSignal<UnwrapOpaque<T>> & {
2478
2591
  } & (IsAny<T> extends true ? MutableSignalStoreObject<T> : NonNullable<T> extends BaseType ? {
2479
2592
  readonly [LEAF]: () => boolean;
2480
2593
  } : NonNullable<T> extends any[] ? MutableArrayStore<NonNullable<T>> : MutableSignalStoreObject<T>);
2594
+
2595
+ /**
2596
+ * @internal
2597
+ * Validates whether a value is a Signal Store.
2598
+ */
2599
+ declare function isStore<T>(value: unknown): value is SignalStore<T>;
2600
+
2481
2601
  declare function toStore<T extends AnyRecord>(source: MutableSignal<T>, injector?: Injector, vivify?: Vivify, noUnionLeaves?: boolean): MutableSignalStore<T>;
2482
2602
  declare function toStore<T extends AnyRecord>(source: WritableSignal<T>, injector?: Injector, vivify?: Vivify, noUnionLeaves?: boolean): WritableSignalStore<T>;
2483
2603
  declare function toStore<T extends AnyRecord>(source: Signal<T>, injector?: Injector, vivify?: Vivify, noUnionLeaves?: boolean): SignalStore<T>;
2604
+ declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: MutableSignalStore<T>, source: MutableSignal<L> | L, injector?: Injector): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2605
+ declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: WritableSignalStore<T>, source: WritableSignal<L> | L, injector?: Injector): WritableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2606
+ declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: SignalStore<T>, source: Signal<L> | L, injector?: Injector): SignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2484
2607
  /**
2485
2608
  * Creates a WritableSignalStore from a value.
2486
2609
  * @see {@link toStore}
@@ -2677,6 +2800,18 @@ type CreateStoredOptions<T> = CreateSignalOptions<T> & {
2677
2800
  * Optional validator, which is called on load of value. Store will be set to fallback if value is false
2678
2801
  */
2679
2802
  validate?: (value: T) => boolean;
2803
+ /**
2804
+ * Opt-in pause: gate the persistence effect on an ambient Activity boundary (`true`), a custom
2805
+ * predicate, or `false` (default — no pausing). While paused the value stays live; persistence is
2806
+ * skipped and flushes the latest value on resume. The inbound `storage` listener stays live.
2807
+ * See {@link PauseOption}.
2808
+ */
2809
+ pause?: PauseOption;
2810
+ /**
2811
+ * Injector used when `stored` is created outside an injection context, and to resolve the ambient
2812
+ * pause boundary when `pause` is `true`.
2813
+ */
2814
+ injector?: Injector;
2680
2815
  };
2681
2816
  /**
2682
2817
  * A specialized `WritableSignal` returned by the `stored()` function.
@@ -2748,13 +2883,21 @@ type StoredSignal<T> = WritableSignal<T> & {
2748
2883
  * }
2749
2884
  * ```
2750
2885
  */
2751
- declare function stored<T>(fallback: T, { key, store: providedStore, serialize, deserialize, syncTabs, equal, onKeyChange, cleanupOldKey, validate, ...rest }: CreateStoredOptions<T>): StoredSignal<T>;
2886
+ declare function stored<T>(fallback: T, { key, store: providedStore, serialize, deserialize, syncTabs, equal, onKeyChange, cleanupOldKey, validate, pause, injector: providedInjector, ...rest }: CreateStoredOptions<T>): StoredSignal<T>;
2752
2887
 
2753
2888
  type LegacySyncSignalOptions = {
2754
2889
  id?: string;
2755
2890
  };
2756
2891
  type SyncSignalOptions = {
2757
2892
  id: string;
2893
+ /**
2894
+ * Injector used when `tabSync` is called outside an injection context.
2895
+ *
2896
+ * NOTE: `tabSync` is intentionally NOT pausable. Pausing the outbound broadcast would let its
2897
+ * mount-time echo guard swallow a value changed while hidden, so other tabs would silently miss
2898
+ * it — a cross-tab consistency gap not worth the negligible saving. The channel stays live.
2899
+ */
2900
+ injector?: Injector;
2758
2901
  };
2759
2902
  /**
2760
2903
  * @example tabSync(signal('dark'), { id: 'theme' })
@@ -2803,12 +2946,16 @@ type CreateThrottledOptions<T> = CreateSignalOptions<T> & {
2803
2946
  /**
2804
2947
  * A specialized `WritableSignal` whose publicly readable value updates are throttled.
2805
2948
  *
2806
- * It provides access to the underlying, non-throttled signal via the `original` property.
2949
+ * Provides access to the underlying, non-throttled signal via `original`, and a
2950
+ * `flush()` that emits the current value immediately (clearing any open window) —
2951
+ * useful for terminal transitions that shouldn't wait for the trailing edge.
2807
2952
  *
2808
2953
  * @template T The type of value held by the signal.
2809
- * @see {DebouncedSignal} as the output type has the same structure.
2810
2954
  */
2811
- type ThrottledSignal<T> = DebouncedSignal<T>;
2955
+ type ThrottledSignal<T> = DebouncedSignal<T> & {
2956
+ /** Emit the latest value now, bypassing the remaining throttle window. */
2957
+ flush: () => void;
2958
+ };
2812
2959
  /**
2813
2960
  * A convenience function that creates and throttles a new `WritableSignal` in one step.
2814
2961
  *
@@ -2829,7 +2976,7 @@ type ThrottledSignal<T> = DebouncedSignal<T>;
2829
2976
  * // With a trailing-edge throttle, the final value 'c' would be set
2830
2977
  * // after the 500ms cooldown.
2831
2978
  */
2832
- declare function throttled<T>(initial: T, opt?: CreateThrottledOptions<T>): DebouncedSignal<T>;
2979
+ declare function throttled<T>(initial: T, opt?: CreateThrottledOptions<T>): ThrottledSignal<T>;
2833
2980
  /**
2834
2981
  * Wraps an existing `WritableSignal` to create a new one whose readable value is throttled.
2835
2982
  *
@@ -3045,5 +3192,5 @@ type CreateHistoryOptions<T> = Omit<CreateSignalOptions<T[]>, 'equal'> & {
3045
3192
  */
3046
3193
  declare function withHistory<T>(sourceOrValue: WritableSignal<T> | T, opt?: CreateHistoryOptions<T>): SignalWithHistory<T>;
3047
3194
 
3048
- export { MmActivity, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, batteryStatus, chunked, clipboard, combineWith, createForwardingScope, createTransaction, createTransitionScope, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, filterWith, focusWithin, forkStore, geolocation, getTransitionScope, holdUntilReady, idle, indexArray, injectPaused, injectRegisterResource, injectStartTransaction, injectStartTransition, injectTransitionScope, isDerivation, isLeaf, isMutable, isOpaque, isStore, keepPrevious, keyArray, map, mapArray, mapObject, mediaQuery, merge3, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, opaque, orientation, pageVisibility, pairwise, pausableComputed, pausableEffect, pausableSignal, pipeable, piped, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, provideForwardingTransitionScope, providePaused, provideTransitionScope, registerResource, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
3049
- export type { BatteryStatus, ClipboardSignal, Computation, CreateChunkedOptions, CreateDebouncedOptions, CreateHistoryOptions, CreatePooledOptions, CreateProvidedPooledOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, Fork, ForkStrategy, ForwardingTransitionScope, Frame, GeolocationOptions, GeolocationSignal, IdleOptions, IdleSignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, Opaque, PausableOptions, PauseOption, PipeableSignal, ReconcileFn, RegisterOptions, ScreenOrientation, ScreenOrientationState, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SensorRunOptions, SignalFromEventOptions, SignalStore, SignalWithHistory, StoredSignal, SuspendType, ThrottledSignal, Transaction, TransactionRef, TransitionRef, TransitionScope, UntilOptions, Vivify, WindowSize, WindowSizeOptions, WindowSizeSignal, WithVivify, WritableSignalStore };
3195
+ export { MmActivity, PAUSABLE_OPTIONS, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, batteryStatus, chunked, clipboard, combineWith, createForwardingScope, createTransaction, createTransitionScope, debounce, debounced, derived, distinct, elementSize, elementVisibility, extendStore, filter, filterWith, focusWithin, forkStore, geolocation, getTransitionScope, holdUntilReady, idle, indexArray, injectPaused, injectRegisterResource, injectStartTransaction, injectStartTransition, injectTransitionScope, isDerivation, isLeaf, isMutable, isOpaque, isStore, keepPrevious, keyArray, map, mapArray, mapObject, mediaQuery, merge3, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, opaque, orientation, pageVisibility, pairwise, pausableComputed, pausableEffect, pausableSignal, pipeable, piped, pointerDrag, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, provideForwardingTransitionScope, providePausableOptions, providePaused, provideTransitionScope, registerResource, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
3196
+ export type { BatteryStatus, ClipboardSignal, Computation, CreateChunkedOptions, CreateDebouncedOptions, CreateHistoryOptions, CreatePooledOptions, CreateProvidedPooledOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, Fork, ForkStrategy, ForwardingTransitionScope, Frame, GeolocationOptions, GeolocationSignal, IdleOptions, IdleSignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, Opaque, PausableOptions, PauseOption, PipeableSignal, PointerDragOptions, PointerDragSignal, PointerDragState, PointerModifiers, PointerPoint, ReconcileFn, RegisterOptions, ScreenOrientation, ScreenOrientationState, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SensorRunOptions, SignalFromEventOptions, SignalStore, SignalWithHistory, StoredSignal, SuspendType, ThrottledSignal, Transaction, TransactionRef, TransitionRef, TransitionScope, UntilOptions, Vivify, WindowSize, WindowSizeOptions, WindowSizeSignal, WithVivify, WritableSignalStore };