@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.3

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.
Files changed (58) hide show
  1. package/dist/dev.js +1779 -383
  2. package/dist/node.cjs +2058 -1359
  3. package/dist/prod/affects.js +16 -16
  4. package/dist/prod/boundaries.js +90 -90
  5. package/dist/prod/core/action.js +3 -3
  6. package/dist/prod/core/async.js +74 -72
  7. package/dist/prod/core/constants.js +39 -1
  8. package/dist/prod/core/core.js +332 -224
  9. package/dist/prod/core/effect.js +56 -56
  10. package/dist/prod/core/external.js +4 -4
  11. package/dist/prod/core/graph.js +65 -54
  12. package/dist/prod/core/heap.js +52 -44
  13. package/dist/prod/core/invariants.js +3 -2
  14. package/dist/prod/core/lanes.js +41 -34
  15. package/dist/prod/core/optimistic.js +93 -68
  16. package/dist/prod/core/owner.js +97 -96
  17. package/dist/prod/core/scheduler.js +243 -194
  18. package/dist/prod/core/verdict.js +191 -77
  19. package/dist/prod/map.js +104 -104
  20. package/dist/prod/signals.js +1 -1
  21. package/dist/prod/store/next/optimistic.js +31 -23
  22. package/dist/prod/store/next/projection.js +109 -47
  23. package/dist/prod/store/next/reconcile.js +78 -74
  24. package/dist/prod/store/next/store.js +357 -90
  25. package/dist/prod/store/store.js +7 -7
  26. package/dist/types/core/attribution-hooks.d.ts +52 -0
  27. package/dist/types/core/attribution.d.ts +186 -0
  28. package/dist/types/core/constants.d.ts +26 -0
  29. package/dist/types/core/core.d.ts +8 -1
  30. package/dist/types/core/dev.d.ts +20 -3
  31. package/dist/types/core/graph.d.ts +1 -0
  32. package/dist/types/core/invariants.d.ts +1 -1
  33. package/dist/types/core/lanes.d.ts +4 -16
  34. package/dist/types/core/scheduler.d.ts +8 -0
  35. package/dist/types/core/types.d.ts +85 -41
  36. package/dist/types/store/next/projection.d.ts +0 -16
  37. package/dist/types/store/next/store.d.ts +6 -0
  38. package/dist/types/store/next/target.d.ts +18 -0
  39. package/dist/types-cjs/core/attribution-hooks.d.cts +52 -0
  40. package/dist/types-cjs/core/attribution.d.cts +186 -0
  41. package/dist/types-cjs/core/constants.d.cts +26 -0
  42. package/dist/types-cjs/core/core.d.cts +8 -1
  43. package/dist/types-cjs/core/dev.d.cts +20 -3
  44. package/dist/types-cjs/core/graph.d.cts +1 -0
  45. package/dist/types-cjs/core/invariants.d.cts +1 -1
  46. package/dist/types-cjs/core/lanes.d.cts +4 -16
  47. package/dist/types-cjs/core/scheduler.d.cts +8 -0
  48. package/dist/types-cjs/core/types.d.cts +85 -41
  49. package/dist/types-cjs/store/next/projection.d.cts +0 -16
  50. package/dist/types-cjs/store/next/store.d.cts +6 -0
  51. package/dist/types-cjs/store/next/target.d.cts +18 -0
  52. package/package.json +15 -15
  53. package/dist/types/store/optimistic.d.ts +0 -45
  54. package/dist/types/store/projection.d.ts +0 -70
  55. package/dist/types/store/reconcile.d.ts +0 -46
  56. package/dist/types-cjs/store/optimistic.d.cts +0 -45
  57. package/dist/types-cjs/store/projection.d.cts +0 -70
  58. package/dist/types-cjs/store/reconcile.d.cts +0 -46
