@reactra/store 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/index.d.ts +357 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +570 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Akhil Shastri and the Reactra contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @reactra/store
|
|
2
|
+
|
|
3
|
+
> Reactra store runtime — scoped, fine-grained, per-field-subscription state for Reactra apps.
|
|
4
|
+
|
|
5
|
+
**Alpha** — published under the npm dist-tag `alpha`. APIs may change before 1.0.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @reactra/store@alpha
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Part of [Reactra](https://github.com/akhilshastri/reactra) — a compiler-first,
|
|
12
|
+
React-19-compatible framework. See the [documentation](https://reactra-docs.vercel.app) to get
|
|
13
|
+
started.
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-store runtime instance. Compiler-emitted factories build one of these
|
|
3
|
+
* via `createStoreInstance` and hand it to the registry. The factory closure
|
|
4
|
+
* owns the state vars; the instance just exposes the subscribe + getSnapshot
|
|
5
|
+
* pair that `useSyncExternalStore` needs.
|
|
6
|
+
*/
|
|
7
|
+
export interface StoreInstance<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
8
|
+
/** Subscribe to all changes. Returns an unsubscribe fn. */
|
|
9
|
+
subscribe: (onChange: () => void) => () => void;
|
|
10
|
+
/**
|
|
11
|
+
* Return the current snapshot — a stable object reference until the next
|
|
12
|
+
* `notify()` call. `useSyncExternalStore` relies on referential stability
|
|
13
|
+
* to avoid infinite re-renders.
|
|
14
|
+
*
|
|
15
|
+
* `T` is the store's public surface (state + derived + actions). The
|
|
16
|
+
* compiler-emitted factory infers it from the snapshot composer, which is
|
|
17
|
+
* how `StoreSurface` recovers the precise type for `export type <store>`
|
|
18
|
+
* (Store §2.5). Defaults to `Record<string, unknown>` so hand-written /
|
|
19
|
+
* untyped callers keep working.
|
|
20
|
+
*/
|
|
21
|
+
getSnapshot: () => T;
|
|
22
|
+
/**
|
|
23
|
+
* Internal — fan out the current snapshot to all subscribers. Used by
|
|
24
|
+
* `StoreRegistry.replace` during HMR to wake old subscribers after a
|
|
25
|
+
* factory swap so their next render reads the new instance from the
|
|
26
|
+
* registry. User code (and compiler-emitted action bodies) call notify
|
|
27
|
+
* through the closure parameter passed to `createStoreInstance.build`,
|
|
28
|
+
* not via this field.
|
|
29
|
+
*/
|
|
30
|
+
notify: () => void;
|
|
31
|
+
}
|
|
32
|
+
/** Lifecycle kind that determines when a store's factory runs. */
|
|
33
|
+
export type StoreBindingKind = "export" | "session" | "route";
|
|
34
|
+
/**
|
|
35
|
+
* The shape a compiler-emitted store binding takes: a `{ name, kind, factory }`
|
|
36
|
+
* tuple the user passes to `configureStores`. The factory's `inputs` parameter
|
|
37
|
+
* is only meaningful for route stores (the router passes URL-derived values
|
|
38
|
+
* mapped via argumented `use storeX(param a, query b)`). Export and session
|
|
39
|
+
* stores ignore it.
|
|
40
|
+
*/
|
|
41
|
+
export interface StoreBinding {
|
|
42
|
+
name: string;
|
|
43
|
+
/**
|
|
44
|
+
* "export" / "session" → instantiate eagerly at `configureStores` time.
|
|
45
|
+
* "route" → register the factory but wait for `StoreRegistry.instantiate`
|
|
46
|
+
* to fire on route enter.
|
|
47
|
+
*/
|
|
48
|
+
kind: StoreBindingKind;
|
|
49
|
+
/**
|
|
50
|
+
* Wave 3 §2b — `route store ... for subtree "/path"`. When set, this store
|
|
51
|
+
* survives across every route whose pathname starts with the subtree path.
|
|
52
|
+
* `instantiate(name, ...)` is a NO-OP when an instance is already live;
|
|
53
|
+
* `dispose(name, { nextPathname })` is a no-op when `nextPathname` is still
|
|
54
|
+
* inside the subtree. Both checks isolate subtree-aware behaviour to
|
|
55
|
+
* stores that opt in via this field — non-subtree stores keep their
|
|
56
|
+
* existing per-route lifecycle.
|
|
57
|
+
*/
|
|
58
|
+
subtreePath?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Builds an instance. `inputs` is route-derived (argumented `inject store`).
|
|
61
|
+
* `restored` (route stores with `preserved state`) carries the values read
|
|
62
|
+
* back from `sessionStorage` — the compiler-emitted factory overwrites the
|
|
63
|
+
* matching `state` fields from it (Store §6). Both optional + ignored by
|
|
64
|
+
* stores that don't use them, so existing factories are unaffected.
|
|
65
|
+
*/
|
|
66
|
+
factory: (inputs?: Record<string, unknown>, restored?: Record<string, unknown>) => StoreInstance;
|
|
67
|
+
/**
|
|
68
|
+
* State field names listed under `preserved state X, Y` (Store §6) — the
|
|
69
|
+
* compiler emits this on the binding. The registry persists exactly these
|
|
70
|
+
* fields on route exit and reads them back into `restored` on the next enter.
|
|
71
|
+
*/
|
|
72
|
+
preservedFields?: readonly string[];
|
|
73
|
+
/**
|
|
74
|
+
* Stage E (Resource v1 §8) — compiler-emitted prefetch warmer. For a route
|
|
75
|
+
* store with `resource r(deps) => fn(deps)` declarations, the compiler emits
|
|
76
|
+
* a `warm(inputs, signal)` companion that calls `warmResource(name, deps,
|
|
77
|
+
* fn, signal)` once per resource (parallel `Promise.all`). Best-effort: the
|
|
78
|
+
* returned promise resolves silently on any failure (RES015 was deliberately
|
|
79
|
+
* not minted — failed warms are debug-only). Stores without resources omit
|
|
80
|
+
* this field; `StoreRegistry.warm` treats absence as a no-op.
|
|
81
|
+
*/
|
|
82
|
+
warm?: (inputs: Record<string, unknown> | undefined, signal: AbortSignal) => Promise<void>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The public surface type of a compiler-emitted store binding — its state,
|
|
86
|
+
* derived, and action members (inputs are excluded; they are factory
|
|
87
|
+
* parameters, not part of the snapshot). Pass 9 emits, alongside each store
|
|
88
|
+
* binding, `export type <name> = StoreSurface<typeof <name>>` (Store §2.5) so
|
|
89
|
+
* a consumer's `import type { <name> }` resolves the live surface through
|
|
90
|
+
* native module resolution.
|
|
91
|
+
*
|
|
92
|
+
* It stays in lockstep with the store body **by construction**: the type is
|
|
93
|
+
* inferred from the same factory the runtime executes, so it cannot drift the
|
|
94
|
+
* way a hand-maintained interface would. This is what lets store linkage
|
|
95
|
+
* survive package boundaries (the `.reactra.json` sidecar does not — see
|
|
96
|
+
* Compiler §6) and is the prerequisite for retiring the implicit sidecar-index
|
|
97
|
+
* name resolution (backlog 1a).
|
|
98
|
+
*/
|
|
99
|
+
export type StoreSurface<B extends {
|
|
100
|
+
factory: (...args: never[]) => StoreInstance;
|
|
101
|
+
}> = ReturnType<B["factory"]> extends StoreInstance<infer T> ? T : never;
|
|
102
|
+
/**
|
|
103
|
+
* Route-entry coordinates that key a preserved-state slot (Store §6 / Router
|
|
104
|
+
* §8.4). Two distinct entries to the same route (different params/query) get
|
|
105
|
+
* distinct slots, so e.g. `/checkout?u=1` and `/checkout?u=2` don't leak.
|
|
106
|
+
*/
|
|
107
|
+
export interface PreservedKey {
|
|
108
|
+
pathname: string;
|
|
109
|
+
params: Record<string, unknown>;
|
|
110
|
+
query: Record<string, unknown>;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Internal/diagnostics tier (Runtime §3) — register a store's restore closure.
|
|
114
|
+
* Compiler-emitted (Pass 9); last-wins per name. Mirrors `__listStoreBindings`.
|
|
115
|
+
* The closure returns the **count of state fields it actually wrote** so callers
|
|
116
|
+
* can tell a real re-drive from a no-op (shape-drift) one.
|
|
117
|
+
*/
|
|
118
|
+
export declare const __registerStoreRestore: (name: string, restore: (state: Record<string, unknown>) => number) => void;
|
|
119
|
+
/**
|
|
120
|
+
* Internal/diagnostics tier (Runtime §3) — drive a live store back to a past
|
|
121
|
+
* `state` (Devtools time-travel re-drive). Looks up the registered restore
|
|
122
|
+
* closure; when present, fires it (writes the matching state fields + notifies)
|
|
123
|
+
* and returns the **number of fields written** — 0 when no field in `state`
|
|
124
|
+
* matched a declared store `state` (e.g. a post-HMR shape drift), so the caller's
|
|
125
|
+
* "⟲ live" signal can't claim a no-op store moved. Returns 0 when no closure is
|
|
126
|
+
* registered (never instantiated / torn down) — a view-only degrade, never a throw.
|
|
127
|
+
*/
|
|
128
|
+
export declare const replayStoreState: (name: string, state: Record<string, unknown>) => number;
|
|
129
|
+
declare class StoreRegistryImpl {
|
|
130
|
+
private instances;
|
|
131
|
+
private factories;
|
|
132
|
+
private kinds;
|
|
133
|
+
private preservedFields;
|
|
134
|
+
private preserveWarned;
|
|
135
|
+
private warmers;
|
|
136
|
+
private subtreePaths;
|
|
137
|
+
/**
|
|
138
|
+
* Register a binding. Export / session stores instantiate immediately so a
|
|
139
|
+
* bare `use storeX` anywhere in the tree resolves. Route stores hold their
|
|
140
|
+
* factory until the router calls `instantiate(name, { inputs })` on enter.
|
|
141
|
+
*/
|
|
142
|
+
register: (binding: StoreBinding) => void;
|
|
143
|
+
/**
|
|
144
|
+
* Instantiate a route store with the inputs the router mapped from URL
|
|
145
|
+
* params/query. Idempotent within a single route lifetime — re-entering
|
|
146
|
+
* the same route disposes the previous instance first (router contract).
|
|
147
|
+
*/
|
|
148
|
+
instantiate: (name: string, opts?: {
|
|
149
|
+
inputs?: Record<string, unknown>;
|
|
150
|
+
preservedKey?: PreservedKey;
|
|
151
|
+
}) => void;
|
|
152
|
+
/**
|
|
153
|
+
* Persist a route store's `preserved state` fields to `sessionStorage` under
|
|
154
|
+
* the route-entry key (Store §6 / Router §8.4). Called by the route lifecycle
|
|
155
|
+
* immediately before `dispose` on exit. No-op for stores with no preserved
|
|
156
|
+
* fields or no live instance. Quota / serialization failures are swallowed
|
|
157
|
+
* with one `console.warn` per store per session.
|
|
158
|
+
*/
|
|
159
|
+
savePreservedState: (name: string, key: PreservedKey) => void;
|
|
160
|
+
/**
|
|
161
|
+
* Remove a live instance but keep its factory so the next route enter can
|
|
162
|
+
* rebuild it. Export / session stores live for the app lifetime and are
|
|
163
|
+
* never disposed by the router.
|
|
164
|
+
*
|
|
165
|
+
* Wave 3 §2b — for stores declared `route store ... for subtree "/path"`,
|
|
166
|
+
* pass the incoming route's pathname in `opts.nextPathname`. The dispose
|
|
167
|
+
* is SKIPPED when the destination is still inside the subtree (the next
|
|
168
|
+
* page's `instantiate` becomes a no-op too, so the same instance flows
|
|
169
|
+
* through the transition). Non-subtree stores ignore the option.
|
|
170
|
+
*/
|
|
171
|
+
dispose: (name: string, opts?: {
|
|
172
|
+
nextPathname?: string | null;
|
|
173
|
+
}) => void;
|
|
174
|
+
/**
|
|
175
|
+
* Look up an instance by name. Throws if the store hasn't been instantiated
|
|
176
|
+
* — either configureStores hasn't run, or it's a route store whose route
|
|
177
|
+
* isn't active.
|
|
178
|
+
*/
|
|
179
|
+
get: (name: string) => StoreInstance;
|
|
180
|
+
/** True if a live instance exists. Used by tests + router wiring. */
|
|
181
|
+
has: (name: string) => boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Internal tier (Runtime §1) — enumerate every registered binding for
|
|
184
|
+
* diagnostics (the Devtools spec §5 Stores tab). Read-only snapshots;
|
|
185
|
+
* never part of the public contract.
|
|
186
|
+
*/
|
|
187
|
+
__list: () => ReadonlyArray<{
|
|
188
|
+
name: string;
|
|
189
|
+
kind: StoreBindingKind;
|
|
190
|
+
instantiated: boolean;
|
|
191
|
+
preservedFields: readonly string[];
|
|
192
|
+
subtreePath?: string;
|
|
193
|
+
}>;
|
|
194
|
+
/**
|
|
195
|
+
* Resource v1 §8.2 — invoke a route store's compiler-emitted `warm(inputs,
|
|
196
|
+
* signal)` companion if present. Pre-fills the resource cache so the
|
|
197
|
+
* consumer mount that follows hits a fresh entry (Stage E hookup with
|
|
198
|
+
* `PrefetchRuntime`). Stores without resources omit the companion; this
|
|
199
|
+
* is a silent no-op. Best-effort: the returned promise resolves even on
|
|
200
|
+
* warmer failure (the warmer itself swallows; see `warmResource` in
|
|
201
|
+
* `@reactra/resource`).
|
|
202
|
+
*/
|
|
203
|
+
warm: (name: string, inputs: Record<string, unknown> | undefined, signal: AbortSignal) => Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* HMR hot-replace a binding (Compiler §5.3). Compiler-emitted
|
|
206
|
+
* `import.meta.hot.accept(...)` blocks in store-bearing files call this
|
|
207
|
+
* after the module re-evaluates so the new factory takes effect without
|
|
208
|
+
* a full page reload.
|
|
209
|
+
*
|
|
210
|
+
* Semantics:
|
|
211
|
+
* - "export" / "session" — build a fresh instance from the new factory
|
|
212
|
+
* and notify any old subscribers, so React re-renders consumers and
|
|
213
|
+
* their next `useReactraStore` read picks up the new instance from the
|
|
214
|
+
* registry. **State is intentionally lost** (new factory = fresh
|
|
215
|
+
* closure vars). Trade-off: the edited action body actually runs.
|
|
216
|
+
* - "route" — dispose the live instance; the router re-instantiates with
|
|
217
|
+
* inputs on the next route enter, which is the natural picking-up
|
|
218
|
+
* point for the new factory.
|
|
219
|
+
*
|
|
220
|
+
* Idempotent on a name that wasn't registered (treated as a fresh
|
|
221
|
+
* register) — this happens if the HMR fires before configureStores ran,
|
|
222
|
+
* which shouldn't occur in practice but isn't worth crashing over.
|
|
223
|
+
*/
|
|
224
|
+
replace: (binding: StoreBinding) => void;
|
|
225
|
+
/**
|
|
226
|
+
* Day 27 / `#5c-followup`: reconcile the registry against a new
|
|
227
|
+
* `STORES` array (typically the freshly-evaluated `newMod.STORES`
|
|
228
|
+
* from a HMR-accept callback on the generated route manifest).
|
|
229
|
+
*
|
|
230
|
+
* Semantics:
|
|
231
|
+
* - **Newcomers** (in `newStores`, not in the registry) → `register`.
|
|
232
|
+
* - **Departures** (in the registry, not in `newStores`) → drop
|
|
233
|
+
* factory + instance + kind. Subscribers that hold a stale
|
|
234
|
+
* instance reference keep that reference until React re-renders;
|
|
235
|
+
* their next `useReactraStore(name)` throws "store not active",
|
|
236
|
+
* which is the right signal — the user removed the store, so
|
|
237
|
+
* consumers should be next to go.
|
|
238
|
+
* - **Existing** (in both) → `replace` (so action-body edits to a
|
|
239
|
+
* re-emitted store take effect via the existing replace path).
|
|
240
|
+
*
|
|
241
|
+
* This is the manifest-level companion to per-file HMR (Day 16 /
|
|
242
|
+
* `#11`'s `import.meta.hot.accept` block emitted alongside store
|
|
243
|
+
* containers). The per-file path handles edits to a stable set of
|
|
244
|
+
* stores; this path handles add/remove of WHOLE store FILES.
|
|
245
|
+
*/
|
|
246
|
+
applyDelta: (newStores: readonly StoreBinding[]) => void;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The process-wide store registry singleton. The compiler emits imports of
|
|
250
|
+
* this and the `useReactraStore` hook below; user code typically doesn't
|
|
251
|
+
* touch it directly except through `configureStores`.
|
|
252
|
+
*/
|
|
253
|
+
export declare const StoreRegistry: StoreRegistryImpl;
|
|
254
|
+
/**
|
|
255
|
+
* Internal tier (Runtime §1) — registered-binding enumeration for
|
|
256
|
+
* diagnostics. Consumed by `@reactra/devtools` (Devtools spec §5).
|
|
257
|
+
*/
|
|
258
|
+
export declare const __listStoreBindings: () => ReadonlyArray<{
|
|
259
|
+
name: string;
|
|
260
|
+
kind: StoreBindingKind;
|
|
261
|
+
instantiated: boolean;
|
|
262
|
+
preservedFields: readonly string[];
|
|
263
|
+
subtreePath?: string;
|
|
264
|
+
}>;
|
|
265
|
+
/**
|
|
266
|
+
* Bootstrap call — invoked from `src/main.tsx` per Runtime v0 §5. Registers
|
|
267
|
+
* every store binding the app cares about. Order matters: `configureStores`
|
|
268
|
+
* must precede `configureRouter`.
|
|
269
|
+
*/
|
|
270
|
+
export declare const configureStores: (opts: {
|
|
271
|
+
stores: StoreBinding[];
|
|
272
|
+
}) => void;
|
|
273
|
+
/**
|
|
274
|
+
* React hook used by compiler-emitted `use storeX` bindings. Reads the live
|
|
275
|
+
* snapshot via `useSyncExternalStore`, so the component re-renders when the
|
|
276
|
+
* store calls `notify()`.
|
|
277
|
+
*
|
|
278
|
+
* The compiler destructures the returned object into the bare names the user
|
|
279
|
+
* wrote (state field, derived, action) — see Compiler v2 §7.3 / Store v4.1 §7.3.
|
|
280
|
+
*
|
|
281
|
+
* MVP simplification: snapshot is whole-store; per-field selection (Store
|
|
282
|
+
* §7.3 Selector Optimization) is a v1 improvement.
|
|
283
|
+
*/
|
|
284
|
+
export declare const useReactraStore: <T extends Record<string, unknown> = Record<string, unknown>>(name: string) => T;
|
|
285
|
+
/**
|
|
286
|
+
* A2 (Store §7.3 Selector Optimization) — per-FIELD store subscription. Backs
|
|
287
|
+
* the compiler-emitted field-selected binding `inject store X { a, b }`: the
|
|
288
|
+
* component re-renders ONLY when one of the selected SOURCE fields changes, not
|
|
289
|
+
* on every store write.
|
|
290
|
+
*
|
|
291
|
+
* The store's `notify()` still fans out to every listener (subscription is
|
|
292
|
+
* unchanged — C1/C4); the per-field bail-out happens in React via the
|
|
293
|
+
* `selector` + `isEqual` pair of `useSyncExternalStoreWithSelector`. A write to
|
|
294
|
+
* an UNselected field re-runs the selector but produces a selection that is
|
|
295
|
+
* shallow-equal to the previous one, so React skips the re-render.
|
|
296
|
+
*
|
|
297
|
+
* `fields` are the store's SOURCE keys (the names on the store surface), NOT the
|
|
298
|
+
* renamed locals — the compiler keeps the destructure rename in the emitted
|
|
299
|
+
* code; only the projected source keys flow here (Compiler §7.3 C3).
|
|
300
|
+
*
|
|
301
|
+
* The `K extends keyof T = keyof T` generic key-checks `fields` against the
|
|
302
|
+
* surface — a hand-caller typo (`["staus"]`) is a compile error either way,
|
|
303
|
+
* because `K` (whether explicit or defaulted to `keyof T`) constrains the array.
|
|
304
|
+
* Supplying `K` explicitly (`<T, "a" | "b">`) narrows the return to exactly the
|
|
305
|
+
* selected keys. The `= keyof T` default is load-bearing: the compiler emits a
|
|
306
|
+
* SINGLE type arg (`useReactraStoreFields<X>("X", ["a","b"])`), and TS requires
|
|
307
|
+
* every non-defaulted type param when any is given — the default lets that
|
|
308
|
+
* one-arg emitted form compile (it yields `Pick<T, keyof T>` = `T`, the pre-A2
|
|
309
|
+
* whole-surface type; the destructure only names selected fields, so this is
|
|
310
|
+
* harmless). Type-only — emission is byte-identical.
|
|
311
|
+
*
|
|
312
|
+
* **Reassignment invariant (Store §7.3):** the per-field bail-out compares each
|
|
313
|
+
* selected field by `Object.is`, so reactive state must be updated by
|
|
314
|
+
* REASSIGNMENT (`items = [...items, x]`), not in-place mutation
|
|
315
|
+
* (`items.push(x)`). An in-place mutation of a selected object/array field keeps
|
|
316
|
+
* the same reference → `isEqual` returns true → no re-render. (Whole-store /
|
|
317
|
+
* namespace bindings are unaffected — they re-render on any `notify()`.) This
|
|
318
|
+
* matches the framework's reassignment-based reactive model.
|
|
319
|
+
*
|
|
320
|
+
* **Version-cache invariant:** this relies on `createStoreInstance`'s
|
|
321
|
+
* version-cache — `getSnapshot` returns the SAME object reference until
|
|
322
|
+
* `notify()` bumps the version. Every state-changing path MUST call `notify()`
|
|
323
|
+
* (it does today, via every emitted setter); a write that skips it leaves the
|
|
324
|
+
* cached snapshot in place, the selector never re-runs, and the consumer never
|
|
325
|
+
* re-renders.
|
|
326
|
+
*
|
|
327
|
+
* @param name registered store name
|
|
328
|
+
* @param fields source-key names to select + subscribe to (re-render gate)
|
|
329
|
+
* @returns an object with exactly the selected source keys
|
|
330
|
+
*/
|
|
331
|
+
export declare const useReactraStoreFields: <T extends Record<string, unknown>, K extends keyof T = keyof T>(name: string, fields: readonly K[]) => Pick<T, K>;
|
|
332
|
+
/**
|
|
333
|
+
* Compiler-emitted factories call this to build a `StoreInstance`. The
|
|
334
|
+
* `build` callback receives a `notify` function the factory must call after
|
|
335
|
+
* every state mutation. The callback returns the snapshot composer — a fn
|
|
336
|
+
* that produces the current snapshot object on demand. The instance handles
|
|
337
|
+
* snapshot caching + listener fan-out.
|
|
338
|
+
*
|
|
339
|
+
* Shape used by emitted code (see Pass 9 codegen):
|
|
340
|
+
*
|
|
341
|
+
* // export store — no inputs
|
|
342
|
+
* createStoreInstance((notify) => {
|
|
343
|
+
* let count = 0
|
|
344
|
+
* const increment = () => { count = count + 1; notify() }
|
|
345
|
+
* return () => ({ count, increment }) // snapshot composer
|
|
346
|
+
* })
|
|
347
|
+
*
|
|
348
|
+
* // route store — inputs come from argumented `use storeX(param a, query b)`
|
|
349
|
+
* // via StoreRegistry.instantiate
|
|
350
|
+
* (inputs) => createStoreInstance((notify) => {
|
|
351
|
+
* const { customerId, returnTo } = inputs ?? {}
|
|
352
|
+
* ...
|
|
353
|
+
* })
|
|
354
|
+
*/
|
|
355
|
+
export declare const createStoreInstance: <T extends Record<string, unknown>>(build: (notify: () => void) => () => T) => StoreInstance<T>;
|
|
356
|
+
export {};
|
|
357
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
// @reactra/store — Store factories + StoreRegistry (Phase 1 MVP)
|
|
2
|
+
//
|
|
3
|
+
// Owner: reactra-store-spec.md (Spec 3.1 / Discussion v4.1)
|
|
4
|
+
//
|
|
5
|
+
// Phase 1 MVP surface — what's shipped today:
|
|
6
|
+
// StoreRegistry: register / instantiate / dispose / get / has
|
|
7
|
+
// configureStores({ stores })
|
|
8
|
+
// useReactraStore(name) — React hook backed by useSyncExternalStore
|
|
9
|
+
// createStoreInstance — helper consumed by compiler-emitted factories
|
|
10
|
+
//
|
|
11
|
+
// Day 10a addition — route-store lifecycle:
|
|
12
|
+
// StoreBinding.kind = "export" | "session" | "route" so the registry
|
|
13
|
+
// knows which factories to eagerly instantiate at configureStores time
|
|
14
|
+
// (export, session) vs which to defer until the router calls
|
|
15
|
+
// `instantiate(name, { inputs })` (route).
|
|
16
|
+
//
|
|
17
|
+
// Day 16 addition — HMR replace:
|
|
18
|
+
// StoreRegistry.replace(binding) — invoked from compiler-emitted
|
|
19
|
+
// `import.meta.hot.accept(...)` blocks in store-bearing files. Swaps
|
|
20
|
+
// the factory; for export/session also rebuilds the instance and
|
|
21
|
+
// notifies old subscribers so consumers re-render against the new
|
|
22
|
+
// instance. State is intentionally lost (new factory = fresh closure
|
|
23
|
+
// vars); the trade-off is that the action body edit actually takes
|
|
24
|
+
// effect. See Compiler §5.3 (HMR Boundary Per File).
|
|
25
|
+
//
|
|
26
|
+
// Preserved state (Store §6) — SHIPPED:
|
|
27
|
+
// StoreRegistry.savePreservedState(name, key) persists `preserved state`
|
|
28
|
+
// fields to sessionStorage on route exit; instantiate(name, { preservedKey })
|
|
29
|
+
// reads them back into the factory's `restored` arg on the next enter.
|
|
30
|
+
//
|
|
31
|
+
// Stage E (Resource v1 §8) — SHIPPED:
|
|
32
|
+
// StoreBinding.warm? + StoreRegistry.warm(name, inputs, signal) — prefetch
|
|
33
|
+
// resource warming. The runtime contract is live; the compiler-emitted
|
|
34
|
+
// warm(inputs, signal) companion (which calls warmResource per-resource
|
|
35
|
+
// from @reactra/resource) lands in a follow-up compiler stage. Hand-written
|
|
36
|
+
// bindings that set `warm` work today.
|
|
37
|
+
//
|
|
38
|
+
// Phase 1 deferred:
|
|
39
|
+
// per-field subscription (today: whole-store notification on any change)
|
|
40
|
+
// middleware (interceptAction / stateChanged / afterAction)
|
|
41
|
+
// resources / effects / mount / cleanup inside store bodies
|
|
42
|
+
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
|
43
|
+
// A2 (framework-review §A2 / Store §7.3): per-field store subscription. The shim
|
|
44
|
+
// import is Node-portable (no Bun API) and ships with React's own
|
|
45
|
+
// use-sync-external-store package. The selector + equality gate the RE-RENDER;
|
|
46
|
+
// the underlying `subscribe` is unchanged (notify() still fans to all listeners).
|
|
47
|
+
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector";
|
|
48
|
+
/** `sessionStorage` key: `reactra:preserved:<name>:<pathname>:<params>|<query>` (Store §6.4). */
|
|
49
|
+
/**
|
|
50
|
+
* Wave 3 §2b — true when `pathname` is inside the subtree rooted at
|
|
51
|
+
* `subtreePath`. Path-component atomic — `/checkout` matches `/checkout`
|
|
52
|
+
* and `/checkout/cart`, but NOT `/checkout-summary`. Trailing slashes on
|
|
53
|
+
* `subtreePath` are normalised away.
|
|
54
|
+
*/
|
|
55
|
+
const isInsideSubtree = (pathname, subtreePath) => {
|
|
56
|
+
const stripped = subtreePath.endsWith("/") ? subtreePath.slice(0, -1) : subtreePath;
|
|
57
|
+
if (pathname === stripped)
|
|
58
|
+
return true;
|
|
59
|
+
return pathname.startsWith(stripped + "/");
|
|
60
|
+
};
|
|
61
|
+
const preservedStorageKey = (name, k) => `reactra:preserved:${name}:${k.pathname}:${JSON.stringify(k.params)}|${JSON.stringify(k.query)}`;
|
|
62
|
+
/** Read + parse a preserved slot; `undefined` if absent / unavailable / malformed. */
|
|
63
|
+
const readPreserved = (key) => {
|
|
64
|
+
if (typeof sessionStorage === "undefined")
|
|
65
|
+
return undefined;
|
|
66
|
+
try {
|
|
67
|
+
const raw = sessionStorage.getItem(key);
|
|
68
|
+
if (raw == null)
|
|
69
|
+
return undefined;
|
|
70
|
+
const parsed = JSON.parse(raw);
|
|
71
|
+
return parsed != null && typeof parsed === "object"
|
|
72
|
+
? parsed
|
|
73
|
+
: undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
/** Write a serialized preserved slot. Throws on quota — `savePreservedState` swallows. */
|
|
80
|
+
const writePreserved = (key, json) => {
|
|
81
|
+
if (typeof sessionStorage === "undefined")
|
|
82
|
+
return;
|
|
83
|
+
sessionStorage.setItem(key, json);
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Module-private name-keyed registry of compiler-emitted store restore
|
|
87
|
+
* closures (Store §6 / Devtools time-travel). Pass 9 emits, inside each store
|
|
88
|
+
* factory, a call to `__registerStoreRestore(name, restore)` where `restore`
|
|
89
|
+
* writes the `state` fields of a `next` map into the factory's closure `let`s
|
|
90
|
+
* and calls the factory's `notify`. Last-wins per name (a re-instantiated
|
|
91
|
+
* factory overwrites the stale closure). Cleared on instance teardown so a
|
|
92
|
+
* `replayStoreState` against a torn-down store degrades to a view-only no-op.
|
|
93
|
+
*
|
|
94
|
+
* This is a plain module-level map — `@reactra/store` takes NO dependency edge
|
|
95
|
+
* toward devtools/replay (architect condition C2).
|
|
96
|
+
*/
|
|
97
|
+
const storeRestores = new Map();
|
|
98
|
+
/**
|
|
99
|
+
* Internal/diagnostics tier (Runtime §3) — register a store's restore closure.
|
|
100
|
+
* Compiler-emitted (Pass 9); last-wins per name. Mirrors `__listStoreBindings`.
|
|
101
|
+
* The closure returns the **count of state fields it actually wrote** so callers
|
|
102
|
+
* can tell a real re-drive from a no-op (shape-drift) one.
|
|
103
|
+
*/
|
|
104
|
+
export const __registerStoreRestore = (name, restore) => {
|
|
105
|
+
storeRestores.set(name, restore);
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Internal/diagnostics tier (Runtime §3) — drive a live store back to a past
|
|
109
|
+
* `state` (Devtools time-travel re-drive). Looks up the registered restore
|
|
110
|
+
* closure; when present, fires it (writes the matching state fields + notifies)
|
|
111
|
+
* and returns the **number of fields written** — 0 when no field in `state`
|
|
112
|
+
* matched a declared store `state` (e.g. a post-HMR shape drift), so the caller's
|
|
113
|
+
* "⟲ live" signal can't claim a no-op store moved. Returns 0 when no closure is
|
|
114
|
+
* registered (never instantiated / torn down) — a view-only degrade, never a throw.
|
|
115
|
+
*/
|
|
116
|
+
export const replayStoreState = (name, state) => {
|
|
117
|
+
const restore = storeRestores.get(name);
|
|
118
|
+
if (restore === undefined)
|
|
119
|
+
return 0;
|
|
120
|
+
return restore(state);
|
|
121
|
+
};
|
|
122
|
+
class StoreRegistryImpl {
|
|
123
|
+
instances = new Map();
|
|
124
|
+
factories = new Map();
|
|
125
|
+
kinds = new Map();
|
|
126
|
+
// `preserved state` field names per store (Store §6). Empty/absent → the
|
|
127
|
+
// save/restore paths are no-ops for that store.
|
|
128
|
+
preservedFields = new Map();
|
|
129
|
+
// One save-failure warning per store per session (quota / serialization).
|
|
130
|
+
preserveWarned = new Set();
|
|
131
|
+
// Stage E (Resource v1 §8) — per-store `warm(inputs, signal)` companions,
|
|
132
|
+
// populated by `register`/`replace`/`applyDelta` from the binding. Stores
|
|
133
|
+
// without resources have no entry; `warm()` no-ops in that case.
|
|
134
|
+
warmers = new Map();
|
|
135
|
+
// Wave 3 §2b — `for subtree "/path"` subtree paths per store. Drives the
|
|
136
|
+
// skip-instantiate + skip-dispose logic so a single instance survives
|
|
137
|
+
// across every page whose pathname starts with the subtree path. No
|
|
138
|
+
// entry → store is a regular per-route store (existing behaviour).
|
|
139
|
+
subtreePaths = new Map();
|
|
140
|
+
/**
|
|
141
|
+
* Register a binding. Export / session stores instantiate immediately so a
|
|
142
|
+
* bare `use storeX` anywhere in the tree resolves. Route stores hold their
|
|
143
|
+
* factory until the router calls `instantiate(name, { inputs })` on enter.
|
|
144
|
+
*/
|
|
145
|
+
register = (binding) => {
|
|
146
|
+
if (this.factories.has(binding.name)) {
|
|
147
|
+
throw new Error(`[reactra:store] S001: store "${binding.name}" is already registered`);
|
|
148
|
+
}
|
|
149
|
+
this.factories.set(binding.name, binding.factory);
|
|
150
|
+
this.kinds.set(binding.name, binding.kind);
|
|
151
|
+
if (binding.preservedFields && binding.preservedFields.length > 0) {
|
|
152
|
+
this.preservedFields.set(binding.name, binding.preservedFields);
|
|
153
|
+
}
|
|
154
|
+
if (binding.warm !== undefined) {
|
|
155
|
+
this.warmers.set(binding.name, binding.warm);
|
|
156
|
+
}
|
|
157
|
+
if (binding.subtreePath !== undefined && binding.subtreePath.length > 0) {
|
|
158
|
+
this.subtreePaths.set(binding.name, binding.subtreePath);
|
|
159
|
+
}
|
|
160
|
+
if (binding.kind === "export" || binding.kind === "session") {
|
|
161
|
+
this.instances.set(binding.name, binding.factory());
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Instantiate a route store with the inputs the router mapped from URL
|
|
166
|
+
* params/query. Idempotent within a single route lifetime — re-entering
|
|
167
|
+
* the same route disposes the previous instance first (router contract).
|
|
168
|
+
*/
|
|
169
|
+
instantiate = (name, opts = {}) => {
|
|
170
|
+
const factory = this.factories.get(name);
|
|
171
|
+
if (!factory) {
|
|
172
|
+
throw new Error(`[reactra:store] cannot instantiate "${name}" — no factory registered`);
|
|
173
|
+
}
|
|
174
|
+
// Wave 3 §2b — for subtree stores, REUSE the existing instance when one
|
|
175
|
+
// is already alive (the previous page in the subtree built it; the new
|
|
176
|
+
// page joins the same lifecycle). Inputs from the new page are
|
|
177
|
+
// ignored — the entry route's inputs are what defined the store, per
|
|
178
|
+
// Router §4.6 "argumented form passes inputs at subtree entry; bare
|
|
179
|
+
// form everywhere else in the subtree". Non-subtree stores keep the
|
|
180
|
+
// existing always-rebuild behaviour.
|
|
181
|
+
if (this.subtreePaths.has(name) && this.instances.has(name)) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Preserved-state restore (Store §6): if this route store opted into
|
|
185
|
+
// `preserved state` AND the router passed the entry key, read the persisted
|
|
186
|
+
// values back and hand them to the factory, which overwrites the matching
|
|
187
|
+
// `state` fields before the snapshot composer runs — so the restored values
|
|
188
|
+
// are visible on first render (before React subscribes). No-op for stores
|
|
189
|
+
// with no preserved fields or when the entry has nothing stored.
|
|
190
|
+
const fields = this.preservedFields.get(name);
|
|
191
|
+
const restored = fields && fields.length > 0 && opts.preservedKey
|
|
192
|
+
? readPreserved(preservedStorageKey(name, opts.preservedKey))
|
|
193
|
+
: undefined;
|
|
194
|
+
this.instances.set(name, factory(opts.inputs, restored));
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Persist a route store's `preserved state` fields to `sessionStorage` under
|
|
198
|
+
* the route-entry key (Store §6 / Router §8.4). Called by the route lifecycle
|
|
199
|
+
* immediately before `dispose` on exit. No-op for stores with no preserved
|
|
200
|
+
* fields or no live instance. Quota / serialization failures are swallowed
|
|
201
|
+
* with one `console.warn` per store per session.
|
|
202
|
+
*/
|
|
203
|
+
savePreservedState = (name, key) => {
|
|
204
|
+
const fields = this.preservedFields.get(name);
|
|
205
|
+
if (!fields || fields.length === 0)
|
|
206
|
+
return;
|
|
207
|
+
const inst = this.instances.get(name);
|
|
208
|
+
if (!inst)
|
|
209
|
+
return;
|
|
210
|
+
try {
|
|
211
|
+
const snap = inst.getSnapshot();
|
|
212
|
+
const out = {};
|
|
213
|
+
for (const f of fields)
|
|
214
|
+
out[f] = snap[f];
|
|
215
|
+
writePreserved(preservedStorageKey(name, key), JSON.stringify(out));
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
if (!this.preserveWarned.has(name)) {
|
|
219
|
+
this.preserveWarned.add(name);
|
|
220
|
+
console.warn(`[reactra:store] preserved-state save failed for "${name}"`, err);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Remove a live instance but keep its factory so the next route enter can
|
|
226
|
+
* rebuild it. Export / session stores live for the app lifetime and are
|
|
227
|
+
* never disposed by the router.
|
|
228
|
+
*
|
|
229
|
+
* Wave 3 §2b — for stores declared `route store ... for subtree "/path"`,
|
|
230
|
+
* pass the incoming route's pathname in `opts.nextPathname`. The dispose
|
|
231
|
+
* is SKIPPED when the destination is still inside the subtree (the next
|
|
232
|
+
* page's `instantiate` becomes a no-op too, so the same instance flows
|
|
233
|
+
* through the transition). Non-subtree stores ignore the option.
|
|
234
|
+
*/
|
|
235
|
+
dispose = (name, opts = {}) => {
|
|
236
|
+
const subtreePath = this.subtreePaths.get(name);
|
|
237
|
+
if (subtreePath !== undefined &&
|
|
238
|
+
typeof opts.nextPathname === "string" &&
|
|
239
|
+
isInsideSubtree(opts.nextPathname, subtreePath)) {
|
|
240
|
+
// Still inside the subtree — keep the instance alive for the next page.
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
this.instances.delete(name);
|
|
244
|
+
// C7: the torn-down instance's restore closure points at dead closure vars;
|
|
245
|
+
// drop it so a stale `replayStoreState(name, ...)` degrades to a view-only
|
|
246
|
+
// no-op (returns 0) instead of writing into the old closure.
|
|
247
|
+
storeRestores.delete(name);
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Look up an instance by name. Throws if the store hasn't been instantiated
|
|
251
|
+
* — either configureStores hasn't run, or it's a route store whose route
|
|
252
|
+
* isn't active.
|
|
253
|
+
*/
|
|
254
|
+
get = (name) => {
|
|
255
|
+
const inst = this.instances.get(name);
|
|
256
|
+
if (!inst) {
|
|
257
|
+
throw new Error(`[reactra:store] store "${name}" is not active — either configureStores() didn't register it, or it's a route store whose route isn't entered`);
|
|
258
|
+
}
|
|
259
|
+
return inst;
|
|
260
|
+
};
|
|
261
|
+
/** True if a live instance exists. Used by tests + router wiring. */
|
|
262
|
+
has = (name) => this.instances.has(name);
|
|
263
|
+
/**
|
|
264
|
+
* Internal tier (Runtime §1) — enumerate every registered binding for
|
|
265
|
+
* diagnostics (the Devtools spec §5 Stores tab). Read-only snapshots;
|
|
266
|
+
* never part of the public contract.
|
|
267
|
+
*/
|
|
268
|
+
__list = () => [...this.factories.keys()].map((name) => ({
|
|
269
|
+
name,
|
|
270
|
+
// kinds is populated in lockstep with factories by register/replace.
|
|
271
|
+
kind: this.kinds.get(name),
|
|
272
|
+
instantiated: this.instances.has(name),
|
|
273
|
+
preservedFields: this.preservedFields.get(name) ?? [],
|
|
274
|
+
...(this.subtreePaths.has(name) ? { subtreePath: this.subtreePaths.get(name) } : {}),
|
|
275
|
+
}));
|
|
276
|
+
/**
|
|
277
|
+
* Resource v1 §8.2 — invoke a route store's compiler-emitted `warm(inputs,
|
|
278
|
+
* signal)` companion if present. Pre-fills the resource cache so the
|
|
279
|
+
* consumer mount that follows hits a fresh entry (Stage E hookup with
|
|
280
|
+
* `PrefetchRuntime`). Stores without resources omit the companion; this
|
|
281
|
+
* is a silent no-op. Best-effort: the returned promise resolves even on
|
|
282
|
+
* warmer failure (the warmer itself swallows; see `warmResource` in
|
|
283
|
+
* `@reactra/resource`).
|
|
284
|
+
*/
|
|
285
|
+
warm = (name, inputs, signal) => {
|
|
286
|
+
const w = this.warmers.get(name);
|
|
287
|
+
if (w === undefined)
|
|
288
|
+
return Promise.resolve();
|
|
289
|
+
return w(inputs, signal).catch(() => {
|
|
290
|
+
// Defensive — the warmer itself is documented best-effort, but a
|
|
291
|
+
// hand-written binding that rejects must not break the route prefetch.
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* HMR hot-replace a binding (Compiler §5.3). Compiler-emitted
|
|
296
|
+
* `import.meta.hot.accept(...)` blocks in store-bearing files call this
|
|
297
|
+
* after the module re-evaluates so the new factory takes effect without
|
|
298
|
+
* a full page reload.
|
|
299
|
+
*
|
|
300
|
+
* Semantics:
|
|
301
|
+
* - "export" / "session" — build a fresh instance from the new factory
|
|
302
|
+
* and notify any old subscribers, so React re-renders consumers and
|
|
303
|
+
* their next `useReactraStore` read picks up the new instance from the
|
|
304
|
+
* registry. **State is intentionally lost** (new factory = fresh
|
|
305
|
+
* closure vars). Trade-off: the edited action body actually runs.
|
|
306
|
+
* - "route" — dispose the live instance; the router re-instantiates with
|
|
307
|
+
* inputs on the next route enter, which is the natural picking-up
|
|
308
|
+
* point for the new factory.
|
|
309
|
+
*
|
|
310
|
+
* Idempotent on a name that wasn't registered (treated as a fresh
|
|
311
|
+
* register) — this happens if the HMR fires before configureStores ran,
|
|
312
|
+
* which shouldn't occur in practice but isn't worth crashing over.
|
|
313
|
+
*/
|
|
314
|
+
replace = (binding) => {
|
|
315
|
+
const oldInst = this.instances.get(binding.name);
|
|
316
|
+
// C7 (HMR): drop the stale restore closure before the new factory runs.
|
|
317
|
+
// For export/session the rebuild below re-emits `__registerStoreRestore`
|
|
318
|
+
// (last-wins); clearing first guarantees a factory edited to drop all
|
|
319
|
+
// `state` fields leaves no stale closure pointing at dead vars. For route
|
|
320
|
+
// stores the live instance is kept, but its closure was rebuilt on the
|
|
321
|
+
// last instantiate — a mid-scrub HMR tolerating the swap drops travel
|
|
322
|
+
// state with no throw (the next instantiate re-registers).
|
|
323
|
+
storeRestores.delete(binding.name);
|
|
324
|
+
this.factories.set(binding.name, binding.factory);
|
|
325
|
+
this.kinds.set(binding.name, binding.kind);
|
|
326
|
+
if (binding.preservedFields && binding.preservedFields.length > 0) {
|
|
327
|
+
this.preservedFields.set(binding.name, binding.preservedFields);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
this.preservedFields.delete(binding.name);
|
|
331
|
+
}
|
|
332
|
+
if (binding.warm !== undefined) {
|
|
333
|
+
this.warmers.set(binding.name, binding.warm);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
this.warmers.delete(binding.name);
|
|
337
|
+
}
|
|
338
|
+
if (binding.kind === "route") {
|
|
339
|
+
// Day 18 / `#18b`: keep the live instance. The router naturally
|
|
340
|
+
// re-instantiates on the next route enter, which is the right
|
|
341
|
+
// pickup point for the new factory. Disposing here would throw
|
|
342
|
+
// "store not active" in any mounted consumer the moment we
|
|
343
|
+
// achieve HMR for a file with a live route store.
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
this.instances.set(binding.name, binding.factory());
|
|
347
|
+
if (oldInst)
|
|
348
|
+
oldInst.notify();
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* Day 27 / `#5c-followup`: reconcile the registry against a new
|
|
352
|
+
* `STORES` array (typically the freshly-evaluated `newMod.STORES`
|
|
353
|
+
* from a HMR-accept callback on the generated route manifest).
|
|
354
|
+
*
|
|
355
|
+
* Semantics:
|
|
356
|
+
* - **Newcomers** (in `newStores`, not in the registry) → `register`.
|
|
357
|
+
* - **Departures** (in the registry, not in `newStores`) → drop
|
|
358
|
+
* factory + instance + kind. Subscribers that hold a stale
|
|
359
|
+
* instance reference keep that reference until React re-renders;
|
|
360
|
+
* their next `useReactraStore(name)` throws "store not active",
|
|
361
|
+
* which is the right signal — the user removed the store, so
|
|
362
|
+
* consumers should be next to go.
|
|
363
|
+
* - **Existing** (in both) → `replace` (so action-body edits to a
|
|
364
|
+
* re-emitted store take effect via the existing replace path).
|
|
365
|
+
*
|
|
366
|
+
* This is the manifest-level companion to per-file HMR (Day 16 /
|
|
367
|
+
* `#11`'s `import.meta.hot.accept` block emitted alongside store
|
|
368
|
+
* containers). The per-file path handles edits to a stable set of
|
|
369
|
+
* stores; this path handles add/remove of WHOLE store FILES.
|
|
370
|
+
*/
|
|
371
|
+
applyDelta = (newStores) => {
|
|
372
|
+
const newNames = new Set(newStores.map((s) => s.name));
|
|
373
|
+
// Departures first — drop the old factories+instances before we
|
|
374
|
+
// potentially register a same-named newcomer (defensive; the loops
|
|
375
|
+
// below shouldn't overlap on names but the order keeps it sane).
|
|
376
|
+
for (const name of [...this.factories.keys()]) {
|
|
377
|
+
if (!newNames.has(name)) {
|
|
378
|
+
this.instances.delete(name);
|
|
379
|
+
this.factories.delete(name);
|
|
380
|
+
this.kinds.delete(name);
|
|
381
|
+
this.preservedFields.delete(name);
|
|
382
|
+
this.warmers.delete(name);
|
|
383
|
+
// C7: a departed store's restore closure must not survive the delta.
|
|
384
|
+
storeRestores.delete(name);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// Newcomers + existing — replace handles both (idempotent on
|
|
388
|
+
// an unknown name; see its own docstring).
|
|
389
|
+
for (const binding of newStores) {
|
|
390
|
+
if (this.factories.has(binding.name)) {
|
|
391
|
+
this.replace(binding);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
this.register(binding);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* The process-wide store registry singleton. The compiler emits imports of
|
|
401
|
+
* this and the `useReactraStore` hook below; user code typically doesn't
|
|
402
|
+
* touch it directly except through `configureStores`.
|
|
403
|
+
*/
|
|
404
|
+
export const StoreRegistry = new StoreRegistryImpl();
|
|
405
|
+
/**
|
|
406
|
+
* Internal tier (Runtime §1) — registered-binding enumeration for
|
|
407
|
+
* diagnostics. Consumed by `@reactra/devtools` (Devtools spec §5).
|
|
408
|
+
*/
|
|
409
|
+
export const __listStoreBindings = StoreRegistry.__list;
|
|
410
|
+
/**
|
|
411
|
+
* Bootstrap call — invoked from `src/main.tsx` per Runtime v0 §5. Registers
|
|
412
|
+
* every store binding the app cares about. Order matters: `configureStores`
|
|
413
|
+
* must precede `configureRouter`.
|
|
414
|
+
*/
|
|
415
|
+
export const configureStores = (opts) => {
|
|
416
|
+
for (const binding of opts.stores)
|
|
417
|
+
StoreRegistry.register(binding);
|
|
418
|
+
};
|
|
419
|
+
/**
|
|
420
|
+
* React hook used by compiler-emitted `use storeX` bindings. Reads the live
|
|
421
|
+
* snapshot via `useSyncExternalStore`, so the component re-renders when the
|
|
422
|
+
* store calls `notify()`.
|
|
423
|
+
*
|
|
424
|
+
* The compiler destructures the returned object into the bare names the user
|
|
425
|
+
* wrote (state field, derived, action) — see Compiler v2 §7.3 / Store v4.1 §7.3.
|
|
426
|
+
*
|
|
427
|
+
* MVP simplification: snapshot is whole-store; per-field selection (Store
|
|
428
|
+
* §7.3 Selector Optimization) is a v1 improvement.
|
|
429
|
+
*/
|
|
430
|
+
export const useReactraStore = (name) => {
|
|
431
|
+
const inst = StoreRegistry.get(name);
|
|
432
|
+
// useCallback so React sees stable subscribe/getSnapshot references and
|
|
433
|
+
// doesn't tear them down between renders.
|
|
434
|
+
const subscribe = useCallback((onChange) => inst.subscribe(onChange), [inst]);
|
|
435
|
+
const getSnapshot = useCallback(() => inst.getSnapshot(), [inst]);
|
|
436
|
+
return useSyncExternalStore(subscribe, getSnapshot);
|
|
437
|
+
};
|
|
438
|
+
/**
|
|
439
|
+
* A2 (Store §7.3 Selector Optimization) — per-FIELD store subscription. Backs
|
|
440
|
+
* the compiler-emitted field-selected binding `inject store X { a, b }`: the
|
|
441
|
+
* component re-renders ONLY when one of the selected SOURCE fields changes, not
|
|
442
|
+
* on every store write.
|
|
443
|
+
*
|
|
444
|
+
* The store's `notify()` still fans out to every listener (subscription is
|
|
445
|
+
* unchanged — C1/C4); the per-field bail-out happens in React via the
|
|
446
|
+
* `selector` + `isEqual` pair of `useSyncExternalStoreWithSelector`. A write to
|
|
447
|
+
* an UNselected field re-runs the selector but produces a selection that is
|
|
448
|
+
* shallow-equal to the previous one, so React skips the re-render.
|
|
449
|
+
*
|
|
450
|
+
* `fields` are the store's SOURCE keys (the names on the store surface), NOT the
|
|
451
|
+
* renamed locals — the compiler keeps the destructure rename in the emitted
|
|
452
|
+
* code; only the projected source keys flow here (Compiler §7.3 C3).
|
|
453
|
+
*
|
|
454
|
+
* The `K extends keyof T = keyof T` generic key-checks `fields` against the
|
|
455
|
+
* surface — a hand-caller typo (`["staus"]`) is a compile error either way,
|
|
456
|
+
* because `K` (whether explicit or defaulted to `keyof T`) constrains the array.
|
|
457
|
+
* Supplying `K` explicitly (`<T, "a" | "b">`) narrows the return to exactly the
|
|
458
|
+
* selected keys. The `= keyof T` default is load-bearing: the compiler emits a
|
|
459
|
+
* SINGLE type arg (`useReactraStoreFields<X>("X", ["a","b"])`), and TS requires
|
|
460
|
+
* every non-defaulted type param when any is given — the default lets that
|
|
461
|
+
* one-arg emitted form compile (it yields `Pick<T, keyof T>` = `T`, the pre-A2
|
|
462
|
+
* whole-surface type; the destructure only names selected fields, so this is
|
|
463
|
+
* harmless). Type-only — emission is byte-identical.
|
|
464
|
+
*
|
|
465
|
+
* **Reassignment invariant (Store §7.3):** the per-field bail-out compares each
|
|
466
|
+
* selected field by `Object.is`, so reactive state must be updated by
|
|
467
|
+
* REASSIGNMENT (`items = [...items, x]`), not in-place mutation
|
|
468
|
+
* (`items.push(x)`). An in-place mutation of a selected object/array field keeps
|
|
469
|
+
* the same reference → `isEqual` returns true → no re-render. (Whole-store /
|
|
470
|
+
* namespace bindings are unaffected — they re-render on any `notify()`.) This
|
|
471
|
+
* matches the framework's reassignment-based reactive model.
|
|
472
|
+
*
|
|
473
|
+
* **Version-cache invariant:** this relies on `createStoreInstance`'s
|
|
474
|
+
* version-cache — `getSnapshot` returns the SAME object reference until
|
|
475
|
+
* `notify()` bumps the version. Every state-changing path MUST call `notify()`
|
|
476
|
+
* (it does today, via every emitted setter); a write that skips it leaves the
|
|
477
|
+
* cached snapshot in place, the selector never re-runs, and the consumer never
|
|
478
|
+
* re-renders.
|
|
479
|
+
*
|
|
480
|
+
* @param name registered store name
|
|
481
|
+
* @param fields source-key names to select + subscribe to (re-render gate)
|
|
482
|
+
* @returns an object with exactly the selected source keys
|
|
483
|
+
*/
|
|
484
|
+
export const useReactraStoreFields = (name, fields) => {
|
|
485
|
+
const inst = StoreRegistry.get(name);
|
|
486
|
+
const subscribe = useCallback((onChange) => inst.subscribe(onChange), [inst]);
|
|
487
|
+
const getSnapshot = useCallback(() => inst.getSnapshot(), [inst]);
|
|
488
|
+
// Stable selector + equality keyed on the field list. The selector projects
|
|
489
|
+
// the selected source keys; `isEqual` is a shallow Object.is comparison over
|
|
490
|
+
// exactly those keys — the per-field bail-out. We do NOT allocate the selected
|
|
491
|
+
// object outside the selector (the selector's own result is what
|
|
492
|
+
// with-selector memoizes against the previous selection via `isEqual`).
|
|
493
|
+
const key = fields.join(",");
|
|
494
|
+
const { selector, isEqual } = useMemo(() => {
|
|
495
|
+
const sel = (snap) => {
|
|
496
|
+
const out = {};
|
|
497
|
+
for (const f of fields)
|
|
498
|
+
out[f] = snap[f];
|
|
499
|
+
return out;
|
|
500
|
+
};
|
|
501
|
+
const eq = (a, b) => {
|
|
502
|
+
for (const f of fields) {
|
|
503
|
+
if (!Object.is(a[f], b[f])) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return true;
|
|
508
|
+
};
|
|
509
|
+
return { selector: sel, isEqual: eq };
|
|
510
|
+
// `key` is the stable identity of `fields`; recompute only when it changes.
|
|
511
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
512
|
+
}, [key]);
|
|
513
|
+
return useSyncExternalStoreWithSelector(subscribe, getSnapshot,
|
|
514
|
+
// getServerSnapshot: same source as the client snapshot. Correct for CSR;
|
|
515
|
+
// when SSR lands this must return a request-scoped snapshot or hydration
|
|
516
|
+
// will mismatch (ref specs/adr/0001-ssr-scoping.md — singleton registries
|
|
517
|
+
// are the client-only boundary).
|
|
518
|
+
getSnapshot, selector, isEqual);
|
|
519
|
+
};
|
|
520
|
+
/**
|
|
521
|
+
* Compiler-emitted factories call this to build a `StoreInstance`. The
|
|
522
|
+
* `build` callback receives a `notify` function the factory must call after
|
|
523
|
+
* every state mutation. The callback returns the snapshot composer — a fn
|
|
524
|
+
* that produces the current snapshot object on demand. The instance handles
|
|
525
|
+
* snapshot caching + listener fan-out.
|
|
526
|
+
*
|
|
527
|
+
* Shape used by emitted code (see Pass 9 codegen):
|
|
528
|
+
*
|
|
529
|
+
* // export store — no inputs
|
|
530
|
+
* createStoreInstance((notify) => {
|
|
531
|
+
* let count = 0
|
|
532
|
+
* const increment = () => { count = count + 1; notify() }
|
|
533
|
+
* return () => ({ count, increment }) // snapshot composer
|
|
534
|
+
* })
|
|
535
|
+
*
|
|
536
|
+
* // route store — inputs come from argumented `use storeX(param a, query b)`
|
|
537
|
+
* // via StoreRegistry.instantiate
|
|
538
|
+
* (inputs) => createStoreInstance((notify) => {
|
|
539
|
+
* const { customerId, returnTo } = inputs ?? {}
|
|
540
|
+
* ...
|
|
541
|
+
* })
|
|
542
|
+
*/
|
|
543
|
+
export const createStoreInstance = (build) => {
|
|
544
|
+
const listeners = new Set();
|
|
545
|
+
let version = 0;
|
|
546
|
+
let cachedSnapshot = null;
|
|
547
|
+
let cachedVersion = -1;
|
|
548
|
+
const notify = () => {
|
|
549
|
+
version++;
|
|
550
|
+
cachedSnapshot = null;
|
|
551
|
+
for (const l of listeners)
|
|
552
|
+
l();
|
|
553
|
+
};
|
|
554
|
+
const compose = build(notify);
|
|
555
|
+
return {
|
|
556
|
+
subscribe: (onChange) => {
|
|
557
|
+
listeners.add(onChange);
|
|
558
|
+
return () => listeners.delete(onChange);
|
|
559
|
+
},
|
|
560
|
+
getSnapshot: () => {
|
|
561
|
+
if (cachedVersion !== version || cachedSnapshot === null) {
|
|
562
|
+
cachedSnapshot = compose();
|
|
563
|
+
cachedVersion = version;
|
|
564
|
+
}
|
|
565
|
+
return cachedSnapshot;
|
|
566
|
+
},
|
|
567
|
+
notify,
|
|
568
|
+
};
|
|
569
|
+
};
|
|
570
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reactra/store",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"use-sync-external-store": "^1.5.0"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"react": "^19.2.0"
|
|
17
|
+
},
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public",
|
|
24
|
+
"tag": "alpha",
|
|
25
|
+
"provenance": false
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/akhilshastri/reactra.git",
|
|
30
|
+
"directory": "packages/store"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://reactra-docs.vercel.app",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=22.18"
|
|
36
|
+
},
|
|
37
|
+
"sideEffects": false,
|
|
38
|
+
"description": "Reactra store runtime — scoped, fine-grained, per-field-subscription state for Reactra apps."
|
|
39
|
+
}
|