@solidjs/signals 2.0.0-rc.13 → 2.0.0-rc.15

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 (121) hide show
  1. package/dist/dev-shared.js +2059 -3768
  2. package/dist/dev.attribution.js +237 -101
  3. package/dist/dev.js +7466 -8497
  4. package/dist/observe/affects.js +128 -104
  5. package/dist/observe/boundaries.js +492 -665
  6. package/dist/observe/core/action.js +63 -66
  7. package/dist/observe/core/async.js +243 -379
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +394 -253
  10. package/dist/observe/core/constants.js +120 -187
  11. package/dist/observe/core/context.js +3 -3
  12. package/dist/observe/core/core.js +874 -1440
  13. package/dist/observe/core/dev.js +3 -3
  14. package/dist/observe/core/effect.js +73 -84
  15. package/dist/observe/core/external.js +5 -5
  16. package/dist/observe/core/graph.js +62 -71
  17. package/dist/observe/core/heap.js +75 -98
  18. package/dist/observe/core/invariants.js +1 -34
  19. package/dist/observe/core/lanes.js +750 -181
  20. package/dist/observe/core/owner.js +80 -101
  21. package/dist/observe/core/scheduler.js +719 -1356
  22. package/dist/observe/core/verdict.js +314 -621
  23. package/dist/observe/flatten.js +79 -0
  24. package/dist/observe/index.js +15 -13
  25. package/dist/observe/map.js +232 -235
  26. package/dist/observe/reveal.js +212 -0
  27. package/dist/observe/signals.js +144 -216
  28. package/dist/observe/store/affects.js +142 -0
  29. package/dist/observe/store/hooks.js +13 -0
  30. package/dist/observe/store/index.js +27 -24
  31. package/dist/observe/store/optimistic.js +571 -0
  32. package/dist/observe/store/projection.js +308 -0
  33. package/dist/observe/store/reconcile.js +259 -0
  34. package/dist/observe/store/store.js +1988 -277
  35. package/dist/observe/store/storePath.js +1 -1
  36. package/dist/{prod/store/next → observe/store}/target.js +17 -18
  37. package/dist/observe/store/types.js +73 -0
  38. package/dist/observe/store/utils.js +1 -13
  39. package/dist/prod/affects.js +130 -106
  40. package/dist/prod/boundaries.js +476 -654
  41. package/dist/prod/core/action.js +71 -74
  42. package/dist/prod/core/async.js +306 -444
  43. package/dist/prod/core/constants.js +117 -186
  44. package/dist/prod/core/context.js +3 -3
  45. package/dist/prod/core/core.js +888 -1462
  46. package/dist/prod/core/effect.js +88 -99
  47. package/dist/prod/core/external.js +5 -5
  48. package/dist/prod/core/graph.js +62 -71
  49. package/dist/prod/core/heap.js +75 -98
  50. package/dist/prod/core/invariants.js +1 -32
  51. package/dist/prod/core/lanes.js +712 -181
  52. package/dist/prod/core/owner.js +75 -96
  53. package/dist/prod/core/scheduler.js +686 -1335
  54. package/dist/prod/core/verdict.js +309 -621
  55. package/dist/prod/flatten.js +77 -0
  56. package/dist/prod/index.js +15 -13
  57. package/dist/prod/map.js +142 -145
  58. package/dist/prod/reveal.js +212 -0
  59. package/dist/prod/signals.js +155 -227
  60. package/dist/prod/store/affects.js +142 -0
  61. package/dist/prod/store/hooks.js +13 -0
  62. package/dist/prod/store/index.js +26 -19
  63. package/dist/prod/store/optimistic.js +566 -0
  64. package/dist/prod/store/projection.js +301 -0
  65. package/dist/prod/store/reconcile.js +259 -0
  66. package/dist/prod/store/store.js +1883 -272
  67. package/dist/prod/store/storePath.js +1 -1
  68. package/dist/{observe/store/next → prod/store}/target.js +13 -17
  69. package/dist/prod/store/types.js +73 -0
  70. package/dist/prod/store/utils.js +1 -11
  71. package/dist/types/affects.d.ts +11 -30
  72. package/dist/types/boundaries.d.ts +66 -176
  73. package/dist/types/carved.d.ts +1 -0
  74. package/dist/types/core/action.d.ts +5 -6
  75. package/dist/types/core/async.d.ts +10 -5
  76. package/dist/types/core/attribution-hooks.d.ts +20 -1
  77. package/dist/types/core/attribution.d.ts +26 -11
  78. package/dist/types/core/constants.d.ts +130 -180
  79. package/dist/types/core/core.d.ts +134 -264
  80. package/dist/types/core/dev.d.ts +2 -2
  81. package/dist/types/core/effect.d.ts +0 -7
  82. package/dist/types/core/graph.d.ts +7 -1
  83. package/dist/types/core/heap.d.ts +5 -7
  84. package/dist/types/core/index.d.ts +5 -5
  85. package/dist/types/core/invariants.d.ts +0 -29
  86. package/dist/types/core/lanes.d.ts +74 -86
  87. package/dist/types/core/owner.d.ts +3 -3
  88. package/dist/types/core/scheduler.d.ts +255 -331
  89. package/dist/types/core/types.d.ts +45 -85
  90. package/dist/types/core/verdict.d.ts +3 -0
  91. package/dist/types/flatten.d.ts +8 -0
  92. package/dist/types/index.d.ts +6 -4
  93. package/dist/types/reveal.d.ts +19 -0
  94. package/dist/types/signals.d.ts +35 -91
  95. package/dist/types/store/affects.d.ts +12 -0
  96. package/dist/types/store/hooks.d.ts +48 -0
  97. package/dist/types/store/index.d.ts +34 -15
  98. package/dist/types/store/optimistic.d.ts +23 -0
  99. package/dist/types/store/projection.d.ts +18 -0
  100. package/dist/types/store/reconcile.d.ts +3 -0
  101. package/dist/types/store/store.d.ts +132 -145
  102. package/dist/types/store/storePath.d.ts +1 -1
  103. package/dist/types/store/target.d.ts +151 -0
  104. package/dist/types/store/types.d.ts +84 -0
  105. package/package.json +1 -1
  106. package/dist/observe/core/optimistic.js +0 -669
  107. package/dist/observe/store/next/optimistic.js +0 -717
  108. package/dist/observe/store/next/projection.js +0 -266
  109. package/dist/observe/store/next/reconcile.js +0 -375
  110. package/dist/observe/store/next/store.js +0 -2608
  111. package/dist/prod/core/optimistic.js +0 -658
  112. package/dist/prod/store/next/optimistic.js +0 -710
  113. package/dist/prod/store/next/projection.js +0 -257
  114. package/dist/prod/store/next/reconcile.js +0 -373
  115. package/dist/prod/store/next/store.js +0 -2484
  116. package/dist/types/core/optimistic.d.ts +0 -6
  117. package/dist/types/store/next/optimistic.d.ts +0 -25
  118. package/dist/types/store/next/projection.d.ts +0 -27
  119. package/dist/types/store/next/reconcile.d.ts +0 -10
  120. package/dist/types/store/next/store.d.ts +0 -145
  121. package/dist/types/store/next/target.d.ts +0 -196
