@yoltra/core 0.2.0 → 0.4.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 +4 -4
- package/README.md +115 -10
- package/dist/types/entity/entityAdapter.d.ts +118 -0
- package/dist/types/eventBus/EventBus.d.ts +18 -5
- package/dist/types/eventBus/LooseEventBus.d.ts +72 -49
- package/dist/types/index.d.ts +9 -1
- package/dist/types/persistence/adapters.d.ts +33 -0
- package/dist/types/persistence/persist.d.ts +126 -0
- package/dist/types/serialize/codec.d.ts +119 -0
- package/dist/types/store/Store.d.ts +73 -15
- package/dist/types/types.d.ts +129 -29
- package/dist/types/utils/immutability.d.ts +24 -1
- package/dist/yoltra.cjs.js +2 -2
- package/dist/yoltra.esm.js +1090 -460
- package/dist/yoltra.umd.js +2 -2
- package/package.json +23 -3
package/dist/types/types.d.ts
CHANGED
|
@@ -48,7 +48,30 @@ export type EventKey<EM extends EventMapBase> = {
|
|
|
48
48
|
[C in keyof EM & string]: [C, keyof EM[C] & string];
|
|
49
49
|
}[keyof EM & string];
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* Opaque, optional envelope metadata carried alongside an {@link Event}.
|
|
52
|
+
*
|
|
53
|
+
* @remarks
|
|
54
|
+
* The store never reads, validates or acts on this — it only carries it end to end, so
|
|
55
|
+
* reducers, middleware, effects, event subscribers and instrumentation all observe the same
|
|
56
|
+
* value. It is deliberately untyped at this level: consumers namespace their own keys (for
|
|
57
|
+
* example a tracing integration keeping provenance under `meta.trace`) rather than
|
|
58
|
+
* extending core with domain concepts.
|
|
59
|
+
*
|
|
60
|
+
* It is **not** part of the deduplication fingerprint, which is computed from
|
|
61
|
+
* `(channel, type, payload)` only. Two events differing solely in `meta` still dedupe.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* await store.emit('orders', 'created', payload, {
|
|
66
|
+
* meta: { trace: { origin: 'checkout-service', hop: 1 } },
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @public
|
|
71
|
+
*/
|
|
72
|
+
export type EventMeta = Readonly<Record<string, unknown>>;
|
|
73
|
+
/**
|
|
74
|
+
* A single event object: `{ channel, type, payload, id }`, plus optional `meta`.
|
|
52
75
|
*
|
|
53
76
|
* @typeParam EM - Event map.
|
|
54
77
|
* @typeParam C - Channel key.
|
|
@@ -56,14 +79,16 @@ export type EventKey<EM extends EventMapBase> = {
|
|
|
56
79
|
* @typeParam P - Payload type (defaults to `EM[C][T]`).
|
|
57
80
|
*
|
|
58
81
|
* @remarks
|
|
59
|
-
* - The `id` field is automatically added by the store to enable deduplication
|
|
82
|
+
* - The `id` field is automatically added by the store to enable deduplication, unless the
|
|
83
|
+
* emitter supplies one via {@link EmitOptions.id}.
|
|
60
84
|
* - Used for preventing duplicate event processing (e.g., React Strict Mode).
|
|
85
|
+
* - `meta` is present only when {@link EmitOptions.meta} was supplied. See {@link EventMeta}.
|
|
61
86
|
*
|
|
62
87
|
* @example
|
|
63
88
|
* ```ts
|
|
64
89
|
* type EM = { ui: { toggle: boolean } };
|
|
65
90
|
* type Evt = Event<EM, 'ui', 'toggle'>;
|
|
66
|
-
* // { channel: 'ui'; type: 'toggle'; payload: boolean; id: string }
|
|
91
|
+
* // { channel: 'ui'; type: 'toggle'; payload: boolean; id: string; meta?: EventMeta }
|
|
67
92
|
* ```
|
|
68
93
|
*
|
|
69
94
|
* @public
|
|
@@ -74,6 +99,11 @@ export interface Event<EM extends EventMapBase = EventMapBase, C extends keyof E
|
|
|
74
99
|
payload: P;
|
|
75
100
|
/** Unique identifier for deduplication and devtools tracking (automatically added by store) */
|
|
76
101
|
id: string;
|
|
102
|
+
/**
|
|
103
|
+
* Optional caller-supplied metadata, carried through the pipeline untouched.
|
|
104
|
+
* Absent entirely unless {@link EmitOptions.meta} was supplied. See {@link EventMeta}.
|
|
105
|
+
*/
|
|
106
|
+
readonly meta?: EventMeta;
|
|
77
107
|
}
|
|
78
108
|
/**
|
|
79
109
|
* Generic "old → new" wrapper for fine-grained change notifications.
|
|
@@ -129,6 +159,41 @@ export interface EmitOptions {
|
|
|
129
159
|
* is 0, using a short default window.
|
|
130
160
|
*/
|
|
131
161
|
dedupKey?: string;
|
|
162
|
+
/**
|
|
163
|
+
* Use this exact id for the event instead of generating one.
|
|
164
|
+
*
|
|
165
|
+
* @remarks
|
|
166
|
+
* Intended for **idempotent re-emission**: a caller replaying an event from elsewhere (a
|
|
167
|
+
* peer store, a durable log) can preserve the original id so the same logical event keeps
|
|
168
|
+
* one identity everywhere, which makes it traceable across systems and in DevTools.
|
|
169
|
+
*
|
|
170
|
+
* The store does **not** enforce uniqueness — supplying a duplicate id does not dedupe the
|
|
171
|
+
* event. Deduplication is a separate, opt-in concern; see {@link EmitOptions.dedupKey}.
|
|
172
|
+
*/
|
|
173
|
+
id?: string;
|
|
174
|
+
/**
|
|
175
|
+
* Metadata to attach to this event, carried through the pipeline untouched and visible to
|
|
176
|
+
* reducers, middleware, effects, subscribers and instrumentation. See {@link EventMeta}.
|
|
177
|
+
*
|
|
178
|
+
* @remarks
|
|
179
|
+
* Omitting this leaves `event.meta` genuinely absent rather than `undefined`, so event
|
|
180
|
+
* objects are byte-identical to those produced before this option existed.
|
|
181
|
+
*/
|
|
182
|
+
meta?: EventMeta;
|
|
183
|
+
/**
|
|
184
|
+
* Bypass deduplication for this emit entirely, even when the store was created with
|
|
185
|
+
* {@link StoreSpec.dedupWindowMs} greater than 0.
|
|
186
|
+
*
|
|
187
|
+
* @remarks
|
|
188
|
+
* Content-based dedup fingerprints `(channel, type, payload)`, so a store with a dedup
|
|
189
|
+
* window silently collapses genuinely distinct events that happen to share a payload —
|
|
190
|
+
* repeated ticks with an empty payload, or the same event legitimately arriving twice from
|
|
191
|
+
* two different sources. Set this when the caller already guarantees distinctness by other
|
|
192
|
+
* means and needs every emit to land.
|
|
193
|
+
*
|
|
194
|
+
* Takes precedence over both {@link EmitOptions.dedupKey} and the store-level window.
|
|
195
|
+
*/
|
|
196
|
+
skipDedup?: boolean;
|
|
132
197
|
}
|
|
133
198
|
export type Emit<EM extends EventMapBase> = <C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, payload: EM[C][T], opts?: EmitOptions) => Promise<void>;
|
|
134
199
|
/**
|
|
@@ -145,12 +210,16 @@ export type Unsubscribe = () => void;
|
|
|
145
210
|
* @public
|
|
146
211
|
*/
|
|
147
212
|
export interface InstrumentedEvent<EM extends EventMapBase = EventMapBase> {
|
|
148
|
-
/**
|
|
213
|
+
/**
|
|
214
|
+
* The processed event, including its `id` and any {@link EventMeta} the emitter attached.
|
|
215
|
+
* `meta` is absent unless it was supplied.
|
|
216
|
+
*/
|
|
149
217
|
event: {
|
|
150
218
|
id: string;
|
|
151
219
|
channel: string;
|
|
152
220
|
type: string;
|
|
153
221
|
payload: unknown;
|
|
222
|
+
meta?: EventMeta;
|
|
154
223
|
};
|
|
155
224
|
/** `true` if the event passed middleware and ran reducers; `false` if vetoed. */
|
|
156
225
|
committed: boolean;
|
|
@@ -295,6 +364,26 @@ export type StoreSpec<R extends string, S extends Record<R, any>, EM extends Eve
|
|
|
295
364
|
* @default 0 (disabled)
|
|
296
365
|
*/
|
|
297
366
|
dedupWindowMs?: number;
|
|
367
|
+
/**
|
|
368
|
+
* Generates the `id` for each emitted event. Defaults to `crypto.randomUUID()`.
|
|
369
|
+
*
|
|
370
|
+
* @remarks
|
|
371
|
+
* Two reasons to override it. First, portability: `crypto.randomUUID` requires a **secure
|
|
372
|
+
* context** in browsers and is absent on some runtimes (React Native / Hermes), where the
|
|
373
|
+
* default would throw on every emit. Second, determinism: injecting a counter makes event
|
|
374
|
+
* ids stable across runs, which is what allows byte-exact assertions in tests.
|
|
375
|
+
*
|
|
376
|
+
* The factory must return a string. Uniqueness is the caller's responsibility.
|
|
377
|
+
*
|
|
378
|
+
* @default () => crypto.randomUUID()
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```ts
|
|
382
|
+
* let n = 0;
|
|
383
|
+
* const store = createStore({ name: 'Test', reducer, idFactory: () => `evt-${++n}` });
|
|
384
|
+
* ```
|
|
385
|
+
*/
|
|
386
|
+
idFactory?: () => string;
|
|
298
387
|
/**
|
|
299
388
|
* DevTools configuration options.
|
|
300
389
|
*
|
|
@@ -324,6 +413,25 @@ export type StoreSpec<R extends string, S extends Record<R, any>, EM extends Eve
|
|
|
324
413
|
* @param event - The event whose effect failed.
|
|
325
414
|
*/
|
|
326
415
|
onEffectError?: (error: unknown, event: EventUnion<EM>) => void;
|
|
416
|
+
/**
|
|
417
|
+
* Invoked when a reducer throws.
|
|
418
|
+
*
|
|
419
|
+
* @remarks
|
|
420
|
+
* A reducer is meant to be pure and total, so a throw is a bug in application code — and it
|
|
421
|
+
* used to be almost invisible. Keyed reducers ran through a bus that logged and moved on,
|
|
422
|
+
* letting the event commit and its effects run; pattern reducers threw straight out of the
|
|
423
|
+
* drain, aborting the commit and notifying nobody. Both paths now isolate the failing slice
|
|
424
|
+
* and report here.
|
|
425
|
+
*
|
|
426
|
+
* The failing slice keeps its previous state; every other slice still reduces, and the event
|
|
427
|
+
* still commits if anything else changed. `emit()` never rejects because of a reducer error,
|
|
428
|
+
* so this hook is how a caller observes one.
|
|
429
|
+
*
|
|
430
|
+
* @param error - The thrown value.
|
|
431
|
+
* @param event - The event being reduced when it threw.
|
|
432
|
+
* @param slice - Name of the slice whose reducer threw.
|
|
433
|
+
*/
|
|
434
|
+
onReducerError?: (error: unknown, event: EventUnion<EM>, slice: string) => void;
|
|
327
435
|
};
|
|
328
436
|
/**
|
|
329
437
|
* Public Store surface.
|
|
@@ -384,9 +492,9 @@ export interface StoreInstance<R extends string = string, S extends Record<R, an
|
|
|
384
492
|
*/
|
|
385
493
|
registerEffect(spec: EffectSpec<DeepReadonly<S>, EM>): Unsubscribe;
|
|
386
494
|
/**
|
|
387
|
-
* Dynamically add middleware.
|
|
495
|
+
* Dynamically add middleware, in either the function or the spec form.
|
|
388
496
|
*/
|
|
389
|
-
registerMiddleware(mw:
|
|
497
|
+
registerMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>): Unsubscribe;
|
|
390
498
|
/**
|
|
391
499
|
* Dynamically add/remove a namespaced reducer slice at runtime.
|
|
392
500
|
*/
|
|
@@ -466,7 +574,7 @@ export interface StoreInstance<R extends string = string, S extends Record<R, an
|
|
|
466
574
|
*/
|
|
467
575
|
hotReplace(partial: {
|
|
468
576
|
reducer?: Record<R, ReducerSpec<S[R], EM>>;
|
|
469
|
-
middleware?:
|
|
577
|
+
middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];
|
|
470
578
|
effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;
|
|
471
579
|
preserveState?: boolean;
|
|
472
580
|
}): void;
|
|
@@ -487,6 +595,7 @@ export interface StoreInstance<R extends string = string, S extends Record<R, an
|
|
|
487
595
|
type: string;
|
|
488
596
|
payload: any;
|
|
489
597
|
id: string;
|
|
598
|
+
meta?: EventMeta;
|
|
490
599
|
}>): void;
|
|
491
600
|
/**
|
|
492
601
|
* Returns a structured introspection snapshot for DevTools UIs.
|
|
@@ -569,15 +678,6 @@ export interface StoreInstance<R extends string = string, S extends Record<R, an
|
|
|
569
678
|
* };
|
|
570
679
|
* ```
|
|
571
680
|
*
|
|
572
|
-
* @example Using `events` (legacy)
|
|
573
|
-
* ```ts
|
|
574
|
-
* const counterSpec: ReducerSpec<{ value: number }, MyEM> = {
|
|
575
|
-
* state: { value: 0 },
|
|
576
|
-
* events: [['ui', 'increment'], ['ui', 'decrement']],
|
|
577
|
-
* reducer(s, evt) { ... },
|
|
578
|
-
* };
|
|
579
|
-
* ```
|
|
580
|
-
*
|
|
581
681
|
* @public
|
|
582
682
|
*/
|
|
583
683
|
export interface ReducerSpec<S = any, EM extends EventMapBase = EventMapBase> {
|
|
@@ -587,14 +687,8 @@ export interface ReducerSpec<S = any, EM extends EventMapBase = EventMapBase> {
|
|
|
587
687
|
state: S;
|
|
588
688
|
/**
|
|
589
689
|
* Event targeting using the unified `When` matcher.
|
|
590
|
-
* Preferred over `events` for new code.
|
|
591
690
|
*/
|
|
592
691
|
when?: When<EM>;
|
|
593
|
-
/**
|
|
594
|
-
* List of EventKeys `[channel, type]` that this reducer responds to.
|
|
595
|
-
* @deprecated Use `when: { keys: [...] }` instead for better type inference.
|
|
596
|
-
*/
|
|
597
|
-
events?: ReadonlyArray<EventKey<EM>>;
|
|
598
692
|
/**
|
|
599
693
|
* Pure reducer function: `(state, event) => nextState`.
|
|
600
694
|
*/
|
|
@@ -651,14 +745,8 @@ export type ReducerFunction<S = any, EM extends EventMapBase = EventMapBase> = (
|
|
|
651
745
|
export interface EffectSpec<S = any, EM extends EventMapBase = EventMapBase> {
|
|
652
746
|
/**
|
|
653
747
|
* Event targeting using the unified `When` matcher.
|
|
654
|
-
* Preferred over `events` for new code.
|
|
655
748
|
*/
|
|
656
749
|
when?: When<EM>;
|
|
657
|
-
/**
|
|
658
|
-
* List of EventKeys `[channel, type]` that this effect responds to.
|
|
659
|
-
* @deprecated Use `when: { keys: [...] }` instead for better type inference.
|
|
660
|
-
*/
|
|
661
|
-
events?: ReadonlyArray<EventKey<EM>>;
|
|
662
750
|
/**
|
|
663
751
|
* Async effect handler: `(event, getState, emit) => void | Promise<void>`.
|
|
664
752
|
*/
|
|
@@ -986,11 +1074,23 @@ export type Dotted<Slice> = (keyof Slice & string) | Path<Slice>;
|
|
|
986
1074
|
/**
|
|
987
1075
|
* Deep readonly type: recursively makes all properties readonly.
|
|
988
1076
|
*
|
|
1077
|
+
* @remarks
|
|
1078
|
+
* The built-in object types are handled before the general mapped-object case, because
|
|
1079
|
+
* mapping over one destroys it. `{ readonly [K in keyof Map<K, V>]: ... }` produces an object
|
|
1080
|
+
* carrying the *names* of a Map's methods with their signatures rewritten, so reading a Map
|
|
1081
|
+
* out of state and calling `.get()` on it was a type error even though the value at runtime
|
|
1082
|
+
* is an ordinary Map. The same applied to `Set`, `Date`, `RegExp` and any function stored in
|
|
1083
|
+
* state.
|
|
1084
|
+
*
|
|
1085
|
+
* Collections become their `Readonly*` counterparts, which is the same treatment arrays
|
|
1086
|
+
* already had. Functions are returned untouched: a function's properties are not state, and
|
|
1087
|
+
* mapping over them makes it uncallable.
|
|
1088
|
+
*
|
|
989
1089
|
* @typeParam T - Type to make readonly.
|
|
990
1090
|
*
|
|
991
1091
|
* @public
|
|
992
1092
|
*/
|
|
993
|
-
export type DeepReadonly<T> = T extends (infer A)[] ? ReadonlyArray<DeepReadonly<A>> : T extends object ? {
|
|
1093
|
+
export type DeepReadonly<T> = T extends (...args: never[]) => unknown ? T : T extends (infer A)[] ? ReadonlyArray<DeepReadonly<A>> : T extends ReadonlyMap<infer K, infer V> ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>> : T extends ReadonlySet<infer V> ? ReadonlySet<DeepReadonly<V>> : T extends Date | RegExp | Promise<unknown> | Error ? T : T extends object ? {
|
|
994
1094
|
readonly [K in keyof T]: DeepReadonly<T[K]>;
|
|
995
1095
|
} : T;
|
|
996
1096
|
/**
|
|
@@ -44,4 +44,27 @@ import { DeepReadonly } from '../types';
|
|
|
44
44
|
*
|
|
45
45
|
* @public
|
|
46
46
|
*/
|
|
47
|
-
export declare function freezeState<T>(obj: T, seen?: WeakSet<object
|
|
47
|
+
export declare function freezeState<T>(obj: T, seen?: WeakSet<object>, alias?: AliasWatch): DeepReadonly<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Watches the freeze walk for one specific reference.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* Exists to turn a dev-only heisenbug into a named warning. Because the freeze is deep and
|
|
53
|
+
* in place, anything a reducer stores **by reference** is frozen too — the event payload, a
|
|
54
|
+
* module-level default, a cached response. Mutating that object afterwards then throws, only in
|
|
55
|
+
* development, from a stack that has nothing to do with the store, and the same code works in
|
|
56
|
+
* production because the freeze is compiled out.
|
|
57
|
+
*
|
|
58
|
+
* Freezing it is not the mistake: an object reachable from state genuinely must not be mutated,
|
|
59
|
+
* or state changes behind the store's back. Keeping the reference is. The walk already visits
|
|
60
|
+
* every node, so recognising one of them costs an identity comparison and lets the store say so
|
|
61
|
+
* at the moment it happens.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export interface AliasWatch {
|
|
66
|
+
/** The reference to look for while freezing. */
|
|
67
|
+
readonly watch: object;
|
|
68
|
+
/** Called if `watch` is reachable from the value being frozen. */
|
|
69
|
+
readonly onFound: () => void;
|
|
70
|
+
}
|
package/dist/yoltra.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @yoltra/core v0.
|
|
2
|
+
* @yoltra/core v0.4.0
|
|
3
3
|
* (c) 2026 Manu Ramirez <@pixerael>
|
|
4
4
|
* License: MIT
|
|
5
5
|
* Homepage: https://yoltra.dev
|
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
* This source code is licensed under the MIT license found in the
|
|
8
8
|
* LICENSE file in the root directory of this source tree
|
|
9
9
|
*/
|
|
10
|
-
"use strict";var k=Object.defineProperty;var R=(a,e,t)=>e in a?k(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var d=(a,e,t)=>R(a,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class M{constructor(){d(this,"handlers",new Map)}on(e,t,r){let n=this.handlers.get(e);n||(n=new Map,this.handlers.set(e,n));let s=n.get(t);return s||(s=new Set,n.set(t,s)),s.add(r),()=>this.off(e,t,r)}off(e,t,r){const n=this.handlers.get(e);if(!n)return;const s=n.get(t);s&&(s.delete(r),s.size===0&&n.delete(t),n.size===0&&this.handlers.delete(e))}emit(e,t,r){const n=this.handlers.get(e);if(!n)return;const s=n.get(t);if(!(!s||s.size===0))for(const c of[...s])try{c(r)}catch(i){console.error("EventBus handler error:",i)}}clear(){this.handlers.clear()}}class P{constructor(){d(this,"handlers",new Map);d(this,"patternHandlers",new Map)}on(e,t,r){const n=String(t);if(this.isPattern(n)){const s=n;this.patternHandlers.has(e)||this.patternHandlers.set(e,new Map);const c=this.patternHandlers.get(e);return c.has(s)||c.set(s,[]),c.get(s).push(r),()=>this.offPattern(e,s,r)}else{const s=this.normalizeTypeKey(n);this.handlers.has(e)||this.handlers.set(e,new Map);const c=this.handlers.get(e);return c.has(s)||c.set(s,[]),c.get(s).push(r),()=>this.offExactNormalized(e,s,r)}}off(e,t,r){const n=this.normalizeTypeKey(String(t));this.offExactNormalized(e,n,r)}offExactNormalized(e,t,r){const n=this.handlers.get(e);if(!n)return;const s=n.get(t);if(!s)return;const c=s.indexOf(r);c!==-1&&s.splice(c,1),s.length===0&&n.delete(t),n.size===0&&this.handlers.delete(e)}offPattern(e,t,r){const n=this.patternHandlers.get(e);if(!n)return;const s=n.get(t);if(!s)return;const c=s.indexOf(r);c!==-1&&s.splice(c,1),s.length===0&&n.delete(t),n.size===0&&this.patternHandlers.delete(e)}emit(e,t,r){const n=String(t),s=this.normalizeTypeKey(n),c=this.handlers.get(e)?.get(s)??[],i=this.patternHandlers.get(e),o=[];if(i&&i.size){const l=this.normalizeTypeKey(n);for(const[u,p]of i.entries())this.matchPattern(u,l)&&o.push(p)}const f=new Set,h=l=>{for(const u of[...l])if(!f.has(u)){f.add(u);try{u(r)}catch(p){console.error(p);continue}}};h(c);for(const l of o)h(l)}isPattern(e){return e.includes("*")}normalizeTypeKey(e){return e.replace(/^\./,"")}splitPath(e){return this.normalizeTypeKey(e).split(".").filter(Boolean)}matchPattern(e,t){const r=this.splitPath(e),n=this.splitPath(t);let s=0,c=0,i=-1,o=0;for(;c<n.length;)if(s<r.length&&(r[s]==="*"||r[s]===n[c]))s++,c++;else if(s<r.length&&r[s]==="**")i=s,o=c,s++;else if(i!==-1)s=i+1,c=++o;else return!1;for(;s<r.length&&r[s]==="**";)s++;return s===r.length}clear(){this.handlers.clear(),this.patternHandlers.clear()}__introspect(){const e=[];for(const[t,r]of this.handlers)for(const[n,s]of r)s.length>0&&e.push({channel:t,type:n,count:s.length});for(const[t,r]of this.patternHandlers)for(const[n,s]of r)s.length>0&&e.push({channel:t,type:n,count:s.length});return e}}class z{constructor(e){d(this,"_reduce");this._reduce=e}reduce(e,t){return this._reduce(e,t)}}function g(a,e,t="",r=new Map){if(a===e)return[];if(typeof a!="object"||typeof e!="object"||a===null||e===null)return typeof a=="number"&&Number.isNaN(a)&&Number.isNaN(e)?[]:[t];if(a instanceof Date&&e instanceof Date)return a.getTime()===e.getTime()?[]:[t];if(a instanceof RegExp&&e instanceof RegExp)return a.source===e.source&&e.flags===a.flags?[]:[t];const n=a,s=e,c=r.get(n);if(c?.has(s))return[];const i=c??new Set;i.add(s),c||r.set(n,i);try{const o=Array.isArray(a),f=Array.isArray(e);if(o!==f)return[t];const h=[];if(o){const u=a,p=e;if(u.length!==p.length)return[t];for(let y=0;y<u.length;y++){const m=t?`${t}.${y}`:`${y}`;h.push(...g(u[y],p[y],m,r))}return h.filter(Boolean)}const l=new Set([...Object.keys(a),...Object.keys(e)]);for(const u of l){const p=t?`${t}.${u}`:u,y=Object.prototype.hasOwnProperty.call(a,u),m=Object.prototype.hasOwnProperty.call(e,u);if(!y||!m){h.push(p);continue}h.push(...g(a[u],e[u],p,r))}return h.filter(Boolean)}finally{i.delete(s),i.size===0&&r.delete(n)}}function E(a,e=new WeakSet){if(a===null||typeof a!="object"||e.has(a)||Object.isFrozen(a))return a;if(e.add(a),Array.isArray(a)){const t=a;for(let r=0;r<t.length;r++)t[r]=E(t[r],e);return Object.freeze(t)}for(const t of Object.getOwnPropertyNames(a)){const r=Object.getOwnPropertyDescriptor(a,t);!r||!("value"in r)||(a[t]=E(a[t],e))}for(const t of Object.getOwnPropertySymbols(a)){const r=Object.getOwnPropertyDescriptor(a,t);!r||!("value"in r)||(a[t]=E(a[t],e))}return Object.freeze(a)}function b(a){return process.env.NODE_ENV==="production"?a:E(a)}const w=100,S=()=>typeof performance<"u"&&typeof performance.now=="function"?performance.now():Date.now();class v{constructor(e){d(this,"name");d(this,"middleware");d(this,"reducers");d(this,"state");d(this,"reducerBus");d(this,"connectorBus");d(this,"listeners",new Set);d(this,"effects",new Map);d(this,"patternEffects",new Set);d(this,"committedEventSubscribers",new Map);d(this,"uncommittedEventSubscribers",new Map);d(this,"allEventSubscribers",new Map);d(this,"sliceUnsubs",new Map);d(this,"patternReducers",new Map);d(this,"replayEnabled");d(this,"onEffectError");d(this,"reduceQueue",[]);d(this,"isReducing",!1);d(this,"instrumentObservers",new Set);d(this,"changedPathSink",null);d(this,"inFlightEffects",0);d(this,"processedEvents",new Map);d(this,"dedupCount",0);d(this,"effectMeta",new WeakMap);d(this,"dedupConfig");d(this,"eventCleanupTimer",null);if(this.name=e.name??"yoltra Store",this.reducerBus=new M,this.connectorBus=new P,this.middleware=[...e.middleware??[]],this.reducers={},this.state={},this.replayEnabled=e.devtools?.allowReplay??!1,this.onEffectError=e.onEffectError,this.dedupConfig={windowMs:e.dedupWindowMs??0,maxCacheSize:1e3},Object.entries(e.reducer).forEach(([t,r])=>{this.mountSlice(t,r,{preserveState:!1})}),e.effects?.length)for(const t of e.effects)this.registerEffect(t);this.dispose=this.dispose.bind(this),this.notifyEffects=this.notifyEffects.bind(this),this.forwardEvent=this.forwardEvent.bind(this),this.__applyExternalState=this.__applyExternalState.bind(this),this.__replayEvents=this.__replayEvents.bind(this),this.__devtoolsIntrospect=this.__devtoolsIntrospect.bind(this),this.mountSlice=this.mountSlice.bind(this),this.unmountSlice=this.unmountSlice.bind(this),this.getAtPath=this.getAtPath.bind(this),this.emit=this.emit.bind(this),this.subscribe=this.subscribe.bind(this),this.connect=this.connect.bind(this),this.onEffect=this.onEffect.bind(this),this.onEvent=this.onEvent.bind(this),this.getState=this.getState.bind(this),this.registerEffect=this.registerEffect.bind(this),this.registerMiddleware=this.registerMiddleware.bind(this),this.registerReducer=this.registerReducer.bind(this),this.replaceMiddleware=this.replaceMiddleware.bind(this),this.replaceEffects=this.replaceEffects.bind(this),this.replaceReducers=this.replaceReducers.bind(this),this.hotReplace=this.hotReplace.bind(this)}dispose(){this.eventCleanupTimer&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null),this.processedEvents.clear(),this.effects.clear(),this.patternEffects.clear(),this.effectMeta=new WeakMap,this.listeners.clear(),this.committedEventSubscribers.clear(),this.uncommittedEventSubscribers.clear(),this.allEventSubscribers.clear(),this.instrumentObservers.clear(),this.connectorBus.clear(),this.reducerBus.clear(),this.patternReducers.clear(),this.sliceUnsubs.clear(),this.changedPathSink=null}fingerprint(e,t,r){const n=`${e}::${t}`;try{if(r==null)return`${n}::null`;if(typeof r!="object")return`${n}::${String(r)}`;const s=JSON.stringify(r);return`${n}::${s}`}catch{return`${n}::${Date.now()}::${Math.random()}`}}shouldDedupe(e,t){const r=Date.now(),n=this.processedEvents.get(e);return n!==void 0&&r-n<t?(this.dedupCount++,!0):(this.processedEvents.set(e,r),this.ensureCleanupTimer(),this.processedEvents.size>this.dedupConfig.maxCacheSize&&this.pruneProcessedEvents(r),!1)}ensureCleanupTimer(){this.eventCleanupTimer===null&&(this.eventCleanupTimer=setInterval(()=>{this.pruneProcessedEvents(Date.now())},5e3),this.eventCleanupTimer.unref?.())}pruneProcessedEvents(e){const t=Math.max(this.dedupConfig.windowMs,w),r=e-t*2;for(const[n,s]of this.processedEvents)s<r&&this.processedEvents.delete(n);this.processedEvents.size===0&&this.eventCleanupTimer!==null&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null)}matchesWhen(e,t){return!e||"any"in e&&e.any===!0?!0:"keys"in e?e.keys.some(([r,n])=>t.channel===r&&t.type===n):"channel"in e?t.channel===e.channel:"channels"in e?e.channels.includes(t.channel):!1}getMiddlewareFunction(e){return typeof e=="function"?e:e.middleware}getMiddlewareWhen(e){if(typeof e!="function")return e.when}async notifyEffects(e){const t=`${String(e.channel)}::${String(e.type)}`,r=this.effects.get(t);if(r&&r.size>0)for(const n of[...r])try{await n(e,this.getState,this.emit)}catch(s){console.error("Effect error:",s),this.onEffectError?.(s,e)}for(const{effect:n,when:s}of this.patternEffects)if(this.matchesWhen(s,e))try{await n(e,this.getState,this.emit)}catch(c){console.error("Effect error:",c),this.onEffectError?.(c,e)}}notifyEventSubscribers(e,t){const r=`${String(e.channel)}::${String(e.type)}`,s=(t==="committed"?this.committedEventSubscribers:this.uncommittedEventSubscribers).get(r);if(s?.size)for(const i of[...s])this.invokeEventSubscriber(i,e,t);const c=this.allEventSubscribers.get(r);if(c?.size)for(const i of[...c])this.invokeEventSubscriber(i,e,t)}invokeEventSubscriber(e,t,r){try{const n=e(t,this.getState,this.emit,r);n&&typeof n.then=="function"&&n.catch(s=>console.error("Event subscription error:",s))}catch(n){console.error("Event subscription error:",n)}}forwardEvent(e,t){const r=this.state[e],n=this.reducers[e].reduce(r,t);if(r===n)return!1;const s=g(r,n).filter(Boolean);if(s.length===0)return!1;const c=b(n);if(this.state={...this.state,[e]:c},this.changedPathSink)for(const o of s)this.changedPathSink.push(o?`${e}.${o}`:e);const i=new Set;for(const o of s)for(const f of v.buildAncestorPaths(o))i.add(f);for(const o of i){const f=this.getAtPath(r,o),h=this.getAtPath(c,o);this.connectorBus.emit(e,o,{oldValue:f,newValue:h,path:o})}return!0}__devtoolsIntrospect(){const e=Object.keys(this.reducers).map(i=>{const o=this.patternReducers.get(i);return{name:i,when:o}}),t=[];for(const[i,o]of this.effects){if(o.size===0)continue;const[f,h]=i.split("::");for(const l of o){const u=this.effectMeta.get(l);t.push({channel:f,type:h,name:u?.name,description:u?.description})}}for(const i of this.patternEffects){const o=this.effectMeta.get(i.effect);t.push({channel:"*",type:"*",name:o?.name,description:o?.description})}const r=[];for(const i of this.middleware)typeof i=="function"?r.push({name:i.name||void 0}):r.push({name:i.meta?.name,description:i.meta?.description,when:i.when});const n=[];for(const i of this.connectorBus.__introspect())for(let o=0;o<i.count;o++)n.push({reducer:i.channel,property:i.type});const s=[];for(const[i,o]of this.committedEventSubscribers){if(o.size===0)continue;const[f,h]=i.split("::");for(let l=0;l<o.size;l++)s.push({channel:f,type:h,phase:"committed"})}for(const[i,o]of this.uncommittedEventSubscribers){if(o.size===0)continue;const[f,h]=i.split("::");for(let l=0;l<o.size;l++)s.push({channel:f,type:h,phase:"uncommitted"})}for(const[i,o]of this.allEventSubscribers){if(o.size===0)continue;const[f,h]=i.split("::");for(let l=0;l<o.size;l++)s.push({channel:f,type:h,phase:"all"})}const c=this.listeners.size;return{reducers:e,effects:t,middleware:r,atomic:n,event:s,coarse:c,dedupHits:this.dedupCount,queueDepth:this.reduceQueue.length+this.inFlightEffects}}__applyExternalState(e){if(!this.replayEnabled){console.warn("[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");return}const t=this.state,r=e,n={...this.state};let s=!1;Object.keys(this.reducers).forEach(c=>{const i=t?.[c],o=r?.[c];if(o===void 0){process.env.NODE_ENV!=="production"&&console.warn(`[yoltra] External state is missing slice "${String(c)}"; retaining its current value. Time-travel snapshots should contain all slices.`);return}if(i===o)return;const f=b(o);n[c]=f,s=!0;const h=g(i,o).filter(Boolean);if(h.length===0)return;const l=new Set;for(const u of h)for(const p of v.buildAncestorPaths(u))l.add(p);for(const u of l){const p=this.getAtPath(i,u),y=this.getAtPath(f,u);this.connectorBus.emit(c,u,{oldValue:p,newValue:y,path:u})}}),s&&(this.state=n),s&&this.listeners.forEach(c=>c())}__replayEvents(e,t){if(!this.replayEnabled)throw new Error("[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");this.__applyExternalState(e);for(const r of t){const n=r,s=this.state;this.reducerBus.emit(n.channel,n.type,n.payload);for(const[o,f]of this.patternReducers)this.matchesWhen(f,n)&&this.forwardEvent(o,n);const c=this.state,i=s!==c;this.notifyEventSubscribers(n,"committed"),i&&this.listeners.forEach(o=>o())}}async emit(e,t,r,n){const s=n?.dedupKey,c=this.dedupConfig.windowMs;if(c>0||s!==void 0){const h=s!==void 0&&c<=0?w:c,l=s!==void 0?`${e}::${t}::#${s}`:this.fingerprint(e,t,r);if(this.shouldDedupe(l,h))return}const i=crypto.randomUUID();let o;const f=new Promise(h=>{o=h});return this.reduceQueue.push({channel:e,type:t,payload:r,id:i,resolve:o}),this.drainReduce(),f}drainReduce(){if(!this.isReducing){this.isReducing=!0;try{for(;this.reduceQueue.length>0;){const{channel:e,type:t,payload:r,id:n,resolve:s}=this.reduceQueue.shift(),c={channel:e,type:t,payload:r,id:n},i=this.instrumentObservers.size>0,o=i?this.state:void 0,f=[];i&&(this.changedPathSink=f);const h=i?S():0;let l=!1;try{l=this.applyEventSync(c)}catch(u){console.error("Emit reduce error:",u)}finally{i&&(this.changedPathSink=null)}i&&this.emitInstrumentation(c,l,f,o,S()-h),this.runEventEffects(c,l,s)}}finally{this.isReducing=!1}}}applyEventSync(e){for(const n of this.middleware){const s=this.getMiddlewareWhen(n);if(!this.matchesWhen(s,e))continue;const c=this.getMiddlewareFunction(n);let i;try{i=c(this.state,e,this.emit)}catch(o){console.error("Middleware error:",o),i=!1}if(!i)return this.notifyEventSubscribers(e,"uncommitted"),!1}const t=this.state;this.reducerBus.emit(e.channel,e.type,e.payload);for(const[n,s]of this.patternReducers)this.matchesWhen(s,e)&&this.forwardEvent(n,e);const r=t!==this.state;return this.notifyEventSubscribers(e,"committed"),r&&this.listeners.forEach(n=>n()),!0}async runEventEffects(e,t,r){this.inFlightEffects++;try{t&&await this.notifyEffects(e)}catch(n){console.error("Effect error:",n)}finally{this.inFlightEffects--,r()}}instrument(e){return this.instrumentObservers.add(e),()=>{this.instrumentObservers.delete(e)}}emitInstrumentation(e,t,r,n,s){const c={},i={};for(const f of r)c[f]=this.getAtPath(n,f),i[f]=this.getAtPath(this.state,f);const o={event:{id:e.id,channel:e.channel,type:e.type,payload:e.payload},committed:t,changedPaths:r,prevValues:c,nextValues:i,reduceTimeMs:s};for(const f of[...this.instrumentObservers])try{f(o)}catch(h){console.error("Instrumentation observer error:",h)}}connect(e,t){return this.connectorBus.on(e.reducer,e.property,t)}onEvent(e,t,r,n="committed"){const s=`${e}::${String(t)}`,c=n==="committed"?this.committedEventSubscribers:n==="uncommitted"?this.uncommittedEventSubscribers:this.allEventSubscribers;return c.has(s)||c.set(s,new Set),c.get(s).add(r),()=>{const i=c.get(s);i&&(i.delete(r),i.size===0&&c.delete(s))}}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}getState(){return this.state}registerMiddleware(e){return this.middleware.push(e),()=>{const t=this.middleware.indexOf(e);t!==-1&&this.middleware.splice(t,1)}}registerReducer(e,t){if(e in this.reducers)throw new Error(`Reducer ${e} already exists`);return this.mountSlice(e,t,{preserveState:!1}),this.listeners.forEach(r=>r()),()=>{this.unmountSlice(e,{deleteState:!0}),this.listeners.forEach(r=>r())}}registerEffect(e){const{effect:t,meta:r,when:n}=e,s=[];if(r&&this.effectMeta.set(t,r),n&&("any"in n&&n.any===!0||"channel"in n||"channels"in n)){const o={effect:t,when:n};return this.patternEffects.add(o),()=>{this.patternEffects.delete(o)}}const i=this.normalizeEventKeys(e);if(i.length===0&&!n&&!e.events){const o={effect:t,when:{any:!0}};return this.patternEffects.add(o),()=>{this.patternEffects.delete(o)}}for(const[o,f]of i){const h=`${String(o)}::${String(f)}`;this.effects.has(h)||this.effects.set(h,new Set),this.effects.get(h).add(t),s.push(()=>{const l=this.effects.get(h);l&&(l.delete(t),l.size===0&&this.effects.delete(h))})}return()=>{for(const o of s)o()}}onEffect(e,t,r){const n=async(s,c,i)=>{if(s.channel!==e||s.type!==t)return;const o=s;return r(o.payload,c,i,o)};return this.registerEffect({events:[[e,t]],effect:n})}replaceMiddleware(e){this.middleware.length=0;for(const t of e)this.middleware.push(t)}replaceEffects(e){this.effects.clear(),this.patternEffects.clear();for(const t of e)this.registerEffect(t)}replaceReducers(e,t={}){const r=t.preserveState!==!1,n=new Set(Object.keys(this.reducers)),s=Object.entries(e),c=new Set(s.map(([i])=>i));for(const i of n)c.has(i)||this.unmountSlice(i,{deleteState:!0});for(const[i,o]of s)n.has(i)?(this.unmountSlice(i,{deleteState:!1}),this.mountSlice(i,o,{preserveState:r})):this.mountSlice(i,o,{preserveState:!1})}hotReplace(e){e.middleware&&this.replaceMiddleware(e.middleware),e.effects&&this.replaceEffects(e.effects),e.reducer&&this.replaceReducers(e.reducer,{preserveState:e.preserveState})}mountSlice(e,t,r){const n=e,{events:s,reducer:c,state:i,when:o}=t;if(this.reducers[e]=new z(c),(!r.preserveState||this.state[n]===void 0)&&(this.state[n]=b(structuredClone(i))),o&&("any"in o&&o.any===!0||"channel"in o||"channels"in o)){this.patternReducers.set(e,o),this.sliceUnsubs.set(n,[]);return}const h=this.normalizeEventKeys(t);if(h.length===0&&!o&&!s){this.patternReducers.set(e,{any:!0}),this.sliceUnsubs.set(n,[]);return}const l=[];for(const[u,p]of h){const y=this.reducerBus.on(u,p,m=>{const O={channel:u,type:p,payload:m,id:crypto.randomUUID()};this.forwardEvent(e,O)});l.push(y)}this.sliceUnsubs.set(n,l)}unmountSlice(e,t){const r=e;this.patternReducers.delete(e);const n=this.sliceUnsubs.get(r);if(n){for(const s of n)try{s()}catch(c){console.error(`[Store error]: ${c}`)}this.sliceUnsubs.delete(r)}delete this.reducers[e],t.deleteState&&delete this.state[r]}normalizeEventKeys(e){if(e.when){const t=e.when;if("any"in t&&t.any===!0)return[];if("keys"in t)return t.keys;if("channel"in t)return[];if("channels"in t)return[]}return e.events?e.events:[]}getAtPath(e,t){if(!t)return e;const n=(t[0]==="."?t.slice(1):t).split(".");let s=e;for(const c of n){if(s==null)return;s=s[c]}return s}static buildAncestorPaths(e){if(!e)return[];const r=(e[0]==="."?e.slice(1):e).split("."),n=[];for(let s=0;s<r.length;s++)n.push(r.slice(0,s+1).join("."));return n}}function _(a){return new v({name:a.name,reducer:a.reducer??{},middleware:a.middleware??[],effects:a.effects??[],dedupWindowMs:a.dedupWindowMs,devtools:a.devtools,onEffectError:a.onEffectError})}const $=a=>(e,t)=>t.map(r=>[e,r]),x=()=>a=>a;exports.EventBus=M;exports.LooseEventBus=P;exports.Reducer=z;exports.Store=v;exports.createStore=_;exports.detectChangedProps=g;exports.eventKeys=x;exports.freezeState=E;exports.typedEvents=$;
|
|
10
|
+
"use strict";var K=Object.defineProperty;var W=(o,e,t)=>e in o?K(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var p=(o,e,t)=>W(o,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class A{constructor(){p(this,"handlers",new Map)}on(e,t,s){let n=this.handlers.get(e);n||(n=new Map,this.handlers.set(e,n));let i=n.get(t);return i||(i=new Set,n.set(t,i)),i.add(s),()=>this.off(e,t,s)}off(e,t,s){const n=this.handlers.get(e);if(!n)return;const i=n.get(t);i&&(i.delete(s),i.size===0&&n.delete(t),n.size===0&&this.handlers.delete(e))}emit(e,t,s,n){const i=this.handlers.get(e);if(!i)return;const d=i.get(t);if(!(!d||d.size===0))for(const a of[...d])try{a(s,n)}catch(r){console.error("EventBus handler error:",r)}}clear(){this.handlers.clear()}}class N{constructor(){p(this,"handlers",new Map);p(this,"patternHandlers",new Map);p(this,"patternIndex",new Map)}on(e,t,s){const n=String(t);if(this.isPattern(n)){const i=n;this.patternHandlers.has(e)||this.patternHandlers.set(e,new Map);const d=this.patternHandlers.get(e);return d.has(i)||(d.set(i,[]),this.indexPattern(e,i)),d.get(i).push(s),()=>this.offPattern(e,i,s)}else{const i=this.normalizeTypeKey(n);this.handlers.has(e)||this.handlers.set(e,new Map);const d=this.handlers.get(e);return d.has(i)||d.set(i,[]),d.get(i).push(s),()=>this.offExactNormalized(e,i,s)}}off(e,t,s){const n=this.normalizeTypeKey(String(t));this.offExactNormalized(e,n,s)}offExactNormalized(e,t,s){const n=this.handlers.get(e);if(!n)return;const i=n.get(t);if(!i)return;const d=i.indexOf(s);d!==-1&&i.splice(d,1),i.length===0&&n.delete(t),n.size===0&&this.handlers.delete(e)}offPattern(e,t,s){const n=this.patternHandlers.get(e);if(!n)return;const i=n.get(t);if(!i)return;const d=i.indexOf(s);d!==-1&&i.splice(d,1),i.length===0&&(n.delete(t),this.unindexPattern(e,t)),n.size===0&&(this.patternHandlers.delete(e),this.patternIndex.delete(e))}emit(e,t,s){const n=String(t),i=this.normalizeTypeKey(n),d=this.handlers.get(e)?.get(i)??[],a=this.matchingPatternHandlers(e,n),r=new Set,f=c=>{for(const u of[...c])if(!r.has(u)){r.add(u);try{u(s)}catch(l){console.error(l);continue}}};f(d);for(const c of a)f(c)}emitWith(e,t,s){const n=String(t),i=this.normalizeTypeKey(n),d=this.handlers.get(e)?.get(i)??[],a=this.matchingPatternHandlers(e,n);if(d.length===0&&a.length===0)return;const r=s(),f=new Set,c=u=>{for(const l of[...u])if(!f.has(l)){f.add(l);try{l(r)}catch(y){console.error(y);continue}}};c(d);for(const u of a)c(u)}isPattern(e){return e.includes("*")}normalizeTypeKey(e){return e.replace(/^\./,"")}splitPath(e){return this.normalizeTypeKey(e).split(".").filter(Boolean)}indexPattern(e,t){let s=this.patternIndex.get(e);s===void 0&&(s={byHead:new Map,anyHead:[]},this.patternIndex.set(e,s));const n=this.splitPath(t),i={pattern:t,segments:n},d=n[0];if(d===void 0||d==="*"||d==="**"){s.anyHead.push(i);return}const a=s.byHead.get(d);a===void 0?s.byHead.set(d,[i]):a.push(i)}unindexPattern(e,t){const s=this.patternIndex.get(e);if(s===void 0)return;const n=this.splitPath(t)[0],i=n===void 0||n==="*"||n==="**"?s.anyHead:s.byHead.get(n);if(i===void 0)return;const d=i.findIndex(a=>a.pattern===t);d!==-1&&i.splice(d,1),i.length===0&&i!==s.anyHead&&n!==void 0&&s.byHead.delete(n)}matchingPatternHandlers(e,t){const s=this.patternHandlers.get(e),n=this.patternIndex.get(e);if(s===void 0||s.size===0||n===void 0)return[];const i=this.splitPath(t),d=[],a=f=>{for(const c of f){if(!this.matchSegments(c.segments,i))continue;const u=s.get(c.pattern);u!==void 0&&d.push(u)}},r=i[0];if(r!==void 0){const f=n.byHead.get(r);f!==void 0&&a(f)}return a(n.anyHead),d}matchSegments(e,t){let s=0,n=0,i=-1,d=0;for(;n<t.length;)if(s<e.length&&(e[s]==="*"||e[s]===t[n]))s++,n++;else if(s<e.length&&e[s]==="**")i=s,d=n,s++;else if(i!==-1)s=i+1,n=++d;else return!1;for(;s<e.length&&e[s]==="**";)s++;return s===e.length}clear(){this.handlers.clear(),this.patternHandlers.clear(),this.patternIndex.clear()}__introspect(){const e=[];for(const[t,s]of this.handlers)for(const[n,i]of s)i.length>0&&e.push({channel:t,type:n,count:i.length});for(const[t,s]of this.patternHandlers)for(const[n,i]of s)i.length>0&&e.push({channel:t,type:n,count:i.length});return e}}class D{constructor(e){p(this,"_reduce");this._reduce=e}reduce(e,t){return this._reduce(e,t)}}const x=new Set;function M(o,e){const t=o?`${o}.${e}`:e;x.has(t)||(x.add(t),console.warn(`[yoltra] State key "${e}"${o?` under "${o}"`:""} contains a dot. Paths are dotted, so this key is indistinguishable from nested objects of the same name: a subscription to "${t}" may match the wrong value, and DevTools patches for it will address the wrong node. Rename the key, or nest it.`))}function k(o,e,t="",s=new Map){const n=[];return $(o,e,t,s,n),n}function $(o,e,t,s,n){if(o===e)return;if(typeof o!="object"||typeof e!="object"||o===null||e===null){if(typeof o=="number"&&Number.isNaN(o)&&Number.isNaN(e))return;n.push(t);return}if(o instanceof Date&&e instanceof Date){o.getTime()!==e.getTime()&&n.push(t);return}if(o instanceof RegExp&&e instanceof RegExp){(o.source!==e.source||e.flags!==o.flags)&&n.push(t);return}if(o instanceof Map||e instanceof Map){n.push(t);return}if(o instanceof Set||e instanceof Set){n.push(t);return}const i=o,d=e,a=s.get(i);if(a?.has(d))return;const r=a??new Set;r.add(d),a||s.set(i,r);try{const f=Array.isArray(o),c=Array.isArray(e);if(f!==c){n.push(t);return}if(f){const h=o,m=e;h.length!==m.length&&t&&n.push(t);const g=Math.min(h.length,m.length);for(let w=0;w<g;w++)h[w]!==m[w]&&$(h[w],m[w],t?`${t}.${w}`:`${w}`,s,n);for(let w=g;w<Math.max(h.length,m.length);w++)n.push(t?`${t}.${w}`:`${w}`);return}const u=Object.keys(o),l=Object.keys(e);if(u.length===0&&l.length===0){n.push(t);return}let y=u.length===l.length;if(y){for(let h=0;h<l.length;h++)if(!Object.prototype.hasOwnProperty.call(o,l[h])){y=!1;break}}if(y){for(const h of l)o[h]!==e[h]&&(process.env.NODE_ENV!=="production"&&h.includes(".")&&M(t,h),$(o[h],e[h],t?`${t}.${h}`:h,s,n));return}for(const h of l){const m=Object.prototype.hasOwnProperty.call(o,h);if(m&&o[h]===e[h])continue;process.env.NODE_ENV!=="production"&&h.includes(".")&&M(t,h);const g=t?`${t}.${h}`:h;if(!m){n.push(g);continue}$(o[h],e[h],g,s,n)}for(const h of u)Object.prototype.hasOwnProperty.call(e,h)||(process.env.NODE_ENV!=="production"&&h.includes(".")&&M(t,h),n.push(t?`${t}.${h}`:h))}finally{r.delete(d),r.size===0&&s.delete(i)}}function v(o,e=new WeakSet,t){if(o===null||typeof o!="object"||e.has(o)||(t!==void 0&&o===t.watch&&t.onFound(),Object.isFrozen(o)))return o;if(e.add(o),Array.isArray(o)){const s=o;for(let n=0;n<s.length;n++)s[n]=v(s[n],e,t);return Object.freeze(s)}for(const s of Object.getOwnPropertyNames(o)){const n=Object.getOwnPropertyDescriptor(o,s);!n||!("value"in n)||(o[s]=v(o[s],e,t))}for(const s of Object.getOwnPropertySymbols(o)){const n=Object.getOwnPropertyDescriptor(o,s);!n||!("value"in n)||(o[s]=v(o[s],e,t))}return Object.freeze(o)}function j(o,e){try{return structuredClone(e)}catch(t){throw new Error(`[yoltra] Initial state for slice "${String(o)}" could not be copied: ${t instanceof Error?t.message:String(t)}. State must be structured-cloneable — functions, class instances and DOM nodes are not. Keep behaviour out of state and store plain data.`)}}function P(o,e){return process.env.NODE_ENV==="production"?o:v(o,new WeakSet,e)}const z=100,I=()=>typeof performance<"u"&&typeof performance.now=="function"?performance.now():Date.now();class S{constructor(e){p(this,"name");p(this,"middleware");p(this,"reducers");p(this,"state");p(this,"reducerBus");p(this,"connectorBus");p(this,"listeners",new Set);p(this,"effects",new Map);p(this,"patternEffects",new Set);p(this,"committedEventSubscribers",new Map);p(this,"uncommittedEventSubscribers",new Map);p(this,"allEventSubscribers",new Map);p(this,"sliceUnsubs",new Map);p(this,"patternReducers",new Map);p(this,"replayEnabled");p(this,"idFactory");p(this,"onEffectError");p(this,"onReducerError");p(this,"warnedPayloadAliases",new Set);p(this,"reduceQueue",[]);p(this,"isReducing",!1);p(this,"instrumentObservers",new Set);p(this,"changedPathSink",null);p(this,"inFlightEffects",0);p(this,"processedEvents",new Map);p(this,"dedupCount",0);p(this,"effectMeta",new WeakMap);p(this,"dedupConfig");p(this,"eventCleanupTimer",null);if(this.name=e.name??"yoltra Store",this.reducerBus=new A,this.connectorBus=new N,this.middleware=[...e.middleware??[]],this.reducers={},this.state={},this.replayEnabled=e.devtools?.allowReplay??!1,this.idFactory=e.idFactory??(()=>crypto.randomUUID()),this.onEffectError=e.onEffectError,this.onReducerError=e.onReducerError,this.dedupConfig={windowMs:e.dedupWindowMs??0,maxCacheSize:1e3},Object.entries(e.reducer).forEach(([t,s])=>{this.mountSlice(t,s,{preserveState:!1})}),e.effects?.length)for(const t of e.effects)this.registerEffect(t);this.dispose=this.dispose.bind(this),this.notifyEffects=this.notifyEffects.bind(this),this.forwardEvent=this.forwardEvent.bind(this),this.__applyExternalState=this.__applyExternalState.bind(this),this.__replayEvents=this.__replayEvents.bind(this),this.__devtoolsIntrospect=this.__devtoolsIntrospect.bind(this),this.mountSlice=this.mountSlice.bind(this),this.unmountSlice=this.unmountSlice.bind(this),this.getAtPath=this.getAtPath.bind(this),this.emit=this.emit.bind(this),this.subscribe=this.subscribe.bind(this),this.connect=this.connect.bind(this),this.onEffect=this.onEffect.bind(this),this.onEvent=this.onEvent.bind(this),this.getState=this.getState.bind(this),this.registerEffect=this.registerEffect.bind(this),this.registerMiddleware=this.registerMiddleware.bind(this),this.registerReducer=this.registerReducer.bind(this),this.replaceMiddleware=this.replaceMiddleware.bind(this),this.replaceEffects=this.replaceEffects.bind(this),this.replaceReducers=this.replaceReducers.bind(this),this.hotReplace=this.hotReplace.bind(this)}dispose(){this.eventCleanupTimer&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null),this.processedEvents.clear(),this.effects.clear(),this.patternEffects.clear(),this.effectMeta=new WeakMap,this.listeners.clear(),this.committedEventSubscribers.clear(),this.uncommittedEventSubscribers.clear(),this.allEventSubscribers.clear(),this.instrumentObservers.clear(),this.connectorBus.clear(),this.reducerBus.clear(),this.patternReducers.clear(),this.sliceUnsubs.clear(),this.changedPathSink=null}fingerprint(e,t,s){const n=`${e}::${t}`;try{if(s==null)return`${n}::null`;if(typeof s!="object")return`${n}::${String(s)}`;const i=JSON.stringify(s);return`${n}::${i}`}catch{return`${n}::${Date.now()}::${Math.random()}`}}shouldDedupe(e,t){const s=Date.now(),n=this.processedEvents.get(e);return n!==void 0&&s-n<t?(this.dedupCount++,!0):(this.processedEvents.set(e,s),this.ensureCleanupTimer(),this.processedEvents.size>this.dedupConfig.maxCacheSize&&this.pruneProcessedEvents(s),!1)}ensureCleanupTimer(){this.eventCleanupTimer===null&&(this.eventCleanupTimer=setInterval(()=>{this.pruneProcessedEvents(Date.now())},5e3),this.eventCleanupTimer.unref?.())}pruneProcessedEvents(e){const t=Math.max(this.dedupConfig.windowMs,z),s=e-t*2;for(const[n,i]of this.processedEvents)i<s&&this.processedEvents.delete(n);this.processedEvents.size===0&&this.eventCleanupTimer!==null&&(clearInterval(this.eventCleanupTimer),this.eventCleanupTimer=null)}matchesWhen(e,t){return!e||"any"in e&&e.any===!0?!0:"keys"in e?e.keys.some(([s,n])=>t.channel===s&&t.type===n):"channel"in e?t.channel===e.channel:"channels"in e?e.channels.includes(t.channel):!1}getMiddlewareFunction(e){return typeof e=="function"?e:e.middleware}getMiddlewareWhen(e){if(typeof e!="function")return e.when}async notifyEffects(e){const t=`${String(e.channel)}::${String(e.type)}`,s=this.effects.get(t);if(s&&s.size>0)for(const n of[...s])try{await n(e,this.getState,this.emit)}catch(i){console.error("Effect error:",i),this.onEffectError?.(i,e)}for(const{effect:n,when:i}of this.patternEffects)if(this.matchesWhen(i,e))try{await n(e,this.getState,this.emit)}catch(d){console.error("Effect error:",d),this.onEffectError?.(d,e)}}notifyEventSubscribers(e,t){const s=`${String(e.channel)}::${String(e.type)}`,i=(t==="committed"?this.committedEventSubscribers:this.uncommittedEventSubscribers).get(s);if(i?.size)for(const a of[...i])this.invokeEventSubscriber(a,e,t);const d=this.allEventSubscribers.get(s);if(d?.size)for(const a of[...d])this.invokeEventSubscriber(a,e,t)}invokeEventSubscriber(e,t,s){try{const n=e(t,this.getState,this.emit,s);n&&typeof n.then=="function"&&n.catch(i=>console.error("Event subscription error:",i))}catch(n){console.error("Event subscription error:",n)}}forwardEventGuarded(e,t){try{return this.forwardEvent(e,t)}catch(s){return console.error(`Reducer error in slice "${e}":`,s),this.onReducerError?.(s,t,e),!1}}forwardEvent(e,t){const s=this.state[e],n=this.reducers[e].reduce(s,t);if(s===n)return!1;const i=k(s,n).filter(Boolean);if(i.length===0)return!1;const d=t.payload,a=process.env.NODE_ENV!=="production"&&d!==null&&typeof d=="object"?{watch:d,onFound:()=>{const c=`${e}:${t.channel}:${t.type}`;this.warnedPayloadAliases.has(c)||(this.warnedPayloadAliases.add(c),console.warn(`[yoltra] Slice "${e}" stored the payload of "${t.channel}/${t.type}" by reference. It is now frozen along with the rest of the state, so the emitter mutating it later will throw in development and silently corrupt state in production. Copy the payload in the reducer instead.`))}}:void 0,r=P(n,a);if(this.state={...this.state,[e]:r},this.changedPathSink)for(const c of i)this.changedPathSink.push(c?`${e}.${c}`:e);const f=new Set;for(const c of i)for(const u of S.buildAncestorPaths(c))f.add(u);for(const c of f)this.connectorBus.emitWith(e,c,()=>({oldValue:this.getAtPath(s,c),newValue:this.getAtPath(r,c),path:c}));return!0}__devtoolsIntrospect(){const e=Object.keys(this.reducers).map(a=>{const r=this.patternReducers.get(a);return{name:a,when:r}}),t=[];for(const[a,r]of this.effects){if(r.size===0)continue;const[f,c]=a.split("::");for(const u of r){const l=this.effectMeta.get(u);t.push({channel:f,type:c,name:l?.name,description:l?.description})}}for(const a of this.patternEffects){const r=this.effectMeta.get(a.effect);t.push({channel:"*",type:"*",name:r?.name,description:r?.description})}const s=[];for(const a of this.middleware)typeof a=="function"?s.push({name:a.name||void 0}):s.push({name:a.meta?.name,description:a.meta?.description,when:a.when});const n=[];for(const a of this.connectorBus.__introspect())for(let r=0;r<a.count;r++)n.push({reducer:a.channel,property:a.type});const i=[];for(const[a,r]of this.committedEventSubscribers){if(r.size===0)continue;const[f,c]=a.split("::");for(let u=0;u<r.size;u++)i.push({channel:f,type:c,phase:"committed"})}for(const[a,r]of this.uncommittedEventSubscribers){if(r.size===0)continue;const[f,c]=a.split("::");for(let u=0;u<r.size;u++)i.push({channel:f,type:c,phase:"uncommitted"})}for(const[a,r]of this.allEventSubscribers){if(r.size===0)continue;const[f,c]=a.split("::");for(let u=0;u<r.size;u++)i.push({channel:f,type:c,phase:"all"})}const d=this.listeners.size;return{reducers:e,effects:t,middleware:s,atomic:n,event:i,coarse:d,dedupHits:this.dedupCount,queueDepth:this.reduceQueue.length+this.inFlightEffects}}__applyExternalState(e){if(!this.replayEnabled)throw new Error("[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");const t=this.state,s=e,n={...this.state};let i=!1;Object.keys(this.reducers).forEach(d=>{const a=t?.[d],r=s?.[d];if(r===void 0){process.env.NODE_ENV!=="production"&&console.warn(`[yoltra] External state is missing slice "${String(d)}"; retaining its current value. Time-travel snapshots should contain all slices.`);return}if(a===r)return;const f=P(r);n[d]=f,i=!0;const c=k(a,r).filter(Boolean);if(c.length===0)return;const u=new Set;for(const l of c)for(const y of S.buildAncestorPaths(l))u.add(y);for(const l of u){const y=this.getAtPath(a,l),h=this.getAtPath(f,l);this.connectorBus.emit(d,l,{oldValue:y,newValue:h,path:l})}}),i&&(this.state=n),i&&this.listeners.forEach(d=>d())}__replayEvents(e,t){if(!this.replayEnabled)throw new Error("[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })");this.__applyExternalState(e);for(const s of t){const n=s,i=this.state;this.reducerBus.emit(n.channel,n.type,n.payload,n);for(const[r,f]of this.patternReducers)this.matchesWhen(f,n)&&this.forwardEventGuarded(r,n);const d=this.state,a=i!==d;this.notifyEventSubscribers(n,"committed"),a&&this.listeners.forEach(r=>r())}}async emit(e,t,s,n){const i=n?.dedupKey,d=this.dedupConfig.windowMs;if(n?.skipDedup!==!0&&(d>0||i!==void 0)){const c=i!==void 0&&d<=0?z:d,u=i!==void 0?`${e}::${t}::#${i}`:this.fingerprint(e,t,s);if(this.shouldDedupe(u,c))return}const a=n?.id??this.idFactory();let r;const f=new Promise(c=>{r=c});return this.reduceQueue.push({channel:e,type:t,payload:s,id:a,meta:n?.meta,resolve:r}),this.drainReduce(),f}drainReduce(){if(!this.isReducing){this.isReducing=!0;try{for(;this.reduceQueue.length>0;){const{channel:e,type:t,payload:s,id:n,meta:i,resolve:d}=this.reduceQueue.shift(),a={channel:e,type:t,payload:s,id:n,...i!==void 0?{meta:i}:{}},r=this.instrumentObservers.size>0,f=r?this.state:void 0,c=r?[]:void 0;c!==void 0&&(this.changedPathSink=c);const u=r?I():0;let l=!1;try{l=this.applyEventSync(a)}catch(y){console.error("Emit reduce error:",y)}finally{r&&(this.changedPathSink=null)}r&&this.emitInstrumentation(a,l,c??[],f,I()-u),this.runEventEffects(a,l,d)}}finally{this.isReducing=!1}}}applyEventSync(e){for(const n of this.middleware){const i=this.getMiddlewareWhen(n);if(!this.matchesWhen(i,e))continue;const d=this.getMiddlewareFunction(n);let a;try{a=d(this.state,e,this.emit),process.env.NODE_ENV!=="production"&&typeof a?.then=="function"&&console.error(`[yoltra] Middleware for "${e.channel}/${e.type}" returned a Promise. Middleware is synchronous: a Promise is truthy, so this event was allowed without waiting and a "return false" inside it can never veto. Do the check synchronously, and put anything that must await in an effect.`)}catch(r){console.error("Middleware error:",r),a=!1}if(!a)return this.notifyEventSubscribers(e,"uncommitted"),!1}const t=this.state;this.reducerBus.emit(e.channel,e.type,e.payload,e);for(const[n,i]of this.patternReducers)this.matchesWhen(i,e)&&this.forwardEventGuarded(n,e);const s=t!==this.state;return this.notifyEventSubscribers(e,"committed"),s&&this.listeners.forEach(n=>n()),!0}async runEventEffects(e,t,s){this.inFlightEffects++;try{t&&await this.notifyEffects(e)}catch(n){console.error("Effect error:",n)}finally{this.inFlightEffects--,s()}}instrument(e){return this.instrumentObservers.add(e),()=>{this.instrumentObservers.delete(e)}}emitInstrumentation(e,t,s,n,i){const d={},a={};for(const f of s)d[f]=this.getAtPath(n,f),a[f]=this.getAtPath(this.state,f);const r={event:{id:e.id,channel:e.channel,type:e.type,payload:e.payload,...e.meta!==void 0?{meta:e.meta}:{}},committed:t,changedPaths:s,prevValues:d,nextValues:a,reduceTimeMs:i};for(const f of[...this.instrumentObservers])try{f(r)}catch(c){console.error("Instrumentation observer error:",c)}}connect(e,t){return this.connectorBus.on(e.reducer,e.property,t)}onEvent(e,t,s,n="committed"){const i=`${e}::${String(t)}`,d=n==="committed"?this.committedEventSubscribers:n==="uncommitted"?this.uncommittedEventSubscribers:this.allEventSubscribers;return d.has(i)||d.set(i,new Set),d.get(i).add(s),()=>{const a=d.get(i);a&&(a.delete(s),a.size===0&&d.delete(i))}}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}getState(){return this.state}registerMiddleware(e){return this.middleware.push(e),()=>{const t=this.middleware.indexOf(e);t!==-1&&this.middleware.splice(t,1)}}registerReducer(e,t){if(e in this.reducers)throw new Error(`Reducer ${e} already exists`);return this.mountSlice(e,t,{preserveState:!1}),this.listeners.forEach(s=>s()),()=>{this.unmountSlice(e,{deleteState:!0}),this.listeners.forEach(s=>s())}}registerEffect(e){const{effect:t,meta:s,when:n}=e,i=[];if(s&&this.effectMeta.set(t,s),n&&("any"in n&&n.any===!0||"channel"in n||"channels"in n)){const r={effect:t,when:n};return this.patternEffects.add(r),()=>{this.patternEffects.delete(r)}}const a=this.normalizeEventKeys(e);if(a.length===0&&!n){const r={effect:t,when:{any:!0}};return this.patternEffects.add(r),()=>{this.patternEffects.delete(r)}}for(const[r,f]of a){const c=`${String(r)}::${String(f)}`;this.effects.has(c)||this.effects.set(c,new Set),this.effects.get(c).add(t),i.push(()=>{const u=this.effects.get(c);u&&(u.delete(t),u.size===0&&this.effects.delete(c))})}return()=>{for(const r of i)r()}}onEffect(e,t,s){const n=async(i,d,a)=>{if(i.channel!==e||i.type!==t)return;const r=i;return s(r.payload,d,a,r)};return this.registerEffect({when:{keys:[[e,t]]},effect:n})}replaceMiddleware(e){this.middleware.length=0;for(const t of e)this.middleware.push(t)}replaceEffects(e){this.effects.clear(),this.patternEffects.clear();for(const t of e)this.registerEffect(t)}replaceReducers(e,t={}){const s=t.preserveState!==!1,n=new Set(Object.keys(this.reducers)),i=Object.entries(e),d=new Set(i.map(([a])=>a));for(const a of n)d.has(a)||this.unmountSlice(a,{deleteState:!0});for(const[a,r]of i)n.has(a)?(this.unmountSlice(a,{deleteState:!1}),this.mountSlice(a,r,{preserveState:s})):this.mountSlice(a,r,{preserveState:!1})}hotReplace(e){e.middleware&&this.replaceMiddleware(e.middleware),e.effects&&this.replaceEffects(e.effects),e.reducer&&this.replaceReducers(e.reducer,{preserveState:e.preserveState})}mountSlice(e,t,s){const n=e,{reducer:i,state:d,when:a}=t;if(this.reducers[e]=new D(i),(!s.preserveState||this.state[n]===void 0)&&(this.state={...this.state,[n]:P(j(n,d))}),a&&("any"in a&&a.any===!0||"channel"in a||"channels"in a)){this.patternReducers.set(e,a),this.sliceUnsubs.set(n,[]);return}const f=this.normalizeEventKeys(t);if(f.length===0&&!a){this.patternReducers.set(e,{any:!0}),this.sliceUnsubs.set(n,[]);return}const c=[];for(const[u,l]of f){const y=this.reducerBus.on(u,l,(h,m)=>{const g=m??{channel:u,type:l,payload:h,id:this.idFactory()};this.forwardEventGuarded(e,g)});c.push(y)}this.sliceUnsubs.set(n,c)}unmountSlice(e,t){const s=e;this.patternReducers.delete(e);const n=this.sliceUnsubs.get(s);if(n){for(const i of n)try{i()}catch(d){console.error(`[Store error]: ${d}`)}this.sliceUnsubs.delete(s)}if(delete this.reducers[e],t.deleteState){const{[s]:i,...d}=this.state;this.state=d}}normalizeEventKeys(e){if(e.when){const t=e.when;if("keys"in t)return t.keys}return[]}getAtPath(e,t){if(!t)return e;const n=(t[0]==="."?t.slice(1):t).split(".");let i=e;for(const d of n){if(i==null)return;i=i[d]}return i}static buildAncestorPaths(e){if(!e)return[];const s=(e[0]==="."?e.slice(1):e).split("."),n=[];for(let i=0;i<s.length;i++)n.push(s.slice(0,i+1).join("."));return n}}function F(o){return new S({name:o.name,reducer:o.reducer??{},middleware:o.middleware??[],effects:o.effects??[],dedupWindowMs:o.dedupWindowMs,idFactory:o.idFactory,devtools:o.devtools,onEffectError:o.onEffectError,onReducerError:o.onReducerError})}const V=o=>(e,t)=>t.map(s=>[e,s]),U=()=>o=>o,R=new Set;function L(o){const e=String(o);R.has(e)||(R.add(e),console.warn(`[yoltra] Entity id "${e}" contains a dot. Paths are dotted, so a subscription to "entities.${e}" is indistinguishable from one to a nested object of the same name. Use ids without dots.`))}function G(o,e){if(o.length!==e.length)return e;for(let t=0;t<o.length;t++)if(o[t]!==e[t])return e;return o}function Q(o={}){const e=o.selectId??(r=>r.id),{sortComparer:t}=o,s=(r,f)=>{if(t===void 0)return f;const c=[...f].sort((u,l)=>{const y=r.entities[u],h=r.entities[l];return y===void 0||h===void 0?0:t(y,h)});return G(f,c)},n=(r,f,c)=>{const u={...r,entities:f,ids:c};return{...u,ids:s(u,c)}},i=(r,f,c)=>{let u=null,l=null;for(const y of f){const h=e(y);process.env.NODE_ENV!=="production"&&String(h).includes(".")&&L(h);const m=(u??r.entities)[h];if(m!==void 0&&c==="add")continue;const g=m!==void 0&&c==="upsert"?{...m,...y}:y;u??(u={...r.entities}),u[h]=g,m===void 0&&(l??(l=[...r.ids]),l.push(h))}return u===null?r:n(r,u,l??r.ids)},d=(r,f)=>{let c=null;for(const{id:u,changes:l}of f){const y=(c??r.entities)[u];y!==void 0&&(c??(c={...r.entities}),c[u]={...y,...l})}return c===null?r:n(r,c,r.ids)},a=(r,f)=>{const c=new Set(f.filter(l=>r.entities[l]!==void 0));if(c.size===0)return r;const u={...r.entities};for(const l of c)delete u[l];return n(r,u,r.ids.filter(l=>!c.has(l)))};return{getInitialState(r){const f={ids:[],entities:{}};return r===void 0?f:{...f,...r}},addOne:(r,f)=>i(r,[f],"add"),addMany:(r,f)=>i(r,f,"add"),setOne:(r,f)=>i(r,[f],"set"),setMany:(r,f)=>i(r,f,"set"),setAll:(r,f)=>{const c={},u=[];for(const l of f){const y=e(l);c[y]===void 0&&u.push(y),c[y]=l}return n(r,c,u)},updateOne:(r,f)=>d(r,[f]),updateMany:(r,f)=>d(r,f),upsertOne:(r,f)=>i(r,[f],"upsert"),upsertMany:(r,f)=>i(r,f,"upsert"),removeOne:(r,f)=>a(r,[f]),removeMany:(r,f)=>a(r,f),removeAll:r=>r.ids.length===0?r:n(r,{},[]),selectIds:r=>r.ids,selectEntities:r=>r.entities,selectAll:r=>r.ids.map(f=>r.entities[f]),selectById:(r,f)=>r.entities[f],selectTotal:r=>r.ids.length,idsPath:"ids",pathTo:(r,f)=>f===void 0?`entities.${r}`:`entities.${r}.${f}`,anyField:r=>`entities.*.${r}`}}const E="$yoltra";function O(o,e={}){const t=e.maxNodes??1e5,s=e.sanitize,n=[],i=new Map;let d=0,a=!1;function r(c,u){if(s!==void 0&&(c=s(u,c)),d+=1,d>t)return a=!0,{[E]:"unsupported",kind:"truncated"};switch(typeof c){case"undefined":return{[E]:"undefined"};case"bigint":return{[E]:"bigint",value:c.toString()};case"number":return Number.isNaN(c)?{[E]:"nan"}:c===1/0?{[E]:"infinity",sign:1}:c===-1/0?{[E]:"infinity",sign:-1}:c;case"function":case"symbol":return n.push(u),{[E]:"unsupported",kind:typeof c};case"string":case"boolean":return c}if(c===null)return null;const l=c,y=i.get(l);if(y!==void 0)return{[E]:"ref",path:y};if(i.set(l,u),c instanceof Date)return{[E]:"date",iso:c.toISOString()};if(c instanceof RegExp)return{[E]:"regexp",source:c.source,flags:c.flags};if(c instanceof Error)return{[E]:"error",name:c.name,message:c.message};if(c instanceof Map){const m=[];let g=0;for(const[w,H]of c)m.push([r(w,`${u}/@k${g}`),r(H,`${u}/${g}`)]),g+=1;return{[E]:"map",entries:m}}if(c instanceof Set){const m=[];let g=0;for(const w of c)m.push(r(w,`${u}/${g}`)),g+=1;return{[E]:"set",values:m}}if(Array.isArray(c))return c.map((m,g)=>r(m,`${u}/${g}`));const h={};for(const[m,g]of Object.entries(c))h[m]=r(g,`${u}/${B(m)}`);return E in h?{[E]:"escaped",value:h}:h}return{value:r(o,""),report:{truncated:a,unsupported:n}}}function T(o){const e=new Map,t=[];function s(d,a){if(d===null||typeof d!="object")return d;if(Array.isArray(d)){const f=[];return e.set(a,f),d.forEach((c,u)=>{if(_(c)){t.push({target:f,key:u,path:c.path}),f[u]=void 0;return}f[u]=s(c,`${a}/${u}`)}),f}if(typeof d[E]=="string"){const f=d;switch(f[E]){case"undefined":return;case"nan":return Number.NaN;case"infinity":return f.sign===1?1/0:-1/0;case"bigint":return BigInt(f.value);case"date":return new Date(f.iso);case"regexp":return new RegExp(f.source,f.flags);case"error":{const c=new Error(f.message);return c.name=f.name,c}case"unsupported":return;case"ref":return;case"map":{const c=new Map;return e.set(a,c),f.entries.forEach(([u,l],y)=>{c.set(s(u,`${a}/@k${y}`),s(l,`${a}/${y}`))}),c}case"set":{const c=new Set;return e.set(a,c),f.values.forEach((u,l)=>c.add(s(u,`${a}/${l}`))),c}case"escaped":return n(f.value,a);default:return}}return n(d,a)}function n(d,a){const r={};e.set(a,r);for(const[f,c]of Object.entries(d)){const u=`${a}/${B(f)}`;if(_(c)){t.push({target:r,key:f,path:c.path}),r[f]=void 0;continue}r[f]=s(c,u)}return r}const i=s(o,"");e.set("",i);for(const{target:d,key:a,path:r}of t)d[a]=e.get(r);return i}function _(o){return o!==null&&typeof o=="object"&&o[E]==="ref"&&typeof o.path=="string"}function B(o){return o.replace(/~/g,"~0").replace(/\//g,"~1")}function J(o,e,t={}){let s=t.maxNodes??1e5;for(let n=0;n<8;n+=1){const{value:i,report:d}=O(o,{...t,maxNodes:s});let a;try{a=JSON.stringify(i)?.length??0}catch{a=Number.POSITIVE_INFINITY}if(a<=e)return d.truncated?{value:i,truncated:!0,note:`State was too large to send in full; parts beyond ${s} nodes are omitted.`}:{value:i,truncated:!1};const r=Math.floor(s*e*.8/a);if(s=Math.max(1,Math.min(r,s-1)),s<=1&&n>0)break}return{value:{[E]:"unsupported",kind:"truncated"},truncated:!0,note:`State exceeds the ${e}-byte transport limit and could not be reduced to fit.`}}function b(o,e,t){o.onError?.(e,t)}async function Y(o){const e={slices:{},restored:!1};let t;try{t=o.source??await o.adapter.read(o.key)}catch(n){return b(o,n,"read"),e}if(t==null||t==="")return e;let s;try{s=T(JSON.parse(t))}catch(n){return b(o,n,"decode"),e}if(s===null||typeof s!="object"||typeof s.version!="number")return b(o,new Error("persisted payload is not a recognisable envelope"),"decode"),e;if(s.version!==o.version){if(o.migrate===void 0)return b(o,new Error(`persisted state is version ${s.version}, this build expects ${o.version}, and no migrate was supplied`),"migrate"),e;try{const n=o.migrate(s.slices,s.version);return n===null?e:{slices:n,restored:!0}}catch(n){return b(o,n,"migrate"),e}}return{slices:s.slices??{},restored:!0}}function q(o,e){if(!e.restored)return o;const t={};for(const[s,n]of Object.entries(o)){const i=e.slices[s];t[s]=i===void 0?n:{...n,state:i}}return t}function C(o,e){const t=o??{},s=e.slices===void 0?t:Object.fromEntries(e.slices.filter(n=>n in t).map(n=>[n,t[n]]));return JSON.stringify(O({version:e.version,slices:s}).value)}function X(o,e){const t=e.throttleMs??250,s=e.slices;let n=null,i=!1;const d=()=>{if(i){i=!1;try{const f=e.adapter.write(e.key,C(o.getState(),e));f instanceof Promise&&f.catch(c=>b(e,c,"write"))}catch(f){b(e,f,"write")}}},a=()=>{if(i=!0,t<=0){d();return}n===null&&(n=setTimeout(()=>{n=null,d()},t),n.unref?.())},r=o.instrument(f=>{if(s===void 0){a();return}(f.changedPaths??[]).some(u=>s.some(l=>u===l||u.startsWith(`${l}.`)))&&a()});return()=>{r(),n!==null&&(clearTimeout(n),n=null),d()}}function Z(o,e){return C(o.getState(),e)}function ee(o){return{read:e=>o.getItem(e),write:(e,t)=>o.setItem(e,t),remove:e=>o.removeItem(e)}}function te(o){const e=new Map(Object.entries(o??{}));return{read:t=>e.get(t)??null,write:(t,s)=>{e.set(t,s)},remove:t=>{e.delete(t)}}}exports.EventBus=A;exports.LooseEventBus=N;exports.Reducer=D;exports.Store=S;exports.createEntityAdapter=Q;exports.createMemoryAdapter=te;exports.createStore=F;exports.createWebStorageAdapter=ee;exports.decodeState=T;exports.dehydrate=Z;exports.detectChangedProps=k;exports.encodeState=O;exports.encodeStateBounded=J;exports.eventKeys=U;exports.freezeState=v;exports.hydrate=Y;exports.persist=X;exports.typedEvents=V;exports.withHydration=q;
|
|
11
11
|
//# sourceMappingURL=yoltra.cjs.js.map
|