@solidjs/signals 0.9.4 → 0.9.6

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.
@@ -6,6 +6,7 @@ export declare const REACTIVE_IN_HEAP: number;
6
6
  export declare const REACTIVE_IN_HEAP_HEIGHT: number;
7
7
  export declare const REACTIVE_ZOMBIE: number;
8
8
  export declare const REACTIVE_DISPOSED: number;
9
+ export declare const REACTIVE_OPTIMISTIC_DIRTY: number;
9
10
  export declare const STATUS_NONE = 0;
10
11
  export declare const STATUS_PENDING: number;
11
12
  export declare const STATUS_ERROR: number;
@@ -13,6 +14,7 @@ export declare const STATUS_UNINITIALIZED: number;
13
14
  export declare const EFFECT_PURE = 0;
14
15
  export declare const EFFECT_RENDER = 1;
15
16
  export declare const EFFECT_USER = 2;
17
+ export declare const EFFECT_TRACKED = 3;
16
18
  export declare const NOT_PENDING: {};
17
19
  export declare const SUPPORTS_PROXY: boolean;
18
20
  export declare const defaultContext: {};
@@ -19,12 +19,9 @@ export interface SignalOptions<T> {
19
19
  lazy?: boolean;
20
20
  }
21
21
  export interface RawSignal<T> {
22
- id?: string;
23
22
  _subs: Link | null;
24
23
  _subsTail: Link | null;
25
24
  _value: T;
26
- _error?: unknown;
27
- _statusFlags: number;
28
25
  _name?: string;
29
26
  _equals: false | ((a: T, b: T) => boolean);
30
27
  _pureWrite?: boolean;
@@ -32,13 +29,9 @@ export interface RawSignal<T> {
32
29
  _time: number;
33
30
  _transition: Transition | null;
34
31
  _pendingValue: T | typeof NOT_PENDING;
35
- _pendingCheck?: Signal<boolean> & {
36
- _set: (v: boolean) => void;
37
- };
38
- _pendingSignal?: Signal<T> & {
39
- _set: (v: T) => void;
40
- };
41
32
  _optimistic?: boolean;
33
+ _pendingSignal?: Signal<boolean>;
34
+ _pendingValueComputed?: Computed<T>;
42
35
  }
43
36
  export interface FirewallSignal<T> extends RawSignal<T> {
44
37
  _firewall: Computed<any>;
@@ -61,13 +54,15 @@ export interface Computed<T> extends RawSignal<T>, Owner {
61
54
  _deps: Link | null;
62
55
  _depsTail: Link | null;
63
56
  _flags: number;
57
+ _error?: unknown;
58
+ _statusFlags: number;
64
59
  _height: number;
65
60
  _nextHeap: Computed<any> | undefined;
66
61
  _prevHeap: Computed<any>;
67
62
  _fn: (prev?: T) => T;
68
- _inFlight: Promise<T> | AsyncIterable<T> | null;
63
+ _inFlight: PromiseLike<T> | AsyncIterable<T> | null;
69
64
  _child: FirewallSignal<any> | null;
70
- _notifyQueue?: (statusFlagsChanged: boolean, prevStatusFlags: number) => void;
65
+ _notifyStatus?: () => void;
71
66
  }
72
67
  export interface Root extends Owner {
73
68
  _root: true;
@@ -75,14 +70,17 @@ export interface Root extends Owner {
75
70
  dispose(self?: boolean): void;
76
71
  }
77
72
  export declare let context: Owner | null;
73
+ export declare function setLeafEffectActive(v: boolean): void;
78
74
  export declare function recompute(el: Computed<any>, create?: boolean): void;
79
- export declare function handleAsync<T>(el: Computed<T>, result: T | Promise<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
75
+ export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
80
76
  export declare function dispose(node: Computed<unknown>): void;
81
77
  export declare function getNextChildId(owner: Owner): string;
82
- export declare function computed<T>(fn: (prev?: T) => T | Promise<T> | AsyncIterable<T>): Computed<T>;
83
- export declare function computed<T>(fn: (prev: T) => T | Promise<T> | AsyncIterable<T>, initialValue?: T, options?: SignalOptions<T>): Computed<T>;
78
+ export declare function computed<T>(fn: (prev?: T) => T | PromiseLike<T> | AsyncIterable<T>): Computed<T>;
79
+ export declare function computed<T>(fn: (prev: T) => T | PromiseLike<T> | AsyncIterable<T>, initialValue?: T, options?: SignalOptions<T>): Computed<T>;
84
80
  export declare function signal<T>(v: T, options?: SignalOptions<T>): Signal<T>;
85
81
  export declare function signal<T>(v: T, options?: SignalOptions<T>, firewall?: Computed<any>): FirewallSignal<T>;
82
+ export declare function optimisticSignal<T>(v: T, options?: SignalOptions<T>): Signal<T>;
83
+ export declare function optimisticComputed<T>(fn: (prev?: T) => T | PromiseLike<T> | AsyncIterable<T>, initialValue?: T, options?: SignalOptions<T>): Computed<T>;
86
84
  export declare function isEqual<T>(a: T, b: T): boolean;
87
85
  /**
88
86
  * Returns the current value stored inside the given compute function without triggering any
@@ -16,3 +16,14 @@ export declare function effect<T>(compute: (prev: T | undefined) => T, effect: (
16
16
  render?: boolean;
17
17
  defer?: boolean;
18
18
  }): void;
19
+ export interface TrackedEffect extends Computed<void> {
20
+ _cleanup?: () => void;
21
+ _modified: boolean;
22
+ _type: number;
23
+ _run: () => void;
24
+ }
25
+ /**
26
+ * Internal tracked effect - bypasses heap, goes directly to effect queue.
27
+ * Children forbidden (__DEV__ throws). Uses stale reads.
28
+ */
29
+ export declare function trackedEffect(fn: () => void | (() => void), options?: SignalOptions<any>): void;
@@ -1,6 +1,6 @@
1
1
  export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./error.js";
2
2
  export { createContext, getContext, setContext, type Context, type ContextRecord } from "./context.js";
3
- export { getObserver, isEqual, untrack, getOwner, runWithOwner, createOwner, createRoot, computed, dispose, signal, read, setSignal, onCleanup, getNextChildId, isPending, pending, refresh, isRefreshing, staleValues, handleAsync, type Owner, type Computed, type Root, type Signal, type SignalOptions } from "./core.js";
4
- export { effect, type Effect } from "./effect.js";
5
- export { action, flush, Queue, type IQueue, type QueueCallback } from "./scheduler.js";
3
+ export { getObserver, isEqual, untrack, getOwner, runWithOwner, createOwner, createRoot, computed, dispose, signal, read, setSignal, onCleanup, optimisticSignal, optimisticComputed, getNextChildId, isPending, pending, refresh, isRefreshing, staleValues, handleAsync, type Owner, type Computed, type Root, type Signal, type SignalOptions } from "./core.js";
4
+ export { effect, trackedEffect, type Effect, type TrackedEffect } from "./effect.js";
5
+ export { action, flush, Queue, GlobalQueue, trackOptimisticStore, type IQueue, type QueueCallback } from "./scheduler.js";
6
6
  export * from "./constants.js";
@@ -1,10 +1,13 @@
1
1
  import type { Computed, Signal } from "./core.js";
2
2
  import { type Heap } from "./heap.js";
3
- export declare let optimisticRun: boolean;
4
3
  export declare const dirtyQueue: Heap;
5
4
  export declare const zombieQueue: Heap;
6
5
  export declare let clock: number;
7
6
  export declare let activeTransition: Transition | null;
7
+ export declare let optimisticReadActive: boolean;
8
+ export declare let projectionWriteActive: boolean;
9
+ export declare function setOptimisticReadActive(value: boolean): void;
10
+ export declare function setProjectionWriteActive(value: boolean): void;
8
11
  export type QueueCallback = (type: number) => void;
9
12
  type QueueStub = {
10
13
  _queues: [QueueCallback[], QueueCallback[]];
@@ -15,6 +18,7 @@ export interface Transition {
15
18
  asyncNodes: Computed<any>[];
16
19
  pendingNodes: Signal<any>[];
17
20
  optimisticNodes: Signal<any>[];
21
+ optimisticStores: Set<any>;
18
22
  actions: Array<Generator<any, any, any> | AsyncGenerator<any, any, any>>;
19
23
  queueStash: QueueStub;
20
24
  done: boolean | Transition;
@@ -34,12 +38,15 @@ export interface IQueue {
34
38
  export declare class Queue implements IQueue {
35
39
  _parent: IQueue | null;
36
40
  _queues: [QueueCallback[], QueueCallback[]];
41
+ _optimisticQueues: [QueueCallback[], QueueCallback[]];
37
42
  _children: IQueue[];
38
43
  created: number;
39
44
  addChild(child: IQueue): void;
40
45
  removeChild(child: IQueue): void;
41
46
  notify(node: Computed<any>, mask: number, flags: number): boolean;
47
+ private _runQueue;
42
48
  run(type: number): void;
49
+ runOptimistic(type: number): void;
43
50
  enqueue(type: number, fn: QueueCallback): void;
44
51
  stashQueues(stub: QueueStub): void;
45
52
  restoreQueues(stub: QueueStub): void;
@@ -48,14 +55,17 @@ export declare class GlobalQueue extends Queue {
48
55
  _running: boolean;
49
56
  _pendingNodes: Signal<any>[];
50
57
  _optimisticNodes: Signal<any>[];
58
+ _optimisticStores: Set<any>;
51
59
  static _update: (el: Computed<unknown>) => void;
52
60
  static _dispose: (el: Computed<unknown>, self: boolean, zombie: boolean) => void;
61
+ static _clearOptimisticStore: ((store: any) => void) | null;
53
62
  flush(): void;
54
63
  notify(node: Computed<any>, mask: number, flags: number): boolean;
55
- initTransition(node?: Computed<any>): void;
64
+ initTransition(transition?: Transition | null): void;
56
65
  }
57
- export declare function notifySubs(node: Signal<any> | Computed<any>): void;
58
- export declare function runOptimistic(activeTransition?: Transition | null): void;
66
+ export declare function insertSubs(node: Signal<any> | Computed<any>, optimistic?: boolean): void;
67
+ export declare function finalizePureQueue(completingTransition?: Transition | null, incomplete?: boolean): void;
68
+ export declare function trackOptimisticStore(store: any): void;
59
69
  export declare const globalQueue: GlobalQueue;
60
70
  /**
61
71
  * By default, changes are batched on the microtask queue which is an async process. You can flush
@@ -63,5 +73,5 @@ export declare const globalQueue: GlobalQueue;
63
73
  */
64
74
  export declare function flush(): void;
65
75
  export declare function runInTransition<T>(transition: Transition, fn: () => T): T;
66
- export declare function action<Args extends any[], Y, R>(genFn: (...args: Args) => Generator<Y, R, any> | AsyncGenerator<Y, R, any>): (...args: Args) => void;
76
+ export declare function action<Args extends any[], Y, R>(genFn: (...args: Args) => Generator<Y, R, any> | AsyncGenerator<Y, R, any>): (...args: Args) => Promise<R>;
67
77
  export {};
@@ -7,7 +7,7 @@ export type Setter<in out T> = {
7
7
  <U extends T>(value: Exclude<U, Function> | ((prev: T) => U)): U;
8
8
  };
9
9
  export type Signal<T> = [get: Accessor<T>, set: Setter<T>];
10
- export type ComputeFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Promise<Next> | AsyncIterable<Next> | Next;
10
+ export type ComputeFunction<Prev, Next extends Prev = Prev> = (v: Prev) => PromiseLike<Next> | AsyncIterable<Next> | Next;
11
11
  export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Next, p?: Prev) => (() => void) | void;
12
12
  export type EffectBundle<Prev, Next extends Prev = Prev> = {
13
13
  effect: EffectFunction<Prev, Next>;
@@ -105,11 +105,17 @@ export declare function createEffect<Next, Init = Next>(compute: ComputeFunction
105
105
  export declare function createRenderEffect<Next>(compute: ComputeFunction<undefined | NoInfer<Next>, Next>, effectFn: EffectFunction<NoInfer<Next>, Next>): void;
106
106
  export declare function createRenderEffect<Next, Init = Next>(compute: ComputeFunction<Init | Next, Next>, effectFn: EffectFunction<Next, Next>, value: Init, options?: EffectOptions): void;
107
107
  /**
108
- * Creates a tracked reactive effect that only tracks dependencies inside the effect itself
108
+ * Creates a tracked reactive effect where dependency tracking and side effects happen
109
+ * in the same scope.
110
+ *
111
+ * WARNING: Because tracking and effects happen in the same scope, this primitive
112
+ * may run multiple times for a single change or show tearing (reading inconsistent
113
+ * state). Use only when dynamic subscription patterns require same-scope tracking.
114
+ *
109
115
  * ```typescript
110
116
  * export function createTrackedEffect(
111
117
  * compute: () => (() => void) | void,
112
- * options?: { name?: string, defer?: boolean }
118
+ * options?: { name?: string }
113
119
  * ): void;
114
120
  * ```
115
121
  * @param compute a function that contains reactive reads to track and returns an optional cleanup function to run on disposal or before next execution
@@ -137,7 +143,48 @@ export declare function createReaction(effectFn: EffectFunction<undefined> | Eff
137
143
  * @param fn a reactive expression to resolve
138
144
  */
139
145
  export declare function resolve<T>(fn: () => T): Promise<T>;
146
+ /**
147
+ * Creates an optimistic signal that can be used to optimistically update a value
148
+ * and then revert it back to the previous value at end of transition.
149
+ * ```typescript
150
+ * export function createOptimistic<T>(): Signal<T | undefined>;
151
+ * export function createOptimistic<T>(
152
+ * value: Exclude<T, Function>,
153
+ * options?: SignalOptions<T>
154
+ * ): Signal<T>;
155
+ * export function createOptimistic<T>(
156
+ * fn: ComputeFunction<T>,
157
+ * initialValue?: T,
158
+ * options?: SignalOptions<T>
159
+ * ): Signal<T>;
160
+ * ```
161
+ * @param value initial value of the signal; if empty, the signal's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error
162
+ * @param options optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity
163
+ *
164
+ * @returns ```typescript
165
+ * [state: Accessor<T>, setState: Setter<T>]
166
+ * ```
167
+ * * the Accessor is a function that returns the current value and registers each call to the reactive root
168
+ * * the Setter is a function that allows directly setting or mutating the value:
169
+ * ```typescript
170
+ * const [count, setCount] = createOptimistic(0);
171
+ * setCount(count => count + 1);
172
+ * ```
173
+ *
174
+ * @description https://docs.solidjs.com/reference/basic-reactivity/create-optimistic-signal
175
+ */
140
176
  export declare function createOptimistic<T>(): Signal<T | undefined>;
141
177
  export declare function createOptimistic<T>(value: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
142
178
  export declare function createOptimistic<T>(fn: ComputeFunction<T>, initialValue?: T, options?: SignalOptions<T>): Signal<T>;
179
+ /**
180
+ * Runs a callback after the current flush cycle completes.
181
+ *
182
+ * When called within a reactive context (owner), uses a tracked effect with untracked
183
+ * reads - this means normal signal reads won't create subscriptions, but uninitialized
184
+ * async values will throw NotReadyError, causing the callback to re-run when they settle.
185
+ *
186
+ * When called without an owner, runs once and immediately calls any returned cleanup.
187
+ *
188
+ * @param callback Function to run, may return a cleanup function
189
+ */
143
190
  export declare function onSettled(callback: () => void | (() => void)): void;
@@ -1,9 +1,10 @@
1
- import { type Store, type StoreSetter } from "./store.js";
1
+ import { $REFRESH } from "../core/index.js";
2
+ import { type NoFn, type Store, type StoreOptions, type StoreSetter } from "./store.js";
2
3
  /**
3
4
  * Creates an optimistic store that can be used to optimistically update a value
4
5
  * and then revert it back to the previous value at end of transition.
5
6
  * ```typescript
6
- * export function createOptimistic<T>(
7
+ * export function createOptimisticStore<T>(
7
8
  * fn: (store: T) => void,
8
9
  * initial: T,
9
10
  * options?: { key?: string | ((item: NonNullable<any>) => any); all?: boolean }
@@ -15,8 +16,7 @@ import { type Store, type StoreSetter } from "./store.js";
15
16
  *
16
17
  * @returns A tuple containing an accessor for the current value and a setter function to apply changes.
17
18
  */
18
- export declare function createOptimisticStore<T extends object = {}>(initial: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
19
- export declare function createOptimisticStore<T extends object = {}>(fn: (store: T) => T | void, initial: T | Store<T>, options?: {
20
- key?: string | ((item: NonNullable<any>) => any);
21
- all?: boolean;
22
- }): [get: Store<T>, set: StoreSetter<T>];
19
+ export declare function createOptimisticStore<T extends object = {}>(store: NoFn<T> | Store<NoFn<T>>): [get: Store<T>, set: StoreSetter<T>];
20
+ export declare function createOptimisticStore<T extends object = {}>(fn: (store: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, store?: NoFn<T> | Store<NoFn<T>>, options?: StoreOptions): [get: Store<T> & {
21
+ [$REFRESH]: any;
22
+ }, set: StoreSetter<T>];
@@ -14,3 +14,4 @@ export declare function createProjectionInternal<T extends object = {}>(fn: (dra
14
14
  export declare function createProjection<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, initialValue?: T, options?: StoreOptions): Store<T> & {
15
15
  [$REFRESH]: any;
16
16
  };
17
+ export declare const writeTraps: ProxyHandler<any>;
@@ -5,19 +5,22 @@ export type StoreOptions = {
5
5
  key?: string | ((item: NonNullable<any>) => any);
6
6
  all?: boolean;
7
7
  };
8
+ export type NoFn<T> = T extends Function ? never : T;
8
9
  type DataNode = Signal<any>;
9
10
  type DataNodes = Record<PropertyKey, DataNode>;
10
11
  export declare const $TRACK: unique symbol, $DEEP: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol, $DELETED: unique symbol;
11
- export declare const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_NODE = "n", STORE_HAS = "h", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f";
12
+ export declare const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p";
12
13
  export type StoreNode = {
13
14
  [$PROXY]: any;
14
15
  [STORE_VALUE]: Record<PropertyKey, any>;
15
16
  [STORE_OVERRIDE]?: Record<PropertyKey, any>;
17
+ [STORE_OPTIMISTIC_OVERRIDE]?: Record<PropertyKey, any>;
16
18
  [STORE_NODE]?: DataNodes;
17
19
  [STORE_HAS]?: DataNodes;
18
20
  [STORE_WRAP]?: (value: any, target?: StoreNode) => any;
19
21
  [STORE_LOOKUP]?: WeakMap<any, any>;
20
22
  [STORE_FIREWALL]?: Computed<any>;
23
+ [STORE_OPTIMISTIC]?: boolean;
21
24
  };
22
25
  export declare namespace SolidStore {
23
26
  interface Unwrappable {
@@ -33,7 +36,6 @@ export declare function getKeys(source: Record<PropertyKey, any>, override: Reco
33
36
  export declare function getPropertyDescriptor(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, property: PropertyKey): PropertyDescriptor | undefined;
34
37
  export declare const storeTraps: ProxyHandler<StoreNode>;
35
38
  export declare function storeSetter<T extends object>(store: Store<T>, fn: (draft: T) => T | void): void;
36
- type NoFn<T> = T extends Function ? never : T;
37
39
  export declare function createStore<T extends object = {}>(store: NoFn<T> | Store<NoFn<T>>): [get: Store<T>, set: StoreSetter<T>];
38
40
  export declare function createStore<T extends object = {}>(fn: (store: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, store?: NoFn<T> | Store<NoFn<T>>, options?: StoreOptions): [get: Store<T> & {
39
41
  [$REFRESH]: any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/signals",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",