@@ -1,19 +1,3 @@
1
- /**
2
- * Store rewrite — projections (§7/§7b): a projection is a computed store.
3
- * The derive runs inside a computed whose recompute merges its output into
4
- * the projection's backing through the adoption channel (replace-mode root:
5
- * entity changes merge in place, the root proxy is stable for life). Children
6
- * wrap into the projection's own FAMILY (writes land here, never in a source
7
- * family), and every family node carries the projection computed as its
8
- * firewall — reads link the derive's status and lifecycle natively. The §6c
9
- * status gate in the traps makes an uninitialized async derive's seed
10
- * unobservable through every read surface.
11
- *
12
- * Mirrors the legacy runProjectionComputed shape (shadow runs for open
13
- * loading windows, handleAsync landings, commit-through-setter) on next
14
- * primitives; the generic draft write-traps are reused from the legacy
15
- * module unchanged.
16
- */
17
1
  import { type Computed, type Refreshable } from "../../core/index.cjs";
18
2
  import { type NoFn, type ProjectionOptions, type Store } from "../store.cjs";
19
3
  export declare function createProjectionNext<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): Refreshable<Store<T>>;
@@ -9,6 +9,12 @@ export declare function getKeySetNode(target: StoreNextTarget): Signal<number>;
9
9
  /** Deep-witness bump: any value/shape change on a record with a live deep()
10
10
  * subscriber notifies it. One null check when unused. */
11
11
  export declare function bumpDeep(t: StoreNextTarget): void;
12
+ /** Downgrade a prototype-overlay pending backing to the clone path: builds
13
+ * the real container (committed + overlay writes − deletes) that fold will
14
+ * SWAP in as the committed backing, exactly as if the draft had started on
15
+ * the clone path. Consumers that need a complete container (reconcile's
16
+ * diff walks, drafts escaping into other storage) call this. */
17
+ export declare function materializePB(target: StoreNextTarget): void;
12
18
  /**
13
19
  * Adoption (2026-08-16c): the incoming object becomes the committed backing
14
20
  * IMMEDIATELY — reconcile is eagerly visible to every reader (shipped
@@ -68,6 +68,24 @@ export interface StoreNextTarget {
68
68
  sc: boolean;
69
69
  /** Backing was swapped by adoption this batch (fold diff-notifies it). */
70
70
  adopted: boolean;
71
+ /** Pending backing is a prototype-chain OVERLAY of the committed backing
72
+ * (`Object.create(v)` — own keys are this batch's writes, everything else
73
+ * reads through). O(written) per flush instead of O(container) clones
74
+ * (#3044); commit flattens own keys onto an owned committed backing in
75
+ * place. Only plain-data non-array non-family containers qualify;
76
+ * `materializePB` downgrades to the clone path when a consumer needs a
77
+ * real container (reconcile, draft escape). */
78
+ ovl: boolean;
79
+ /** Keys deleted in the overlay window (a prototype overlay cannot shadow
80
+ * a delete); null when none. */
81
+ del: Set<PropertyKey> | null;
82
+ /** Keys written through the traps since the last fold commit. Bounds the
83
+ * setter notify/hold-check to O(written) instead of O(subscribed nodes) —
84
+ * a record with thousands of per-key subscriptions (selection maps) would
85
+ * otherwise pay a full node scan on every write. null = no trap writes
86
+ * this batch (bulk paths fall back to the full scan); WK_ALL sentinel =
87
+ * bound unusable this batch (array length write implies index deletes). */
88
+ wk: Set<PropertyKey> | null;
71
89
  /** Projection family, null for plain stores (§7b). */
72
90
  fam: StoreNextFamily | null;