@@ -1,147 +1,134 @@
1
- import { type Signal } from "../core/index.js";
2
- import type { Refreshable } from "../core/index.js";
3
- /** A reactive view of a store's value. Update it through the paired `StoreSetter`. */
4
- export type Store<T> = T;
5
- /**
6
- * A store setter. The callback receives a writable **draft** of the store.
7
- *
8
- * - **Mutate in place (canonical):** `s.foo = 1`, `s.list.push(x)`,
9
- * `s.list.splice(i, 1)`. This is the default form for most updates.
10
- * - **Return a new value:** for shapes where mutation is awkward, most
11
- * commonly removing items (`s => s.list.filter(...)`). Arrays are replaced
12
- * by index (length adjusted); objects are shallow-diffed at the top level
13
- * (keys present in the returned value are written, missing keys deleted).
14
- *
15
- * The setter does **not** perform keyed reconciliation. If you need surviving
16
- * items to keep their store identity across full-array replacement, use the
17
- * projection form — `createStore(fn, seed, { key })` or
18
- * `createProjection(fn, seed, { key })` — whose derive function reconciles
19
- * its return by `options.key`.
20
- */
21
- export type StoreSetter<T> = (fn: (state: T) => T | void) => void;
22
- /** Tuple returned by the plain `createStore(initialValue, options?)` form. */
23
- export type StoreReturn<T> = [get: Store<T>, set: StoreSetter<T>];
24
- /** Tuple returned by the derived `createStore(fn, seed, options?)` form. */
25
- export type ProjectionStoreReturn<T> = [get: Refreshable<Store<T>>, set: StoreSetter<T>];
26
- /** Options shared by all store primitives. */
27
- export interface StoreOptions {
28
- /**
29
- * Debug name (dev and observe builds). Property nodes are labelled
30
- * `<name>.<key>` in attribution output (`todos.title`); a derived store's
31
- * projection node carries the name itself.
32
- */
33
- name?: string;
34
- /** Single-layer store: root keys reactive, values raw records replaced by reference */
35
- shallow?: boolean;
36
- }
37
- /**
38
- * Options for derived/projected stores created with
39
- * `createStore(fn, seed, options?)`, `createProjection(fn, seed, options?)`,
40
- * or `createOptimisticStore(fn, seed, options?)`.
41
- */
42
- export interface ProjectionOptions extends StoreOptions {
43
- /** Key property name or function for reconciliation identity; `null` merges positionally */
44
- key?: string | ((item: NonNullable<any>) => any) | null;
45
- /**
46
- * Treat the seed as commit #0: the store is born committed with the seed's
47
- * contents, shown until the derive's first real answer lands. While that
48
- * first answer is in flight, reads serve the seed everywhere — nothing
49
- * suspends to a `<Loading>` boundary, no transition is held, and
50
- * `isPending` stays false (the seed answers by declaration; first-load
51
- * affordances belong to the data, e.g. a `skeleton: true` field in the
52
- * seed). Once the first answer lands (reconciled into the seed), refetches
53
- * use normal pending semantics with `isPending` true.
54
- *
55
- * The store equivalent of `MemoOptions.loadingValue`; the seed already
56
- * carries the placeholder shape, so this is just the opt-in.
57
- */
58
- seedLoadingValue?: boolean;
1
+ import type { Signal } from "../core/types.js";
2
+ import { type StoreFamily, type StoreTarget } from "./target.js";
3
+ import { type StoreOptions } from "./types.js";
4
+ export { $PROXY, $TARGET, $TRACK, markRaw } from "./types.js";
5
+ export type SetStoreFunction<T> = (fn: (draft: T) => T | void) => void;
6
+ export declare function wrap<T extends Record<PropertyKey, any>>(value: T, parent?: StoreTarget | null, parentKey?: PropertyKey | null, fam?: StoreFamily | null): T;
7
+ /** Unwrap our own proxies to their current backing; leave everything else.
8
+ * A projection draft wrapper is registered as its target's alias
9
+ * (projection.ts `wrapDraft`) — adopted as a backing, it would forward to
10
+ * itself (#3767). */
11
+ export declare function unwrapValue(v: any): any;
12
+ export declare function sameKey(a: any, b: any): boolean;
13
+ /** The container node's arrangement guess: the rows (or keys) the setter
14
+ * left the container with, in order. Its comparator judges a landing or a
15
+ * revert against it by row identity — by key when the family has one
16
+ * (the server's object for a guessed row is the same row). */
17
+ export declare class LaneView {
18
+ rows: Record<PropertyKey, any>;
19
+ /** The backing the guess is shown over: the committed one at the
20
+ * guess, the composed arrangement after a re-base (optimistic.ts). */
21
+ base: Record<PropertyKey, any>;
22
+ /** Keys the setter REMOVED from the view it saw (a deliberate delete,
23
+ * not a row the truth has yet to show): a re-base does not restore
24
+ * them. `null` when none. */
25
+ removed: Set<unknown> | null;
26
+ constructor(rows: Record<PropertyKey, any>,
27
+ /** The backing the guess is shown over: the committed one at the
28
+ * guess, the composed arrangement after a re-base (optimistic.ts). */
29
+ base: Record<PropertyKey, any>,
30
+ /** Keys the setter REMOVED from the view it saw (a deliberate delete,
31
+ * not a row the truth has yet to show): a re-base does not restore
32
+ * them. `null` when none. */
33
+ removed?: Set<unknown> | null);
59
34
  }
60
- export type NoFn<T> = T extends Function ? never : T;
61
- type DataNode = Signal<any>;
62
- type DataNodes = Record<PropertyKey, DataNode>;
63
- /**
64
- * Brand symbols used internally by the store proxy / projection plumbing.
65
- * Cross-package wiring; not part of the user-facing API.
66
- *
67
- * @internal
68
- */
69
- export declare const $TRACK: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol, $RECORD: unique symbol, $DELETED: unique symbol, $AFFECTS: unique symbol;
70
- export declare const STORE_VALUE = "v", STORE_NODE = "n", STORE_HAS = "h", STORE_PARENT = "u", STORE_DESC = "d", STORE_SHALLOW = "s";
71
- /** Structural view of a store target as shared machinery sees it (the real
72
- * shape is `StoreNextTarget` in ./next/target.ts). */
73
- export type StoreNode = {
74
- [$PROXY]: any;
75
- [STORE_VALUE]: Record<PropertyKey, any>;
76
- [STORE_NODE]?: DataNodes;
77
- [STORE_HAS]?: DataNodes;
78
- [STORE_PARENT]?: StoreNode;
79
- [STORE_SHALLOW]?: boolean;
80
- [STORE_DESC]?: boolean;
81
- };
82
- export declare namespace SolidStore {
83
- interface Unwrappable {
84
- }
85
- }
86
- export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
87
- /**
88
- * Marks a value as raw: no store will ever wrap it — every store presents it
89
- * as-is, tracked by reference at whatever slot holds it and updated by
90
- * replacement. Useful for class instances and external objects (editors,
91
- * scene graphs, Maps) and for record-shaped data updated wholesale. Sticky
92
- * for the value's lifetime.
93
- */
94
- export declare let rawValuesUsed: boolean;
95
- export declare function isRawValue(value: any): boolean;
96
- export declare function markRaw<T>(value: T): T;
97
- export declare function markRawOne(v: any): void;
98
- export declare function markRawIngest(container: any): void;
99
- export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
100
- export declare function setWriteOverride(value: boolean): void;
101
- export declare function getWriteOverride(): boolean;
102
- export declare function ownEnumerableKeys(o: object): (string | symbol)[];
103
- /**
104
- * Scope inheritance for late-created nodes: every live mark whose identity
105
- * scope contains the owning record's raw — and, for keyed marks, whose key
106
- * is this property — gets counted on the new node. Inherited marks live
107
- * exactly as long as the scope's carrier — the release hook below drops
108
- * them with the entry.
109
- */
110
- export declare function inheritAffectsMarks(node: DataNode, raw: object, property: PropertyKey): void;
111
- /** Next-store node factory for affects carriers/slots: injected by the
112
- * rewrite module (next targets alias the legacy field names, so everything
113
- * here EXCEPT node creation works on them structurally). */
114
- export declare let nextAffectsNodeResolver: ((target: any, key: PropertyKey) => DataNode) | null;
115
- export declare function setNextAffectsNodeResolver(fn: (target: any, key: PropertyKey) => DataNode): void;
116
- /** Next-store optimistic view for the declaration walk (optimistic rows
117
- * pushed before the declaration are in motion too — legacy reads its write
118
- * overlays; next composes armed-node overrides). */
119
- export declare let nextOptimisticViewResolver: ((target: any, raw: any) => any) | null;
120
- export declare function setNextOptimisticViewResolver(fn: (target: any, raw: any) => any): void;
121
- /** @internal birth inheritance for nodes created inside a live mark window —
122
- * exported for the rewrite's node factories. */
123
- export declare function affectsScopesLive(): boolean;
124
- /**
125
- * Witness live mark coverage of a record into the active isPending() probe.
126
- * Tracked reads don't need this — they go through real signal nodes, which
127
- * carry marks directly (declaration walk or birth inheritance). This covers
128
- * UNTRACKED probes reading through records whose nodes never materialized
129
- * (no observer ever subscribed, so no node exists to carry the mark).
130
- * Callers guard on `pendingCheckActive`, so plain reads never pay for this.
131
- *
132
- * @internal
133
- */
134
- export declare function witnessAffectsMark(target: StoreNode, property?: PropertyKey): void;
135
- /**
136
- * Resolves the store nodes an `affects()` declaration marks: with a `key`,
137
- * the named slot's leaf node (upserted so the mark has an addressable
138
- * carrier); without, the record's $AFFECTS carrier plus every LIVE node in
139
- * its subtree (the edges existing readers subscribed through), with the
140
- * subtree's identities snapshotted into the mark's scope so nodes created
141
- * during the window — and untracked probes over captured proxies — resolve
142
- * against it (#2882).
35
+ /** A container node's value as a backing: the base an arrangement guess is
36
+ * shown over, else the value itself. */
37
+ export declare function asBacking(v: any): Record<PropertyKey, any>;
38
+ /** The container node's comparator: a staging is a backing (identity — a
39
+ * pending backing is never "equal" to the committed one); a lane value is
40
+ * an arrangement (`LaneView`), judged by the optimistic machinery. */
41
+ export declare const containerEquals: (this: any, a: any, b: any) => boolean;
42
+ export declare function getNode(target: StoreTarget, key: PropertyKey, accKnown?: -1 | 0 | 1): Signal<any>;
43
+ export declare function getHasNode(target: StoreTarget, key: PropertyKey): Signal<boolean>;
44
+ /** The container node (plan sec. 31.3): created by the first structural subscription
45
+ * or the first write that needs to stage. Its committed value is the
46
+ * committed backing. */
47
+ export declare function getContainerNode(target: StoreTarget): Signal<any>;
48
+ export declare function bumpDeep(t: StoreTarget): void;
49
+ export declare function nameStore(proxy: any, name: string | undefined): void;
50
+ /** Shallow clone into store ownership. Plain data (grade 2) spreads; anything
51
+ * else copies descriptors (accessors kept, everything made configurable). */
52
+ export declare function cloneRaw(source: Record<PropertyKey, any>, t: StoreTarget): Record<PropertyKey, any>;
53
+ /** Downgrade an overlay to a real clone (a consumer needs a container). */
54
+ export declare function materializePB(target: StoreTarget): Record<PropertyKey, any>;
55
+ /** Adoption (a setter's returned replacement; reconcile and projection
56
+ * landings in S3): the incoming object becomes the backing by reference at
57
+ * the fold — no clones, no user-object mutation, ownership resets to
58
+ * shared. It is the container's staging until then (signal parity: a
59
+ * handler reads the committed frame until the flush; a hold keeps it
60
+ * staged with the rest). The nodes are told now, diffed against the view
61
+ * they were LAST told (#3296): the draft's pending backing when one
62
+ * preceded the adoption this batch — its node writes were real, and the
63
+ * adoption's re-stage cancels or confirms each — else the committed
64
+ * backing. */
65
+ export declare function adoptPB(target: StoreTarget, incoming: Record<PropertyKey, any>, notify?: boolean): void;
66
+ export declare function runDirect(fn: () => void): void;
67
+ /** Is the open setter a user's? (reconcile.ts: a user's reconcile on an
68
+ * optimistic family writes the draft.) */
69
+ export declare function userWriting(): boolean;
70
+ /** Two raws that wrap to the same target are the same logical value. */
71
+ export declare function targetsEqual(ov: any, nv: any): boolean;
72
+ /** Positional identity IS content for arrays (R15). */
73
+ export declare function arrayStructureChanged(old: any[], neu: any[]): boolean;
74
+ export declare function membershipChanged(old: Record<PropertyKey, any>, neu: Record<PropertyKey, any>): boolean;
75
+ /** One leaf's notification for an adoption diff (descriptor-aware). */
76
+ export declare function notifyKeyDiff(node: Signal<any>, key: PropertyKey, old: Record<PropertyKey, any>, neu: Record<PropertyKey, any>, probe?: boolean): void;
77
+ export declare function hasAccessorFlag(node: Signal<any>): boolean;
78
+ /** One leaf's notification when the caller already has both values. */
79
+ export declare function notifyKeyValue(node: Signal<any>, key: PropertyKey, ov: any, nv: any, old: Record<PropertyKey, any>, neu: Record<PropertyKey, any>): void;
80
+ /** The structural half of an adoption's notifications (reconcile does the
81
+ * leaves itself): presence by `in`, the container by membership. Presence
82
+ * is DIFFED `old` → `neu` like the leaves (#3743): a presence node is
83
+ * written only where `in` changed between the view it was last told
84
+ * (#3296) and the adoption — `setSignal` joins a held node's transaction
85
+ * before its equality gate (A34 (1)), so repeating an unchanged absence to
86
+ * a node an action holds would make the whole tick the action's (an
87
+ * unrelated `a.value` stayed stale until the action settled). A real
88
+ * change still writes, and on a held node still proposes. A live chained
89
+ * `old` (a store proxy, §7b) reflects the inner store, not what the node
90
+ * was last told — written unconditionally, as before.
143
91
  *
144
- * @internal
145
- */
146
- export declare function getStoreAffectsNodes(target: StoreNode, key?: PropertyKey): DataNode[];
147
- export {};
92
+ * The container is told of an arrangement change when it has structural
93
+ * subscribers OR carries an arrangement guess (S4): for a guessed
94
+ * container the write is the landing that judges the guess (Q-D, plan
95
+ * sec. 39 — confirm, supersede, or hold beneath), not a subscriber
96
+ * notification, and a landing whose truth changed no guessed key's value
97
+ * or presence (a newer question's rows beneath an optimistic push) still
98
+ * answers the arrangement — before, only the presence write reached the
99
+ * lane, by accident of being unconditional. */
100
+ export declare function notifyFoldTail(t: StoreTarget, old: Record<PropertyKey, any>, neu: Record<PropertyKey, any>): void;
101
+ /** An adoption's notifications: every node of the target, diffed `old` →
102
+ * `neu` (value nodes by key, presence by `in`, the container by
103
+ * membership, the deep witness by identity). */
104
+ export declare function notifyFold(t: StoreTarget, old: Record<PropertyKey, any>, neu: Record<PropertyKey, any>): void;
105
+ /** The committed backing: the container node's committed value while a
106
+ * batch is staged on it (an adoption swaps `t.v` eagerly — INTERNALS §3,
107
+ * "adoption is eager by contract" — and the node keeps the frame committed
108
+ * readers under a hold still see), `t.v` otherwise. */
109
+ export declare function committed(t: StoreTarget): Record<PropertyKey, any>;
110
+ /** The same row at a slot, as the adoption pairs rows (reconcile.ts): two
111
+ * objects whose keys agree — positionally for an unkeyed family. */
112
+ export declare function sameRow(pv: any, nv: any, keyFn: ((item: any) => any) | null): boolean;
113
+ /** A chained backing's child (§7b): a raw the inner family owns, or holds
114
+ * at this key, is served as the inner store's wrapper — never a fresh
115
+ * raw-keyed one — so the chained targets are the same objects across
116
+ * settled and pending views. */
117
+ export declare function resolveChainedRaw(target: StoreTarget, key: PropertyKey, v: object): any;
118
+ export declare function storeSetter<T>(proxy: T, fn: (draft: T) => T | void, guard?: boolean): void;
119
+ export declare function createStore<T extends Record<PropertyKey, any>>(initialValue: T, options?: StoreOptions): [T, SetStoreFunction<T>];
120
+ /** True when `proxy` is a SHALLOW store (children served verbatim, slots
121
+ * replaced by reference — #2932). The list driver uses this to choose the
122
+ * slot-patch channel (collected row bodies) over per-record registration. */
123
+ export declare function storeIsShallow(proxy: any): boolean;
124
+ /** True when `proxy` belongs to a projection family (S3). */
125
+ export declare function storeHasFamily(proxy: any): boolean;
126
+ /** True when `proxy` belongs to an OPTIMISTIC family (S4). */
127
+ export declare function storeHasOptimisticFamily(proxy: any): boolean;
128
+ /** Tracking snapshot: subscribes every reachable record's container and deep
129
+ * witness (one node per record, not one per path), then snapshots. */
130
+ export declare function deep<T>(value: T): T;
131
+ /** Non-tracking snapshot: source identity for unowned subtrees (zero copy),
132
+ * a copy for owned ones (they are by definition modified relative to the
133
+ * source). Sees the pending backing (R27). */
134
+ export declare function snapshot<T>(value: T): T;
@@ -1,4 +1,4 @@
1
- import { type NotWrappable } from "./store.js";
1
+ import { type NotWrappable } from "./types.js";
2
2
  type W<T> = Exclude<T, NotWrappable>;
3
3
  type KeyOf<T> = number extends keyof T ? 0 extends 1 & T ? keyof T : [T] extends [never] ? never : [T] extends [readonly unknown[]] ? number : keyof T : keyof T;
4
4
  export type CustomPartial<T> = T extends readonly unknown[] ? "0" extends keyof T ? {
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Store — target & ownership (INTERNALS-STORE-STATE.md §1, §5b; plan sec. 31).
3
+ *
4
+ * The proxy wraps this internal target, never the raw. `v` is the single
5
+ * committed home; the pending backing (`pb`) is the CoW overlay/clone the
6
+ * draft mutates natively — and, on L2, the **container node's staging**
7
+ * (plan sec. 31.3, Q-A): `k` is the `$TRACK` node given a value. Its `_value` is the
8
+ * committed backing, its `_pendingValue` the pending backing, so the
9
+ * scheduler owns the backing's lifetime (park, commit, revert) and the store
10
+ * keeps no fold ledger of its own. The fold at the flush's commit
11
+ * (`_storeCommit`) is the one mutation of owned raw.
12
+ *
13
+ * Creation budget (§5b): one minimal target + one proxy + one lookup entry
14
+ * per read-through object; nodes, presence nodes, the container node and
15
+ * the deep witness are lazy — materialized by subscription, or (the
16
+ * container) by the first write that needs to stage.
17
+ */
18
+ import type { Computed, Owner, Signal } from "../core/types.js";
19
+ /** Projection family (§7b; returns in S3): children wrap into the family's
20
+ * own map (writes land in the projection, never the source family), and the
21
+ * family's node is the firewall every read through it pulls first. */
22
+ export interface StoreFamily {
23
+ /** Optimistic family (S4): the setter's writes are guesses. */
24
+ opt?: boolean;
25
+ /** Targets carrying a lane value on one of their nodes (reads compose the
26
+ * view over the truth — optimistic.ts); dropped lazily once none is. */
27
+ overlaid?: Set<StoreTarget>;
28
+ /** Normalized row-key fn (`options.key`, "id" default, null = unkeyed). */
29
+ key?: ((item: any) => any) | null;
30
+ map: WeakMap<object, StoreTarget>;
31
+ /** The projection computed — the firewall. Assigned after creation. */
32
+ node: Computed<any> | null;
33
+ /** Targets of the family that carry nodes: the derive's pending wakes
34
+ * their readers (A9) — the family's enumerable index, in place of a
35
+ * per-leaf chain; a target leaves it with its last node. */
36
+ live: Set<StoreTarget>;
37
+ shallow?: boolean;
38
+ /** Derive run counter (proj R37): the run whose draft is live. */
39
+ run?: number;
40
+ /** The derive's pending reached the leaves' readers (`wakeFamily`) and no
41
+ * landing has settled them yet: the next commit walks the family
42
+ * (`settleFamily`). A sync commit with no wake behind it walks nothing. */
43
+ woke?: boolean;
44
+ }
45
+ export interface StoreTarget {
46
+ /** Committed backing: source object (shared) or owned clone. */
47
+ v: Record<PropertyKey, any>;
48
+ /** Pending backing for the current batch (null when settled) — the same
49
+ * object the container node stages (`k._pendingValue`). */
50
+ pb: Record<PropertyKey, any> | null;
51
+ /** cached: committed backing is another store's proxy (§7b chained). */
52
+ ch: boolean;
53
+ /** live value-node count (deleted-key sweep fast-out in the fused walk). */
54
+ nc: number;
55
+ /** Lazy per-property subscription nodes (slot nodes). */
56
+ n: Record<PropertyKey, Signal<any>> | null;
57
+ /** Lazy per-key presence nodes (`in` tracks presence, not value — R13). */
58
+ h: Record<PropertyKey, Signal<boolean>> | null;
59
+ /** Lazy CONTAINER node: membership/iteration/`$TRACK`/`length`
60
+ * subscriptions (§6) and the backing's staging home (plan sec. 31.3). */
61
+ k: Signal<any> | null;
62
+ /** Keys written through the traps since the last fold commit. Bounds the
63
+ * setter notify/hold-check to O(written) instead of O(subscribed nodes) —
64
+ * a record with thousands of per-key subscriptions (selection maps) would
65
+ * otherwise pay a full node scan on every write. null = no trap writes
66
+ * this batch (bulk paths fall back to the full scan); WK_ALL = bound
67
+ * unusable (array length write). LOAD-BEARING SHAPE RULE: array proxy
68
+ * targets carry their fields as named properties on a real array, and V8
69
+ * normalizes an array to dictionary properties as the named count grows
70
+ * (empirically at counts ≡ 0 mod 3 from 18 up on V8 13.x) — every trap
71
+ * field read then becomes a hash lookup (~15% uibench, tree suites
72
+ * worst). Future write-side state MUST ride an extension object, not new
73
+ * named fields. */
74
+ wk: Set<PropertyKey> | null;
75
+ /** Lazy deep-witness node: `deep()` subscribes ONE node per record instead
76
+ * of one per path; write paths bump it only when it exists. Separate from
77
+ * `k` so $TRACK/mapArray never rerun on leaf value changes (R9). */
78
+ dk: Signal<number> | null;
79
+ /** Parent target (path copying walks this at commit). */
80
+ u: StoreTarget | null;
81
+ /** Property key of this target in the parent's backing. */
82
+ pk: PropertyKey | null;
83
+ /** The proxy for this target (stable outward identity). */
84
+ px: any;
85
+ /** Sticky descendants flag (§6d). */
86
+ d: boolean;
87
+ /** Sticky accessors-seen flag: an own accessor property was observed on
88
+ * this target (first-read scan, defineProperty, or clone scan). Gates the
89
+ * fold diff's descriptor-safe path and the get trap's descriptor path. */
90
+ a: boolean;
91
+ /** Accessor scan grade: 0 = not yet scanned (adoption resets — adopted data
92
+ * is not rescanned until the next draft), 1 = scanned, 2 = scanned and
93
+ * PLAIN DATA — `Object.prototype` with every own key an enumerable data
94
+ * property. Grade 2 unlocks the spread clone (cloneRaw), bare-assignment
95
+ * overlay writes and flatten (#3360); a non-plain defineProperty through
96
+ * the draft downgrades it to 1. */
97
+ sc: 0 | 1 | 2;
98
+ /** Own-key count: exact at scan, then bumped by set-trap writes of keys new
99
+ * to the container (never decremented — an estimate for the overlay/clone
100
+ * choice only, #3360). */
101
+ kc: number;
102
+ /** Pending backing is a prototype-chain OVERLAY of the committed backing
103
+ * (`Object.create(v)` — own keys are this batch's writes, everything else
104
+ * reads through). O(written) per flush instead of O(container) clones
105
+ * (#3044); commit flattens own keys onto an owned committed backing in
106
+ * place. Plain-data non-array containers qualify; chained backings and
107
+ * accessor containers keep the descriptor clone. `materializePB`
108
+ * downgrades to the clone path when a consumer needs a real container
109
+ * (draft escape). */
110
+ ovl: boolean;
111
+ /** Keys deleted in the overlay window (a prototype overlay cannot shadow
112
+ * a delete); null when none. */
113
+ del: Set<PropertyKey> | null;
114
+ /** Projection family, null for plain stores (§7b). */
115
+ fam: StoreFamily | null;
116
+ /** Shallow store root (values served raw). */
117
+ s: boolean;
118
+ }
119
+ /**
120
+ * Ownership stamp (#3360): every backing the store ALLOCATES (CoW clones,
121
+ * privatized committed backings) carries its owning target under this
122
+ * enumerable symbol. One property write replaces the two weak-collection
123
+ * registrations (ownership set + raw→target map) a fresh object used to pay
124
+ * per draft — V8's identity-hash + ephemeron cost dominated the one-key
125
+ * write floor. Enumerable so a spread copy (the plain-data clone path) stays
126
+ * on the fast path and carries the stamp along.
127
+ *
128
+ * Owned backings are never user-reachable (`snapshot` copies them, the traps
129
+ * hide the key), so every raw key walk in the store must skip `$OWNER`, and
130
+ * ownership is answered by `isOwned` — a user object never carries it.
131
+ * Overlay drafts (`Object.create(v)` over an owned `v`) inherit the stamp.
132
+ */
133
+ export declare const $OWNER: unique symbol;
134
+ /** raw → target for plain (family-less) stores. Family stores use their own
135
+ * map so one raw can wrap once per family (§7b). */
136
+ export declare const storeLookup: WeakMap<object, StoreTarget>;
137
+ export declare function setLookup(raw: object, t: StoreTarget): void;
138
+ export declare function isOwned(raw: object): boolean;
139
+ /** The target wrapping `raw` in `fam` (or the plain lookup). An owned raw
140
+ * answers from its stamp; a user raw from the map. */
141
+ export declare function lookupTarget(raw: object, fam: StoreFamily | null): StoreTarget | undefined;
142
+ /** Test-tier oracle (INTERNALS §5): no write path ever mutates a
143
+ * user-provided (non-owned) object. */
144
+ export declare const ingestedRaw: WeakSet<object> | null;
145
+ export declare function devAssertNeverUserMutation(target: object): void;
146
+ /** Sticky descendants flag up the parent chain (§6d): adoption descends
147
+ * into a changed child pair only where a target with nodes exists below. */
148
+ export declare function markDescendants(target: StoreTarget): void;
149
+ /** Observe tier: the owner in scope at `createStore` (attribution names and
150
+ * owner paths); the `_owner` write never reaches the proxy. */
151
+ export declare const storeOwners: WeakMap<StoreTarget, Owner | null> | null;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Store — public types, brand symbols, wrappability and raw marking. Shared
3
+ * by every store module; carries no reactive machinery of its own.
4
+ */
5
+ import type { Refreshable } from "../core/index.js";
6
+ /** A reactive view of a store's value. Update it through the paired `StoreSetter`. */
7
+ export type Store<T> = T;
8
+ /**
9
+ * A store setter. The callback receives a writable **draft** of the store.
10
+ *
11
+ * - **Mutate in place (canonical):** `s.foo = 1`, `s.list.push(x)`,
12
+ * `s.list.splice(i, 1)`. This is the default form for most updates.
13
+ * - **Return a new value:** for shapes where mutation is awkward, most
14
+ * commonly removing items (`s => s.list.filter(...)`). Arrays are replaced
15
+ * by index (length adjusted); objects are shallow-diffed at the top level
16
+ * (keys present in the returned value are written, missing keys deleted).
17
+ *
18
+ * The setter does **not** perform keyed reconciliation. If you need surviving
19
+ * items to keep their store identity across full-array replacement, use the
20
+ * projection form — `createStore(fn, seed, { key })` or
21
+ * `createProjection(fn, seed, { key })` — whose derive function reconciles
22
+ * its return by `options.key`.
23
+ */
24
+ export type StoreSetter<T> = (fn: (state: T) => T | void) => void;
25
+ /** Tuple returned by the plain `createStore(initialValue, options?)` form. */
26
+ export type StoreReturn<T> = [get: Store<T>, set: StoreSetter<T>];
27
+ /** Tuple returned by the derived `createStore(fn, seed, options?)` form. */
28
+ export type ProjectionStoreReturn<T> = [get: Refreshable<Store<T>>, set: StoreSetter<T>];
29
+ /** Options shared by all store primitives. */
30
+ export interface StoreOptions {
31
+ /**
32
+ * Debug name (dev and observe builds). Property nodes are labelled
33
+ * `<name>.<key>` in attribution output (`todos.title`); a derived store's
34
+ * projection node carries the name itself.
35
+ */
36
+ name?: string;
37
+ /** Single-layer store: root keys reactive, values raw records replaced by reference */
38
+ shallow?: boolean;
39
+ }
40
+ /**
41
+ * Options for derived/projected stores created with
42
+ * `createStore(fn, seed, options?)`, `createProjection(fn, seed, options?)`,
43
+ * or `createOptimisticStore(fn, seed, options?)`.
44
+ */
45
+ export interface ProjectionOptions extends StoreOptions {
46
+ /** Key property name or function for reconciliation identity; `null` merges positionally */
47
+ key?: string | ((item: NonNullable<any>) => any) | null;
48
+ /**
49
+ * Treat the seed as commit #0: the store is born committed with the seed's
50
+ * contents, shown until the derive's first real answer lands. While that
51
+ * first answer is in flight, reads serve the seed everywhere — nothing
52
+ * suspends to a `<Loading>` boundary, no transition is held, and
53
+ * `isPending` stays false (the seed answers by declaration; first-load
54
+ * affordances belong to the data, e.g. a `skeleton: true` field in the
55
+ * seed). Once the first answer lands (reconciled into the seed), refetches
56
+ * use normal pending semantics with `isPending` true.
57
+ *
58
+ * The store equivalent of `MemoOptions.loadingValue`; the seed already
59
+ * carries the placeholder shape, so this is just the opt-in.
60
+ */
61
+ seedLoadingValue?: boolean;
62
+ }
63
+ export type NoFn<T> = T extends Function ? never : T;
64
+ /** Brand keys the proxy answers directly (never user data). */
65
+ export declare const $TRACK: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol, $RECORD: unique symbol;
66
+ export declare namespace SolidStore {
67
+ interface Unwrappable {
68
+ }
69
+ }
70
+ export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
71
+ export declare let rawValuesUsed: boolean;
72
+ export declare function isRawValue(value: any): boolean;
73
+ /** Mark a value so no store ever wraps it (sticky; it reads as a leaf). */
74
+ export declare function markRaw<T>(value: T): T;
75
+ /** A shallow store's ingested record: raw by contract (values served
76
+ * verbatim, slots replaced by reference). */
77
+ export declare function markRawOne(v: any): void;
78
+ export declare function markRawIngest(container: any): void;
79
+ /** Plain objects and arrays wrap; class instances, DOM nodes, frozen objects
80
+ * and markRaw'd values are leaves. Per-prototype verdict cached. */
81
+ export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
82
+ export declare function ownEnumerableKeys(o: object): (string | symbol)[];
83
+ export declare let writeOverride: boolean;
84
+ export declare function setWriteOverride(value: boolean): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/signals",
3
- "version": "2.0.0-rc.13",
3
+ "version": "2.0.0-rc.15",
4
4
  "description": "Solid's reactive primitives: signals, memos, effects, stores, and async-aware computations.",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",