@yoltra/core 0.6.0 → 0.8.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/README.es.md +443 -148
- package/README.md +207 -84
- package/dist/types/index.d.ts +2 -1
- package/dist/types/persistence/persist.d.ts +2 -2
- package/dist/types/store/Store.d.ts +373 -66
- package/dist/types/store/fingerprint.d.ts +62 -0
- package/dist/types/store/matching.d.ts +49 -0
- package/dist/types/store/paths.d.ts +39 -0
- package/dist/types/store/performCall.d.ts +15 -0
- package/dist/types/store/rejection.d.ts +2 -2
- package/dist/types/types.d.ts +528 -18
- package/dist/yoltra.cjs +3 -8
- package/dist/yoltra.cjs.map +1 -1
- package/dist/yoltra.mjs +2133 -1385
- package/dist/yoltra.mjs.map +1 -1
- package/dist/yoltra.umd.js +3 -8
- package/dist/yoltra.umd.js.map +1 -1
- package/package.json +6 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Event, EventMapBase, EventKey, EventUnion, Change, DeepReadonly, EffectSpec, EventMeta, MiddlewareInput, ReducersMapAny, ReducerSpec, StateFromReducers, StoreInstance, StoreSpec, Unsubscribe, EMFromReducersStrict, Emit, EmitOptions, EmitResult, ConnectOptions, InstrumentationObserver, CascadeInfo, EventPhase, NarrowedEventHandler, When } from '../types.js';
|
|
1
|
+
import { Event, EventMapBase, EventKey, EventUnion, Change, DeepReadonly, EffectSpec, EventMeta, MiddlewareInput, ReducersMapAny, ReducerSpec, StateFromReducers, StoreInstance, StoreSpec, Unsubscribe, EMFromReducersStrict, Emit, EmitOptions, EmitResult, ConnectOptions, InstrumentationObserver, CascadeInfo, EventPhase, Origin, RegistrationObserver, ReplaceScope, NotifiedPhase, NarrowedEventHandler, When } from '../types.js';
|
|
2
2
|
import { CallHandle, CallOptions } from './call.js';
|
|
3
3
|
import { Rejection } from './rejection.js';
|
|
4
4
|
export declare class Store<EM extends EventMapBase, R extends string, S extends Record<R, any>> implements StoreInstance<R, S, EM> {
|
|
@@ -11,7 +11,9 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
11
11
|
/**
|
|
12
12
|
* Registered middleware pipeline (run **before** reducers).
|
|
13
13
|
* Stores either raw functions (legacy) or MiddlewareSpec objects.
|
|
14
|
-
*
|
|
14
|
+
*
|
|
15
|
+
* Only an explicit `false` stops propagation. Returning nothing allows the event, so
|
|
16
|
+
* middleware that only logs or measures needs no `return` at all.
|
|
15
17
|
*
|
|
16
18
|
* @internal
|
|
17
19
|
*/
|
|
@@ -95,6 +97,17 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
95
97
|
*/
|
|
96
98
|
private readonly writtenEventSubscribers;
|
|
97
99
|
private readonly allEventSubscribers;
|
|
100
|
+
/**
|
|
101
|
+
* True while a devtools time-travel is applying a snapshot or replaying events.
|
|
102
|
+
*
|
|
103
|
+
* @remarks
|
|
104
|
+
* Saved and restored rather than set and cleared to `false`: `__replayEvents` calls
|
|
105
|
+
* `__applyExternalState` as its first step, so clearing on the inner call's way out would
|
|
106
|
+
* unset the flag for the entire event loop that follows it.
|
|
107
|
+
*
|
|
108
|
+
* @internal
|
|
109
|
+
*/
|
|
110
|
+
private replaying;
|
|
98
111
|
/**
|
|
99
112
|
* Track reducerBus unsubs per slice for HMR/register/unregister.
|
|
100
113
|
*
|
|
@@ -109,6 +122,70 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
109
122
|
* @internal
|
|
110
123
|
*/
|
|
111
124
|
private readonly patternReducers;
|
|
125
|
+
/**
|
|
126
|
+
* Where each mounted slice came from. See {@link Origin}.
|
|
127
|
+
*
|
|
128
|
+
* @remarks
|
|
129
|
+
* This is what makes `replace*` mean "replace mine" rather than "replace everything". It
|
|
130
|
+
* is written by `mountSlice` and never by a caller.
|
|
131
|
+
*
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
134
|
+
private readonly sliceOrigin;
|
|
135
|
+
/**
|
|
136
|
+
* Who claims each dynamically mounted slice, for introspection only.
|
|
137
|
+
*
|
|
138
|
+
* @remarks
|
|
139
|
+
* Surfaced in `__devtoolsIntrospect()` and named in the collision error. **Never read by
|
|
140
|
+
* `replace*`.** Correctness comes from {@link Origin}, which nobody has to remember to
|
|
141
|
+
* pass; if preservation depended on this string, forgetting it would silently delete a
|
|
142
|
+
* library's state.
|
|
143
|
+
*
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
private readonly sliceOwner;
|
|
147
|
+
/**
|
|
148
|
+
* Slices unmounted by their owner, for a development-time diagnostic.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* Decoration re-types the store, and after a disposer runs the widened type still claims
|
|
152
|
+
* a slice that is gone. Reading it would hand a component `undefined` from a type that
|
|
153
|
+
* promised a value, which is the silent failure this whole feature exists to remove.
|
|
154
|
+
* Populated only for `dynamic` and `internal` slices: a `spec` slice removed by a
|
|
155
|
+
* `replace*` was not promised by anyone's widened type.
|
|
156
|
+
*
|
|
157
|
+
* Bounded, because a long development session that mounts and disposes repeatedly would
|
|
158
|
+
* otherwise accumulate an entry per cycle forever. The oldest is dropped: the diagnostic
|
|
159
|
+
* exists for a slice someone has just stopped using, and a name disposed hundreds of
|
|
160
|
+
* mounts ago is not the one being read by mistake. Maps to the owner, or `undefined`
|
|
161
|
+
* when the library did not name itself.
|
|
162
|
+
*
|
|
163
|
+
* @internal
|
|
164
|
+
*/
|
|
165
|
+
private readonly disposedSlices;
|
|
166
|
+
/** @internal */
|
|
167
|
+
private readonly registrationObservers;
|
|
168
|
+
/**
|
|
169
|
+
* Changes accumulated inside the current public call, flushed once at its end.
|
|
170
|
+
*
|
|
171
|
+
* @internal
|
|
172
|
+
*/
|
|
173
|
+
private pendingRegistrationChanges;
|
|
174
|
+
/**
|
|
175
|
+
* Depth of nested registration transactions.
|
|
176
|
+
*
|
|
177
|
+
* @remarks
|
|
178
|
+
* `hotReplace` calls three `replace*` methods, and each of those registers repeatedly.
|
|
179
|
+
* Only the outermost public entry point flushes, so one `hotReplace` produces one batch
|
|
180
|
+
* spanning all three kinds rather than three batches of intermediate topology.
|
|
181
|
+
*
|
|
182
|
+
* @internal
|
|
183
|
+
*/
|
|
184
|
+
private registrationDepth;
|
|
185
|
+
/** True while observers are being notified, so a re-entrant change is queued. @internal */
|
|
186
|
+
private notifyingRegistrations;
|
|
187
|
+
/** Batches produced by an observer's own registrations, drained after the current one. @internal */
|
|
188
|
+
private readonly queuedRegistrationBatches;
|
|
112
189
|
/**
|
|
113
190
|
* Whether `__replayEvents()` is allowed.
|
|
114
191
|
* Set from `spec.devtools.allowReplay`.
|
|
@@ -135,6 +212,8 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
135
212
|
* signal that a reducer misbehaved.
|
|
136
213
|
*/
|
|
137
214
|
private readonly onReducerError?;
|
|
215
|
+
/** @internal */
|
|
216
|
+
private readonly onSubscriberError?;
|
|
138
217
|
/**
|
|
139
218
|
* `slice:channel:type` combinations already warned about for payload aliasing.
|
|
140
219
|
*
|
|
@@ -224,13 +303,15 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
224
303
|
* Tracks processed events by fingerprint with timestamps for TTL-based deduplication.
|
|
225
304
|
*
|
|
226
305
|
* **Deduplication Behavior:**
|
|
227
|
-
* - Events are fingerprinted
|
|
306
|
+
* - Events are fingerprinted through the codec, so `Map`, `Set`, `Date`, `BigInt`, binary
|
|
307
|
+
* and cyclic payloads all compare by content rather than collapsing to `{}`
|
|
308
|
+
* - Plain-object keys are sorted, so key order is not content; array and `Map` order is
|
|
228
309
|
* - If an identical fingerprint is seen within the dedup window, it's skipped
|
|
229
|
-
* - The window is
|
|
310
|
+
* - The window is `dedupWindowMs`, which defaults to `0` (dedup off)
|
|
230
311
|
*
|
|
231
312
|
* **Limitations:**
|
|
232
|
-
* -
|
|
233
|
-
*
|
|
313
|
+
* - A payload larger than the fingerprint node budget is never deduplicated, which is the
|
|
314
|
+
* safe direction: a missed dedup costs a duplicate, a false one drops a real event
|
|
234
315
|
* - Legitimate rapid-fire identical events may be incorrectly deduplicated
|
|
235
316
|
* - The cache is bounded to 1000 entries with lazy pruning
|
|
236
317
|
*
|
|
@@ -337,42 +418,6 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
337
418
|
* @internal
|
|
338
419
|
*/
|
|
339
420
|
private reportCascade;
|
|
340
|
-
/**
|
|
341
|
-
* Checks if an event matches a `When` matcher.
|
|
342
|
-
*
|
|
343
|
-
* @param when - The When matcher (or undefined for "all events").
|
|
344
|
-
* @param event - The event to check.
|
|
345
|
-
* @returns `true` if the event matches, `false` otherwise.
|
|
346
|
-
*
|
|
347
|
-
* @remarks
|
|
348
|
-
* - `undefined` or missing `when` matches ALL events.
|
|
349
|
-
* - `{ any: true }` matches ALL events.
|
|
350
|
-
* - `{ keys: [...] }` matches if event's `[channel, type]` is in the array.
|
|
351
|
-
* - `{ channel: 'x' }` matches if event's channel equals 'x'.
|
|
352
|
-
* - `{ channels: ['x', 'y'] }` matches if event's channel is in the array.
|
|
353
|
-
*
|
|
354
|
-
* @internal
|
|
355
|
-
*/
|
|
356
|
-
private matchesWhen;
|
|
357
|
-
/**
|
|
358
|
-
* Extracts the middleware function from a MiddlewareInput.
|
|
359
|
-
* Handles both raw functions (legacy) and MiddlewareSpec objects.
|
|
360
|
-
*
|
|
361
|
-
* @param input - MiddlewareInput (function or spec).
|
|
362
|
-
* @returns The middleware function.
|
|
363
|
-
*
|
|
364
|
-
* @internal
|
|
365
|
-
*/
|
|
366
|
-
private getMiddlewareFunction;
|
|
367
|
-
/**
|
|
368
|
-
* Gets the `when` matcher from a MiddlewareInput.
|
|
369
|
-
*
|
|
370
|
-
* @param input - MiddlewareInput (function or spec).
|
|
371
|
-
* @returns The `when` matcher, or `undefined` for raw functions (match all).
|
|
372
|
-
*
|
|
373
|
-
* @internal
|
|
374
|
-
*/
|
|
375
|
-
private getMiddlewareWhen;
|
|
376
421
|
/**
|
|
377
422
|
* Invokes all registered **effects** for a given event.
|
|
378
423
|
* Handles both key-based effects (O(1) lookup) and pattern-based effects (runtime matching).
|
|
@@ -515,17 +560,21 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
515
560
|
reducers: {
|
|
516
561
|
name: string;
|
|
517
562
|
when: When<EM> | undefined;
|
|
563
|
+
origin: Origin;
|
|
564
|
+
owner: string | undefined;
|
|
518
565
|
}[];
|
|
519
566
|
effects: {
|
|
520
567
|
channel: string;
|
|
521
568
|
type: string;
|
|
522
569
|
name?: string;
|
|
523
570
|
description?: string;
|
|
571
|
+
origin: Origin;
|
|
524
572
|
}[];
|
|
525
573
|
middleware: {
|
|
526
574
|
name?: string;
|
|
527
575
|
description?: string;
|
|
528
576
|
when?: unknown;
|
|
577
|
+
origin: Origin;
|
|
529
578
|
}[];
|
|
530
579
|
atomic: {
|
|
531
580
|
reducer: string;
|
|
@@ -535,6 +584,7 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
535
584
|
channel: string;
|
|
536
585
|
type: string;
|
|
537
586
|
phase: string;
|
|
587
|
+
duringReplay: boolean;
|
|
538
588
|
}[];
|
|
539
589
|
coarse: number;
|
|
540
590
|
dedupHits: number;
|
|
@@ -556,6 +606,12 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
556
606
|
* @internal
|
|
557
607
|
*/
|
|
558
608
|
__applyExternalState(nextPlain: any): void;
|
|
609
|
+
/**
|
|
610
|
+
* The body of {@link __applyExternalState}, with the replay flag already set.
|
|
611
|
+
*
|
|
612
|
+
* @internal
|
|
613
|
+
*/
|
|
614
|
+
private applyExternalStateInner;
|
|
559
615
|
/**
|
|
560
616
|
* Replays a sequence of events from a snapshot through reducers and event
|
|
561
617
|
* subscribers ONLY. Skips dedup, middleware, and effects.
|
|
@@ -575,6 +631,12 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
575
631
|
id: string;
|
|
576
632
|
meta?: EventMeta;
|
|
577
633
|
}>): void;
|
|
634
|
+
/**
|
|
635
|
+
* The body of {@link __replayEvents}, with the replay flag already set.
|
|
636
|
+
*
|
|
637
|
+
* @internal
|
|
638
|
+
*/
|
|
639
|
+
private replayEventsInner;
|
|
578
640
|
/**
|
|
579
641
|
* Emits a typed event `(channel, type, payload)`.
|
|
580
642
|
* Events are queued and processed **sequentially** (FIFO).
|
|
@@ -710,6 +772,80 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
710
772
|
reducer: R;
|
|
711
773
|
property: string;
|
|
712
774
|
}, h: (chg: Change) => void, options?: ConnectOptions): () => void;
|
|
775
|
+
/**
|
|
776
|
+
* Subscribe to reducer, middleware and effect registrations.
|
|
777
|
+
*
|
|
778
|
+
* Delivered as an array, one batch per public call: `replaceReducers` unmounts and then
|
|
779
|
+
* remounts, and a per-change observer would see a spurious unmount of a slice that is only
|
|
780
|
+
* being updated. Observers run after the state broadcast, and a registration made by an
|
|
781
|
+
* observer is queued rather than delivered re-entrantly.
|
|
782
|
+
*
|
|
783
|
+
* Replay never produces a change, so there is no `duringReplay` option here. `dispose()`
|
|
784
|
+
* fires nothing.
|
|
785
|
+
*
|
|
786
|
+
* @param observer - Receives one batch per registration change.
|
|
787
|
+
* @param options - `emitCurrent` synthesizes a `'mounted'` batch for everything already
|
|
788
|
+
* installed, delivered synchronously before this call returns, carrying each registration's
|
|
789
|
+
* real origin rather than a synthetic marker.
|
|
790
|
+
* @returns Unsubscribe function.
|
|
791
|
+
*
|
|
792
|
+
* @example
|
|
793
|
+
* ```ts
|
|
794
|
+
* const off = store.onRegistrationChange((changes) => {
|
|
795
|
+
* for (const c of changes) {
|
|
796
|
+
* console.log(c.op, c.kind, c.name, c.origin);
|
|
797
|
+
* }
|
|
798
|
+
* }, { emitCurrent: true });
|
|
799
|
+
* off();
|
|
800
|
+
* ```
|
|
801
|
+
*
|
|
802
|
+
* @public
|
|
803
|
+
*/
|
|
804
|
+
onRegistrationChange(observer: RegistrationObserver<EM>, options?: {
|
|
805
|
+
emitCurrent?: boolean;
|
|
806
|
+
}): Unsubscribe;
|
|
807
|
+
/**
|
|
808
|
+
* Everything currently installed, as `"mounted"` changes.
|
|
809
|
+
*
|
|
810
|
+
* @internal
|
|
811
|
+
*/
|
|
812
|
+
private describeCurrentRegistrations;
|
|
813
|
+
/**
|
|
814
|
+
* Runs `fn` as one registration transaction, flushing a single batch at the outermost end.
|
|
815
|
+
*
|
|
816
|
+
* @internal
|
|
817
|
+
*/
|
|
818
|
+
private inRegistrationTransaction;
|
|
819
|
+
/**
|
|
820
|
+
* Records a change, to be delivered when the current transaction ends.
|
|
821
|
+
*
|
|
822
|
+
* @remarks
|
|
823
|
+
* Guarded on observer count **before** anything is allocated. These call sites run inside
|
|
824
|
+
* `createStore`, so a twenty-slice store with nobody listening must build no objects and
|
|
825
|
+
* no arrays at all - the same discipline `emitInstrumentation` already follows.
|
|
826
|
+
*
|
|
827
|
+
* @internal
|
|
828
|
+
*/
|
|
829
|
+
private recordRegistrationChange;
|
|
830
|
+
/** @internal */
|
|
831
|
+
private flushRegistrationChanges;
|
|
832
|
+
/**
|
|
833
|
+
* Delivers batches an observer produced while being notified.
|
|
834
|
+
*
|
|
835
|
+
* @remarks
|
|
836
|
+
* Bounded like the reduce depth, and for the same reason: two observers registering in
|
|
837
|
+
* response to each other would otherwise loop forever. Logged rather than thrown - the
|
|
838
|
+
* topology is correct at that point, and throwing would truncate the stream *and* unwind a
|
|
839
|
+
* caller that did nothing wrong.
|
|
840
|
+
*
|
|
841
|
+
* @internal
|
|
842
|
+
*/
|
|
843
|
+
private drainQueuedRegistrationBatches;
|
|
844
|
+
/** @internal */
|
|
845
|
+
private deliverRegistrationBatch;
|
|
846
|
+
/** @internal */
|
|
847
|
+
private invokeRegistrationObserver;
|
|
848
|
+
get isReplaying(): boolean;
|
|
713
849
|
/**
|
|
714
850
|
* Subscribe to events by channel and type.
|
|
715
851
|
*
|
|
@@ -721,8 +857,15 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
721
857
|
* - `'committed'` (default): Events that passed middleware and reached reducers.
|
|
722
858
|
* Notified after reducers, before effects.
|
|
723
859
|
* - `'uncommitted'`: Events rejected by middleware. Notified immediately after rejection.
|
|
860
|
+
* - `'written'`: Events that actually changed state. Stricter than `committed`, which
|
|
861
|
+
* fires for every event a store accepts including one with no reducers at all.
|
|
724
862
|
* - `'all'`: Both committed and uncommitted events. Handler receives the phase parameter
|
|
725
|
-
* to distinguish between the two.
|
|
863
|
+
* to distinguish between the two. Deliberately not `written` as well: an event that
|
|
864
|
+
* writes is also committed, so folding it in would notify every existing `all`
|
|
865
|
+
* subscriber twice for one event.
|
|
866
|
+
*
|
|
867
|
+
* **Replay:** a handler is not called while devtools is replaying, unless it opted in with
|
|
868
|
+
* `{ duringReplay: true }`.
|
|
726
869
|
*
|
|
727
870
|
* @typeParam C - Channel key within `EM`.
|
|
728
871
|
* @typeParam T - Event type key within channel `C`.
|
|
@@ -756,7 +899,9 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
756
899
|
*
|
|
757
900
|
* @public
|
|
758
901
|
*/
|
|
759
|
-
onEvent<C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, handler: NarrowedEventHandler<DeepReadonly<S>, EM, C, T>, phase?: EventPhase
|
|
902
|
+
onEvent<C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, handler: NarrowedEventHandler<DeepReadonly<S>, EM, C, T>, phase?: EventPhase, options?: {
|
|
903
|
+
duringReplay?: boolean;
|
|
904
|
+
}): Unsubscribe;
|
|
760
905
|
/**
|
|
761
906
|
* Subscribes to **coarse-grained** commits (called once per successful event, only if state changed).
|
|
762
907
|
*
|
|
@@ -823,7 +968,50 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
823
968
|
*
|
|
824
969
|
* @public
|
|
825
970
|
*/
|
|
826
|
-
registerMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>):
|
|
971
|
+
registerMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>): any;
|
|
972
|
+
/**
|
|
973
|
+
* Turns a disposer into the callable object `register*` returns.
|
|
974
|
+
*
|
|
975
|
+
* @remarks
|
|
976
|
+
* `Object.assign` onto the function rather than a new object, so every existing call site
|
|
977
|
+
* keeps working verbatim: `const off = store.registerEffect(spec); off();` compiles and
|
|
978
|
+
* runs exactly as before, while `.store` and `.dispose` become available to a library that
|
|
979
|
+
* wants the widened type.
|
|
980
|
+
*
|
|
981
|
+
* A callable object rather than an overload or a second method: an overload cannot change
|
|
982
|
+
* the return shape based on nothing, and a parallel `registerSliceX` family would leave
|
|
983
|
+
* the originals permanently second class and force libraries to branch on the core version.
|
|
984
|
+
*
|
|
985
|
+
* @internal
|
|
986
|
+
*/
|
|
987
|
+
private recordMiddlewareChange;
|
|
988
|
+
/**
|
|
989
|
+
* Drops an effect's metadata only once nothing is still registered with it.
|
|
990
|
+
*
|
|
991
|
+
* @remarks
|
|
992
|
+
* `effectMeta` is keyed by the effect *function*, and the same function can legitimately
|
|
993
|
+
* back several registrations. Deleting on the first disposal stripped the name and
|
|
994
|
+
* description of the ones still live, which a devtools panel then showed as unnamed.
|
|
995
|
+
*
|
|
996
|
+
* @internal
|
|
997
|
+
*/
|
|
998
|
+
private releaseEffectMeta;
|
|
999
|
+
/** @internal */
|
|
1000
|
+
private recordEffectChange;
|
|
1001
|
+
/** @internal */
|
|
1002
|
+
private asRegistration;
|
|
1003
|
+
/**
|
|
1004
|
+
* The one place the widening cast lives.
|
|
1005
|
+
*
|
|
1006
|
+
* @remarks
|
|
1007
|
+
* Decoration is type-level only. This returns the **same runtime object**: subscriptions,
|
|
1008
|
+
* effects, middleware, the dedup cache, both buses and any in-flight `call()` are
|
|
1009
|
+
* untouched, and nothing re-subscribes. Keeping the cast here means no call site needs one,
|
|
1010
|
+
* which is the entire point of the feature.
|
|
1011
|
+
*
|
|
1012
|
+
* @internal
|
|
1013
|
+
*/
|
|
1014
|
+
private widened;
|
|
827
1015
|
/**
|
|
828
1016
|
* Dynamically **adds** a named slice reducer at runtime.
|
|
829
1017
|
*
|
|
@@ -846,7 +1034,50 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
846
1034
|
*
|
|
847
1035
|
* @public
|
|
848
1036
|
*/
|
|
849
|
-
registerReducer(name: string, spec: ReducerSpec<any, EM
|
|
1037
|
+
registerReducer(name: string, spec: ReducerSpec<any, EM>, options?: {
|
|
1038
|
+
owner?: string;
|
|
1039
|
+
}): any;
|
|
1040
|
+
/**
|
|
1041
|
+
* Mounts a slice and hands back the widened store alongside a disposer.
|
|
1042
|
+
*
|
|
1043
|
+
* @remarks
|
|
1044
|
+
* The name `registerSlice` is what the guide uses; `registerReducer` keeps its broader
|
|
1045
|
+
* `name: string` signature and delegates here, so existing call sites are untouched.
|
|
1046
|
+
*
|
|
1047
|
+
* @public
|
|
1048
|
+
*/
|
|
1049
|
+
registerSlice(name: string, spec: ReducerSpec<any, EM>, options?: {
|
|
1050
|
+
owner?: string;
|
|
1051
|
+
}): any;
|
|
1052
|
+
/** @internal */
|
|
1053
|
+
private registerSliceInner;
|
|
1054
|
+
/**
|
|
1055
|
+
* Mounts a slice and returns the widened store, for chaining.
|
|
1056
|
+
*
|
|
1057
|
+
* @remarks
|
|
1058
|
+
* No disposer, deliberately. After a disposer runs, the widened type still promises a
|
|
1059
|
+
* slice that is gone, and TypeScript cannot express "valid until that call". The chaining
|
|
1060
|
+
* API therefore does not hand one out, so the footgun does not exist on the path most
|
|
1061
|
+
* people take; {@link registerSlice} carries one for the library that owns the slice, and
|
|
1062
|
+
* the documented rule is that a disposer stays library-private.
|
|
1063
|
+
*
|
|
1064
|
+
* @public
|
|
1065
|
+
*/
|
|
1066
|
+
withSlice(name: string, spec: ReducerSpec<any, EM>, options?: {
|
|
1067
|
+
owner?: string;
|
|
1068
|
+
}): any;
|
|
1069
|
+
/**
|
|
1070
|
+
* Registers middleware and returns the widened store, for chaining.
|
|
1071
|
+
*
|
|
1072
|
+
* @public
|
|
1073
|
+
*/
|
|
1074
|
+
withMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>): any;
|
|
1075
|
+
/**
|
|
1076
|
+
* Registers an effect and returns the widened store, for chaining.
|
|
1077
|
+
*
|
|
1078
|
+
* @public
|
|
1079
|
+
*/
|
|
1080
|
+
withEffect(spec: EffectSpec<DeepReadonly<S>, EM>): any;
|
|
850
1081
|
/**
|
|
851
1082
|
* Registers an **effect** (stateless async event consumer) that runs after reducers.
|
|
852
1083
|
*
|
|
@@ -942,13 +1173,7 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
942
1173
|
* the terminal event from ever being sent. Un-iterated progress therefore buffers to
|
|
943
1174
|
* `highWaterMark` and is then counted on {@link CallHandle.dropped} rather than blocking.
|
|
944
1175
|
*
|
|
945
|
-
* **This is a local primitive.**
|
|
946
|
-
* envelope carries neither `meta` nor `parentId`, and ingress namespaces the channel, so
|
|
947
|
-
* neither correlation nor the reply route survives the hop. That is not an oversight to route
|
|
948
|
-
* around — federation answers cross-node request/reply with typed peer *queries*, which are
|
|
949
|
-
* gated by a responder policy that may concede or deny. A call that federated silently would
|
|
950
|
-
* turn that access decision into an accident of which channel someone named. Ask a peer with a
|
|
951
|
-
* query; use `call` within a process.
|
|
1176
|
+
* **This is a local primitive.**
|
|
952
1177
|
*
|
|
953
1178
|
* @example Timeout is idle, not total
|
|
954
1179
|
* ```ts
|
|
@@ -965,7 +1190,17 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
965
1190
|
* @public
|
|
966
1191
|
*/
|
|
967
1192
|
call<C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, payload: EM[C][T], opts: CallOptions<EM>): CallHandle<EventUnion<EM>, EventUnion<EM>>;
|
|
968
|
-
registerEffect(spec: EffectSpec<DeepReadonly<S>, EM>):
|
|
1193
|
+
registerEffect(spec: EffectSpec<DeepReadonly<S>, EM>): any;
|
|
1194
|
+
/**
|
|
1195
|
+
* {@link registerEffect}, with the provenance the caller cannot set.
|
|
1196
|
+
*
|
|
1197
|
+
* @remarks
|
|
1198
|
+
* Kept private so no origin parameter leaks into `StoreInstance`. Three callers: the
|
|
1199
|
+
* constructor (`spec`), the public method (`dynamic`), and `store.call()` (`internal`).
|
|
1200
|
+
*
|
|
1201
|
+
* @internal
|
|
1202
|
+
*/
|
|
1203
|
+
private registerEffectWithOrigin;
|
|
969
1204
|
/**
|
|
970
1205
|
* Convenience helper to register an **effect** filtered by a single `(channel, type)` pair.
|
|
971
1206
|
*
|
|
@@ -1004,7 +1239,11 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
1004
1239
|
*
|
|
1005
1240
|
* @public
|
|
1006
1241
|
*/
|
|
1007
|
-
replaceMiddleware(next: MiddlewareInput<DeepReadonly<S>, EM>[]
|
|
1242
|
+
replaceMiddleware(next: MiddlewareInput<DeepReadonly<S>, EM>[], opts?: {
|
|
1243
|
+
scope?: ReplaceScope;
|
|
1244
|
+
}): void;
|
|
1245
|
+
/** @internal */
|
|
1246
|
+
private replaceMiddlewareInner;
|
|
1008
1247
|
/**
|
|
1009
1248
|
* Replaces all registered **effects** (HMR-friendly).
|
|
1010
1249
|
*
|
|
@@ -1021,12 +1260,24 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
1021
1260
|
*
|
|
1022
1261
|
* @public
|
|
1023
1262
|
*/
|
|
1024
|
-
replaceEffects(next: Array<EffectSpec<DeepReadonly<S>, EM
|
|
1263
|
+
replaceEffects(next: Array<EffectSpec<DeepReadonly<S>, EM>>, opts?: {
|
|
1264
|
+
scope?: ReplaceScope;
|
|
1265
|
+
}): void;
|
|
1266
|
+
/** @internal */
|
|
1267
|
+
private replaceEffectsInner;
|
|
1025
1268
|
/**
|
|
1026
1269
|
* Replaces the entire **reducer set** (HMR-friendly).
|
|
1027
1270
|
*
|
|
1028
1271
|
* @param next - Map of slice specs keyed by slice name.
|
|
1029
|
-
* @param opts - `{ preserveState?: boolean }` (default `true`)
|
|
1272
|
+
* @param opts - `{ preserveState?: boolean }` (default `true`) and
|
|
1273
|
+
* `{ scope?: "spec" | "all" }` (default `"spec"`).
|
|
1274
|
+
*
|
|
1275
|
+
* @remarks
|
|
1276
|
+
* Replaces **spec-provenance slices only**. A slice mounted after construction with
|
|
1277
|
+
* `registerSlice` survives, along with its state: it was never part of the set this call
|
|
1278
|
+
* is replacing. Pass `{ scope: "all" }` for the pre-0.8.0 wholesale behaviour.
|
|
1279
|
+
*
|
|
1280
|
+
* Throws, before mutating anything, if `next` names a slice a library mounted at runtime.
|
|
1030
1281
|
*
|
|
1031
1282
|
* @example Hot module replacement
|
|
1032
1283
|
* ```ts
|
|
@@ -1041,7 +1292,34 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
1041
1292
|
*/
|
|
1042
1293
|
replaceReducers(next: Record<R, ReducerSpec<S[R], EM>>, opts?: {
|
|
1043
1294
|
preserveState?: boolean;
|
|
1295
|
+
scope?: ReplaceScope;
|
|
1044
1296
|
}): void;
|
|
1297
|
+
/** @internal */
|
|
1298
|
+
private replaceReducersInner;
|
|
1299
|
+
/**
|
|
1300
|
+
* Refuses, before anything is mutated, to take over a slice mounted at runtime.
|
|
1301
|
+
*
|
|
1302
|
+
* @remarks
|
|
1303
|
+
* An application authoring a slice a library owns is a real mistake, and a silent takeover
|
|
1304
|
+
* is the worst available outcome: the library keeps a disposer for a slice that is no
|
|
1305
|
+
* longer its own. Throwing part-way through would be worse still, which is why this runs
|
|
1306
|
+
* as a pre-flight and why `hotReplace` calls it before swapping anything at all.
|
|
1307
|
+
*
|
|
1308
|
+
* @internal
|
|
1309
|
+
*/
|
|
1310
|
+
private assertNoSliceCollision;
|
|
1311
|
+
/**
|
|
1312
|
+
* Says what a `replace*` call left alone, when it left anything alone.
|
|
1313
|
+
*
|
|
1314
|
+
* @remarks
|
|
1315
|
+
* Development only, and silent unless something was actually preserved, so the normal HMR
|
|
1316
|
+
* path stays quiet. `console.debug` rather than `warn`: this is correct operation, and
|
|
1317
|
+
* every existing `warn` in this file marks a genuine problem. It exists so "why is that
|
|
1318
|
+
* effect still firing after a reload" has an answer that does not require reading core.
|
|
1319
|
+
*
|
|
1320
|
+
* @internal
|
|
1321
|
+
*/
|
|
1322
|
+
private reportPreserved;
|
|
1045
1323
|
/**
|
|
1046
1324
|
* Convenience API to replace **any subset** of store parts (HMR patterns).
|
|
1047
1325
|
*
|
|
@@ -1064,6 +1342,7 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
1064
1342
|
middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];
|
|
1065
1343
|
effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;
|
|
1066
1344
|
preserveState?: boolean;
|
|
1345
|
+
scope?: ReplaceScope;
|
|
1067
1346
|
}): void;
|
|
1068
1347
|
/**
|
|
1069
1348
|
* Mounts a slice: installs reducer, initializes state (unless preserved),
|
|
@@ -1076,25 +1355,47 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
1076
1355
|
* @internal
|
|
1077
1356
|
*/
|
|
1078
1357
|
private mountSlice;
|
|
1358
|
+
/** @internal */
|
|
1359
|
+
private mountSliceInner;
|
|
1079
1360
|
/**
|
|
1080
|
-
*
|
|
1081
|
-
* and optionally deletes the slice state.
|
|
1361
|
+
* Records a slice mount or unmount for {@link onRegistrationChange}.
|
|
1082
1362
|
*
|
|
1083
|
-
* @
|
|
1084
|
-
|
|
1363
|
+
* @internal
|
|
1364
|
+
*/
|
|
1365
|
+
private recordSliceChange;
|
|
1366
|
+
/**
|
|
1367
|
+
* Announces a newly mounted slice on the connector bus.
|
|
1368
|
+
*
|
|
1369
|
+
* @remarks
|
|
1370
|
+
* `registerReducer` has always broadcast to `listeners`, which wakes `subscribe` and so
|
|
1371
|
+
* `useSelector`. It emitted **nothing** on `connectorBus`, which is what `connect` rides,
|
|
1372
|
+
* so `useAtomicProp`, `useAtomicProps` and the Suspense hooks never woke for a slice
|
|
1373
|
+
* mounted after creation: a component subscribed to a path inside it simply never
|
|
1374
|
+
* re-rendered. That makes the decoration story ship a documented-as-working path that does
|
|
1375
|
+
* not work, which is why this is here rather than filed as a follow-up.
|
|
1376
|
+
*
|
|
1377
|
+
* Scope, stated precisely because it is narrower than it looks: this emits the slice root
|
|
1378
|
+
* and its **top-level** keys, which is exactly what an ordinary commit emits when a
|
|
1379
|
+
* subtree first appears - `detectChangedProps` reports a newly-appearing branch at its
|
|
1380
|
+
* root, not leaf by leaf. So a `connect` on `"deep.n"` does not fire here, and does not
|
|
1381
|
+
* fire on a normal commit that first creates `deep` either. Consistent, not complete.
|
|
1382
|
+
*
|
|
1383
|
+
* Skipped when nothing is subscribed, and skipped entirely during construction, where no
|
|
1384
|
+
* subscriber can exist yet.
|
|
1085
1385
|
*
|
|
1086
1386
|
* @internal
|
|
1087
1387
|
*/
|
|
1088
|
-
private
|
|
1388
|
+
private announceMountedSlice;
|
|
1089
1389
|
/**
|
|
1090
|
-
*
|
|
1390
|
+
* Unmounts a slice: disposes reducer-bus listeners, removes reducer,
|
|
1391
|
+
* and optionally deletes the slice state.
|
|
1091
1392
|
*
|
|
1092
|
-
* @param
|
|
1093
|
-
* @
|
|
1393
|
+
* @param name - Slice name.
|
|
1394
|
+
* @param opts - `{ deleteState: boolean }`.
|
|
1094
1395
|
*
|
|
1095
1396
|
* @internal
|
|
1096
1397
|
*/
|
|
1097
|
-
private
|
|
1398
|
+
private unmountSlice;
|
|
1098
1399
|
/**
|
|
1099
1400
|
* Reads a dotted path from an object (supports numeric array indices via string keys).
|
|
1100
1401
|
*
|
|
@@ -1102,6 +1403,10 @@ export declare class Store<EM extends EventMapBase, R extends string, S extends
|
|
|
1102
1403
|
* @param path - Dotted path; leading dot is ignored.
|
|
1103
1404
|
* @returns The value at the path, or `undefined`.
|
|
1104
1405
|
*
|
|
1406
|
+
* @remarks
|
|
1407
|
+
* A member rather than a bare import: a test replaces this on the instance to count how many
|
|
1408
|
+
* walks describing a change costs, which only works while the callers go through `this`.
|
|
1409
|
+
*
|
|
1105
1410
|
* @internal
|
|
1106
1411
|
*/
|
|
1107
1412
|
private getAtPath;
|
|
@@ -1177,6 +1482,7 @@ export declare function createStore<S extends Record<string, any>, EM extends Ev
|
|
|
1177
1482
|
};
|
|
1178
1483
|
onEffectError?: (error: unknown, event: EventUnion<EM>) => void;
|
|
1179
1484
|
onReducerError?: (error: unknown, event: EventUnion<EM>, slice: string) => void;
|
|
1485
|
+
onSubscriberError?: (error: unknown, event: EventUnion<EM>, phase: NotifiedPhase) => void;
|
|
1180
1486
|
maxReduceDepth?: number;
|
|
1181
1487
|
maxTransitionsPerDrain?: number;
|
|
1182
1488
|
onCascade?: (info: CascadeInfo<EM>) => void;
|
|
@@ -1222,6 +1528,7 @@ export declare function createStore<RM extends ReducersMapAny>(cfg: {
|
|
|
1222
1528
|
};
|
|
1223
1529
|
onEffectError?: (error: unknown, event: EventUnion<EMFromReducersStrict<RM>>) => void;
|
|
1224
1530
|
onReducerError?: (error: unknown, event: EventUnion<EMFromReducersStrict<RM>>, slice: string) => void;
|
|
1531
|
+
onSubscriberError?: (error: unknown, event: EventUnion<EMFromReducersStrict<RM>>, phase: NotifiedPhase) => void;
|
|
1225
1532
|
maxReduceDepth?: number;
|
|
1226
1533
|
maxTransitionsPerDrain?: number;
|
|
1227
1534
|
onCascade?: (info: CascadeInfo<EMFromReducersStrict<RM>>) => void;
|