73
91
  /** Shallow store root (values served raw). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/signals",
3
- "version": "2.0.0-rc.1",
3
+ "version": "2.0.0-rc.3",
4
4
  "description": "Solid's reactive primitives: signals, memos, effects, stores, and async-aware computations.",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
@@ -8,7 +8,7 @@
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/solidjs/solid.git",
11
- "directory": "packages/solid-signals"
11
+ "directory": "packages/signals"
12
12
  },
13
13
  "publishConfig": {
14
14
  "access": "public"
@@ -39,6 +39,18 @@
39
39
  },
40
40
  "./package.json": "./package.json"
41
41
  },
42
+ "scripts": {
43
+ "build": "npm-run-all -nl build:* && pnpm types",
44
+ "build:clean": "rimraf dist/dev dist/prod dist/node dist/dev.js dist/prod.js dist/node.cjs",
45
+ "build:js": "rollup -c && node ./scripts/mangle-props.mjs dist/prod dist/node.cjs && node ./scripts/check-pure.mjs dist/prod",
46
+ "types": "tsc -p tsconfig.build.json && node ../../scripts/sync-dual-types.mjs ./dist/types ./dist/types-cjs",
47
+ "test": "vitest run",
48
+ "test:watch": "vitest watch tests",
49
+ "test:gc": "node --expose-gc ./vitest.js",
50
+ "test:gc:watch": "node --expose-gc ./vitest.js --watch",
51
+ "coverage": "vitest run --coverage",
52
+ "bench": "vitest bench --run"
53
+ },
42
54
  "devDependencies": {
43
55
  "@codspeed/vitest-plugin": "^5.4.0",
44
56
  "@ianvs/prettier-plugin-sort-imports": "^4.1.1",
@@ -53,17 +65,5 @@
53
65
  "typescript": "^6.0.3",
54
66
  "vite": "^7.0.0",
55
67
  "vitest": "^4.1.6"
56
- },
57
- "scripts": {
58
- "build": "npm-run-all -nl build:* && pnpm types",
59
- "build:clean": "rimraf dist/dev dist/prod dist/node dist/dev.js dist/prod.js dist/node.cjs",
60
- "build:js": "rollup -c && node ./scripts/mangle-props.mjs dist/prod dist/node.cjs && node ./scripts/check-pure.mjs dist/prod",
61
- "types": "tsc -p tsconfig.build.json && node ../../scripts/sync-dual-types.mjs ./dist/types ./dist/types-cjs",
62
- "test": "vitest run",
63
- "test:watch": "vitest watch tests",
64
- "test:gc": "node --expose-gc ./vitest.js",
65
- "test:gc:watch": "node --expose-gc ./vitest.js --watch",
66
- "coverage": "vitest run --coverage",
67
- "bench": "vitest bench --run"
68
68
  }
69
- }
69
+ }
@@ -1,45 +0,0 @@
1
- import { type Refreshable } from "../core/index.js";
2
- import { type NoFn, type ProjectionOptions, type Store, type StoreSetter } from "./store.js";
3
- /**
4
- * The store equivalent of `createOptimistic`. Writes inside an `action`
5
- * transition are tentative — they show up immediately but auto-revert (or
6
- * reconcile to the action's resolved value) once the transition finishes.
7
- *
8
- * Use this for optimistic UI on collection-shaped data. For single-value
9
- * optimistic state, prefer `createOptimistic`.
10
- *
11
- * - Plain form: `createOptimisticStore(initialValue)`.
12
- * - Derived form: `createOptimisticStore(fn, seed, options?)` — a projection
13
- * store whose authoritative value is recomputed by `fn` and whose
14
- * optimistic overlay reverts after each transition.
15
- *
16
- * `options.key` defaults to `"id"`; specify it only when your data uses a
17
- * different identity field (e.g. `{ key: "uuid" }` or `{ key: t => t.slug }`),
18
- * or `null` to merge positionally. Restating the default just adds noise.
19
- *
20
- * @example
21
- * ```ts
22
- * const [todos, setTodos] = createOptimisticStore<Todo[]>([]);
23
- *
24
- * // Mutation: optimistic add, then in-place reconcile to the saved row.
25
- * const addTodo = action(function* (text: string) {
26
- * const tempId = crypto.randomUUID();
27
- * setTodos(t => { t.push({ id: tempId, text, pending: true }); });
28
- * const saved = yield api.createTodo(text);
29
- * setTodos(t => {
30
- * const i = t.findIndex(x => x.id === tempId);
31
- * if (i >= 0) t[i] = saved;
32
- * });
33
- * });
34
- *
35
- * // Return form: filter is the natural shape for removal.
36
- * const removeTodo = action(function* (id: string) {
37
- * setTodos(t => t.filter(x => x.id !== id));
38
- * yield api.removeTodo(id);
39
- * });
40
- * ```
41
- *
42
- * @returns `[store: Store<T>, setStore: StoreSetter<T>]`
43
- */
44
- export declare function createOptimisticStore<T extends object = {}>(store: NoFn<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Store<T>, set: StoreSetter<T>];
45
- export declare function createOptimisticStore<T extends object = {}>(fn: (store: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, store: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Refreshable<Store<T>>, set: StoreSetter<T>];
@@ -1,70 +0,0 @@
1
- import { type Computed, type Refreshable } from "../core/index.js";
2
- import { type NoFn, type ProjectionOptions, type Store } from "./store.js";
3
- export declare function createProjectionInternal<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T>, options?: ProjectionOptions): {
4
- store: Refreshable<Store<T>>;
5
- node: Computed<void | T>;
6
- };
7
- /**
8
- * Creates a derived (projected) store. Like `createMemo` but for stores: the
9
- * derive function receives a mutable draft and either mutates it in place
10
- * (canonical) or returns a new value. Either way the result is reconciled
11
- * against the previous draft by `options.key` (default `"id"`), so surviving
12
- * items keep their proxy identity — only added/removed items are
13
- * created/disposed.
14
- *
15
- * If the derive returns a different entity than the one currently held (the
16
- * `/users/1` → `/users/2` shape), the store swaps to it rather than merging,
17
- * and nothing below it is treated as surviving.
18
- *
19
- * Returns the projected store directly (no setter — reads only).
20
- *
21
- * Use this when you want the structural-sharing / per-property tracking
22
- * behaviour of a store on top of a derived computation. For simple read-only
23
- * derivations, `createMemo` is lighter.
24
- *
25
- * @param fn receives the current draft; mutate it in place or return new
26
- * data. Return is convenient for filter/derive shapes where mutation is
27
- * awkward.
28
- * @param seed the backing store value to wrap and reconcile into
29
- * @param options `ProjectionOptions` — `name`, `key`. `key` defaults to
30
- * `"id"`; specify it only when your data uses a different identity field
31
- * (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`), or `null` to merge
32
- * positionally with no keyed pass.
33
- *
34
- * @example
35
- * ```ts
36
- * // Mutation form — update individual fields on the draft.
37
- * const summary = createProjection<{ total: number; active: number }>(
38
- * draft => {
39
- * draft.total = users().length;
40
- * draft.active = users().filter(u => u.active).length;
41
- * },
42
- * { total: 0, active: 0 }
43
- * );
44
- *
45
- * // Return form — produce a derived collection. Reconciled by `id` so each
46
- * // surviving user keeps the same store identity across recomputes.
47
- * const activeUsers = createProjection<User[]>(
48
- * () => allUsers().filter(u => u.active),
49
- * []
50
- * );
51
- * ```
52
- *
53
- * @see {@link https://github.com/solidjs/x-reactivity#createprojection}
54
- */
55
- export declare function createProjection<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): Refreshable<Store<T>>;
56
- /**
57
- * Shared projection computed body used by both `createProjection` and the derived
58
- * form of `createOptimisticStore`. Encapsulates the write-trap draft, `storeSetter`
59
- * wrapping, the `handleAsync` subscription with a setter callback, and the commit
60
- * path (which must always go through `storeSetter` so the `writeOnly` guard is
61
- * engaged during `reconcile`'s property reads).
62
- *
63
- * `wrapCommit` is invoked for every commit (sync return and each async yield) and
64
- * lets callers layer extra context around the write — e.g. the optimistic store
65
- * re-enters `setProjectionWriteActive` so reconciles target `STORE_OVERRIDE`
66
- * instead of `STORE_OPTIMISTIC_OVERRIDE` even when an async yield fires outside
67
- * the outer `setProjectionWriteActive` scope.
68
- */
69
- export declare function runProjectionComputed<T extends object>(wrappedStore: Store<T>, fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, key: string | ((item: NonNullable<any>) => any) | null, wrapCommit?: (write: () => void) => void, onDraftWrite?: () => void): Computed<void | T>;
70
- export declare function createWriteTraps(isActive?: () => boolean, onDraftWrite?: () => void): ProxyHandler<any>;
@@ -1,46 +0,0 @@
1
- /**
2
- * Shared body of `reconcile()` and the projection commit. `replace` is the
3
- * only difference: a projection commit is a value swap, not a merge — its root
4
- * proxy is a cell handed out by `createProjection` that can never change
5
- * reference, so a derive returning a different entity is not the slot mistake
6
- * `reconcile()` throws on. Nothing below the root survives that swap, which is
7
- * the rule the keyed diff already applies at a nested slot on a key mismatch.
8
- *
9
- * @internal
10
- */
11
- export declare function reconcileState(value: any, state: any, key: any, replace: boolean): void;
12
- /**
13
- * Returns a draft-mutating function that smart-merges `value` into a store,
14
- * preserving fine-grained reactivity: only changed leaves trigger updates.
15
- *
16
- * With a `key` (default `"id"`), array items whose key matches between old
17
- * and new states keep their identity (updated in place, moves and removals
18
- * update the corresponding signals) — the shape for keyed server payloads.
19
- * Items without the key field fall back to positional matching.
20
- *
21
- * With `key: null`, matching is purely positional: index N of the new array
22
- * merges into index N of the old, and object properties merge recursively —
23
- * the classic pattern for fixed-shape data that churns in place (dashboards,
24
- * monitors), where no keyed diff pass is needed or wanted.
25
- *
26
- * Merging into a slot that holds a *different* entity throws — the caller
27
- * picked the slot, so a key mismatch there is a bug.
28
- *
29
- * @param value the next state to merge in
30
- * @param key property name (string) or extractor function for stable
31
- * identity (default `"id"`); pass `null` for positional merging
32
- *
33
- * @example
34
- * ```ts
35
- * const [todos, setTodos] = createStore<Todo[]>([]);
36
- *
37
- * async function refresh() {
38
- * const fresh = await api.getTodos();
39
- * setTodos(reconcile(fresh)); // diff-merge by `id`
40
- * }
41
- *
42
- * // fixed-shape polling data — positional merge
43
- * setStats(reconcile(nextStats, null));
44
- * ```
45
- */
46
- export declare function reconcile<T extends U, U>(value: T, key?: string | ((item: NonNullable<any>) => any) | null): (state: U) => void;
@@ -1,45 +0,0 @@
1
- import { type Refreshable } from "../core/index.cjs";
2
- import { type NoFn, type ProjectionOptions, type Store, type StoreSetter } from "./store.cjs";
3
- /**
4
- * The store equivalent of `createOptimistic`. Writes inside an `action`
5
- * transition are tentative — they show up immediately but auto-revert (or
6
- * reconcile to the action's resolved value) once the transition finishes.
7
- *
8
- * Use this for optimistic UI on collection-shaped data. For single-value
9
- * optimistic state, prefer `createOptimistic`.
10
- *
11
- * - Plain form: `createOptimisticStore(initialValue)`.
12
- * - Derived form: `createOptimisticStore(fn, seed, options?)` — a projection
13
- * store whose authoritative value is recomputed by `fn` and whose
14
- * optimistic overlay reverts after each transition.
15
- *
16
- * `options.key` defaults to `"id"`; specify it only when your data uses a
17
- * different identity field (e.g. `{ key: "uuid" }` or `{ key: t => t.slug }`),
18
- * or `null` to merge positionally. Restating the default just adds noise.
19
- *
20
- * @example
21
- * ```ts
22
- * const [todos, setTodos] = createOptimisticStore<Todo[]>([]);
23
- *
24
- * // Mutation: optimistic add, then in-place reconcile to the saved row.
25
- * const addTodo = action(function* (text: string) {
26
- * const tempId = crypto.randomUUID();
27
- * setTodos(t => { t.push({ id: tempId, text, pending: true }); });
28
- * const saved = yield api.createTodo(text);
29
- * setTodos(t => {
30
- * const i = t.findIndex(x => x.id === tempId);
31
- * if (i >= 0) t[i] = saved;
32
- * });
33
- * });
34
- *
35
- * // Return form: filter is the natural shape for removal.
36
- * const removeTodo = action(function* (id: string) {
37
- * setTodos(t => t.filter(x => x.id !== id));
38
- * yield api.removeTodo(id);
39
- * });
40
- * ```
41
- *
42
- * @returns `[store: Store<T>, setStore: StoreSetter<T>]`
43
- */
44
- export declare function createOptimisticStore<T extends object = {}>(store: NoFn<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Store<T>, set: StoreSetter<T>];
45
- export declare function createOptimisticStore<T extends object = {}>(fn: (store: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, store: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): [get: Refreshable<Store<T>>, set: StoreSetter<T>];
@@ -1,70 +0,0 @@
1
- import { type Computed, type Refreshable } from "../core/index.cjs";
2
- import { type NoFn, type ProjectionOptions, type Store } from "./store.cjs";
3
- export declare function createProjectionInternal<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T>, options?: ProjectionOptions): {
4
- store: Refreshable<Store<T>>;
5
- node: Computed<void | T>;
6
- };
7
- /**
8
- * Creates a derived (projected) store. Like `createMemo` but for stores: the
9
- * derive function receives a mutable draft and either mutates it in place
10
- * (canonical) or returns a new value. Either way the result is reconciled
11
- * against the previous draft by `options.key` (default `"id"`), so surviving
12
- * items keep their proxy identity — only added/removed items are
13
- * created/disposed.
14
- *
15
- * If the derive returns a different entity than the one currently held (the
16
- * `/users/1` → `/users/2` shape), the store swaps to it rather than merging,
17
- * and nothing below it is treated as surviving.
18
- *
19
- * Returns the projected store directly (no setter — reads only).
20
- *
21
- * Use this when you want the structural-sharing / per-property tracking
22
- * behaviour of a store on top of a derived computation. For simple read-only
23
- * derivations, `createMemo` is lighter.
24
- *
25
- * @param fn receives the current draft; mutate it in place or return new
26
- * data. Return is convenient for filter/derive shapes where mutation is
27
- * awkward.
28
- * @param seed the backing store value to wrap and reconcile into
29
- * @param options `ProjectionOptions` — `name`, `key`. `key` defaults to
30
- * `"id"`; specify it only when your data uses a different identity field
31
- * (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`), or `null` to merge
32
- * positionally with no keyed pass.
33
- *
34
- * @example
35
- * ```ts
36
- * // Mutation form — update individual fields on the draft.
37
- * const summary = createProjection<{ total: number; active: number }>(
38
- * draft => {
39
- * draft.total = users().length;
40
- * draft.active = users().filter(u => u.active).length;
41
- * },
42
- * { total: 0, active: 0 }
43
- * );
44
- *
45
- * // Return form — produce a derived collection. Reconciled by `id` so each
46
- * // surviving user keeps the same store identity across recomputes.
47
- * const activeUsers = createProjection<User[]>(
48
- * () => allUsers().filter(u => u.active),
49
- * []
50
- * );
51
- * ```
52
- *
53
- * @see {@link https://github.com/solidjs/x-reactivity#createprojection}
54
- */
55
- export declare function createProjection<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, seed: Partial<T> | Store<NoFn<T>>, options?: ProjectionOptions): Refreshable<Store<T>>;
56
- /**
57
- * Shared projection computed body used by both `createProjection` and the derived
58
- * form of `createOptimisticStore`. Encapsulates the write-trap draft, `storeSetter`
59
- * wrapping, the `handleAsync` subscription with a setter callback, and the commit
60
- * path (which must always go through `storeSetter` so the `writeOnly` guard is
61
- * engaged during `reconcile`'s property reads).
62
- *
63
- * `wrapCommit` is invoked for every commit (sync return and each async yield) and
64
- * lets callers layer extra context around the write — e.g. the optimistic store
65
- * re-enters `setProjectionWriteActive` so reconciles target `STORE_OVERRIDE`
66
- * instead of `STORE_OPTIMISTIC_OVERRIDE` even when an async yield fires outside
67
- * the outer `setProjectionWriteActive` scope.
68
- */
69
- export declare function runProjectionComputed<T extends object>(wrappedStore: Store<T>, fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, key: string | ((item: NonNullable<any>) => any) | null, wrapCommit?: (write: () => void) => void, onDraftWrite?: () => void): Computed<void | T>;
70
- export declare function createWriteTraps(isActive?: () => boolean, onDraftWrite?: () => void): ProxyHandler<any>;
@@ -1,46 +0,0 @@
1
- /**
2
- * Shared body of `reconcile()` and the projection commit. `replace` is the
3
- * only difference: a projection commit is a value swap, not a merge — its root
4
- * proxy is a cell handed out by `createProjection` that can never change
5
- * reference, so a derive returning a different entity is not the slot mistake
6
- * `reconcile()` throws on. Nothing below the root survives that swap, which is
7
- * the rule the keyed diff already applies at a nested slot on a key mismatch.
8
- *
9
- * @internal
10
- */
11
- export declare function reconcileState(value: any, state: any, key: any, replace: boolean): void;
12
- /**
13
- * Returns a draft-mutating function that smart-merges `value` into a store,
14
- * preserving fine-grained reactivity: only changed leaves trigger updates.
15
- *
16
- * With a `key` (default `"id"`), array items whose key matches between old
17
- * and new states keep their identity (updated in place, moves and removals
18
- * update the corresponding signals) — the shape for keyed server payloads.
19
- * Items without the key field fall back to positional matching.
20
- *
21
- * With `key: null`, matching is purely positional: index N of the new array
22
- * merges into index N of the old, and object properties merge recursively —
23
- * the classic pattern for fixed-shape data that churns in place (dashboards,
24
- * monitors), where no keyed diff pass is needed or wanted.
25
- *
26
- * Merging into a slot that holds a *different* entity throws — the caller
27
- * picked the slot, so a key mismatch there is a bug.
28
- *
29
- * @param value the next state to merge in
30
- * @param key property name (string) or extractor function for stable
31
- * identity (default `"id"`); pass `null` for positional merging
32
- *
33
- * @example
34
- * ```ts
35
- * const [todos, setTodos] = createStore<Todo[]>([]);
36
- *
37
- * async function refresh() {
38
- * const fresh = await api.getTodos();
39
- * setTodos(reconcile(fresh)); // diff-merge by `id`
40
- * }
41
- *
42
- * // fixed-shape polling data — positional merge
43
- * setStats(reconcile(nextStats, null));
44
- * ```
45
- */
46
- export declare function reconcile<T extends U, U>(value: T, key?: string | ((item: NonNullable<any>) => any) | null): (state: U) => void;