@sladg/apex-state 3.7.1 → 3.9.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.
@@ -0,0 +1,2119 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * Hash key type for Record-based paths
6
+ *
7
+ * Use in template strings to construct paths through Record/HashMap properties.
8
+ * This type represents the literal string '[*]' used for indexing into Records.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * type Path = `users.${HASH_KEY}.name` // "users.[*].name"
13
+ * ```
14
+ */
15
+ type HASH_KEY = '[*]';
16
+
17
+ /**
18
+ * DeepKey utility type
19
+ *
20
+ * Generates a union of all possible dot-notation paths for nested objects.
21
+ * Supports nested objects up to depth 20 to handle deeply nested data structures.
22
+ * Handles arrays and complex object hierarchies.
23
+ *
24
+ * Uses loop unrolling: processes 2 nesting levels per recursion call,
25
+ * halving recursion depth while preserving bottom-up evaluation that
26
+ * TypeScript can cache (no prefix parameter).
27
+ *
28
+ * Examples of supported paths:
29
+ * - Simple: "name", "email"
30
+ * - Nested: "user.address.street"
31
+ * - Deep: "g.p.data.optionsCommon.base.ccyPair.forCurrency.id" (11 levels)
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * type User = {
36
+ * name: string
37
+ * address: {
38
+ * street: string
39
+ * city: string
40
+ * }
41
+ * }
42
+ *
43
+ * // DeepKey<User> = "name" | "address" | "address.street" | "address.city"
44
+ * ```
45
+ *
46
+ * @example Custom depth — reduce for faster compilation on wide types
47
+ * ```typescript
48
+ * // Only traverse 10 levels deep instead of the default 20
49
+ * type ShallowPaths = DeepKey<User, 10>
50
+ * ```
51
+ *
52
+ * @example Depth limit marker — `??` appears at the cutoff point
53
+ * ```typescript
54
+ * // If a type is nested deeper than Depth, autocomplete shows:
55
+ * // "some.deep.path.??" — signaling you should increase depth or restructure
56
+ * type Paths = DeepKey<VeryDeepType, 6>
57
+ * ```
58
+ */
59
+
60
+ type Primitive = string | number | boolean | bigint | symbol | null | undefined;
61
+ type IsAny$1<T> = 0 extends 1 & T ? true : false;
62
+ /**
63
+ * Default recursion depth for DeepKey and all types that depend on it.
64
+ * Change this single value to adjust the depth limit across the entire type system.
65
+ *
66
+ * Propagates to: SyncPair, FlipPair, AggregationPair, ComputationPair,
67
+ * BoolLogic, SideEffects, DeepKeyFiltered, ClearPathRule.
68
+ *
69
+ * @example Override per-call instead of changing the default
70
+ * ```typescript
71
+ * type Shallow = DeepKey<MyState, 10> // reduced depth
72
+ * type Deeper = DeepKey<MyState, 30> // increased depth
73
+ * ```
74
+ */
75
+ type DefaultDepth = 20;
76
+ /**
77
+ * Marker emitted when DeepKey reaches its depth limit on an object type,
78
+ * or when it encounters an `any`-typed property (unknowable structure).
79
+ * Appears as `some.deep.path.??` in autocomplete, signaling the cutoff point.
80
+ * Users seeing this can increase depth: `DeepKey<T, 30>` or restructure their type.
81
+ */
82
+ type DepthLimitMarker = '??';
83
+ type DeepKey<T, Depth extends number = DefaultDepth> = DeepKeyUnrolled<T, Depth> & string;
84
+ /**
85
+ * DeepKey with `??` marker paths excluded. Use in types that resolve path values
86
+ * (DeepValue, DeepKeyFiltered, PathsWithSameValueAs) where `??` would fail resolution.
87
+ * DeepKey itself keeps `??` for IDE autocomplete visibility.
88
+ */
89
+ type ResolvableDeepKey<T, Depth extends number = DefaultDepth> = Exclude<DeepKey<T, Depth>, `${string}??` | '??'>;
90
+ /**
91
+ * Loop-unrolled DeepKey: processes 2 nesting levels per recursion call.
92
+ *
93
+ * For each key K of T:
94
+ * - Emit K (level 1 path)
95
+ * - If T[K] is an object, inline level 2:
96
+ * - For each key K2 of T[K]:
97
+ * - Emit `${K}.${K2}` (level 2 path)
98
+ * - If T[K][K2] is an object, recurse with `${K}.${K2}.${DeepKeyUnrolled}`
99
+ *
100
+ * Key insight: DeepKeyUnrolled<T, Depth> has NO prefix parameter,
101
+ * so identical sub-types at the same depth are cached by TypeScript.
102
+ * Template literal distribution (`${prefix}.${union}`) is handled natively
103
+ * by TypeScript without extra type instantiation overhead.
104
+ */
105
+ type DeepKeyUnrolled<T, Depth extends number> = Depth extends 0 ? T extends Primitive | readonly any[] ? never : DepthLimitMarker : IsAny$1<T> extends true ? never : T extends Primitive ? never : T extends readonly any[] ? never : string extends keyof T ? HASH_KEY | (IsAny$1<T[string]> extends true ? `${HASH_KEY}.${DepthLimitMarker}` : NonNullable<T[string]> extends Primitive | readonly any[] ? never : RecordLevel2<NonNullable<T[string]>, HASH_KEY, Depth>) : {
106
+ [K in keyof T & (string | number)]: (K & string) | (IsAny$1<T[K]> extends true ? `${K & string}.${DepthLimitMarker}` : NonNullable<T[K]> extends Primitive | readonly any[] ? never : ConcreteLevel2<NonNullable<T[K]>, K & string, Depth>);
107
+ }[keyof T & (string | number)];
108
+ /**
109
+ * Level 2 expansion for concrete-key objects.
110
+ * Enumerates V's keys and uses inline template literal distribution for level 3+.
111
+ */
112
+ type ConcreteLevel2<V, ParentKey extends string, Depth extends number> = IsAny$1<V> extends true ? `${ParentKey}.${DepthLimitMarker}` : V extends Primitive ? never : V extends readonly any[] ? never : string extends keyof V ? `${ParentKey}.${HASH_KEY}` | (IsAny$1<V[string]> extends true ? `${ParentKey}.${HASH_KEY}.${DepthLimitMarker}` : NonNullable<V[string]> extends Primitive | readonly any[] ? never : `${ParentKey}.${HASH_KEY}.${DeepKeyUnrolled<NonNullable<V[string]>, Prev2<Depth>> & string}`) : {
113
+ [K2 in keyof V & (string | number)]: `${ParentKey}.${K2 & string}` | (IsAny$1<V[K2]> extends true ? `${ParentKey}.${K2 & string}.${DepthLimitMarker}` : NonNullable<V[K2]> extends Primitive | readonly any[] ? never : `${ParentKey}.${K2 & string}.${DeepKeyUnrolled<NonNullable<V[K2]>, Prev2<Depth>> & string}`);
114
+ }[keyof V & (string | number)];
115
+ /**
116
+ * Level 2 expansion for Record-value objects.
117
+ * When level 1 was a Record, its value type V is expanded at level 2.
118
+ */
119
+ type RecordLevel2<V, ParentKey extends string, Depth extends number> = IsAny$1<V> extends true ? `${ParentKey}.${DepthLimitMarker}` : V extends Primitive ? never : V extends readonly any[] ? never : string extends keyof V ? `${ParentKey}.${HASH_KEY}` | (IsAny$1<V[string]> extends true ? `${ParentKey}.${HASH_KEY}.${DepthLimitMarker}` : NonNullable<V[string]> extends Primitive | readonly any[] ? never : `${ParentKey}.${HASH_KEY}.${DeepKeyUnrolled<NonNullable<V[string]>, Prev2<Depth>> & string}`) : {
120
+ [K2 in keyof V & (string | number)]: `${ParentKey}.${K2 & string}` | (IsAny$1<V[K2]> extends true ? `${ParentKey}.${K2 & string}.${DepthLimitMarker}` : NonNullable<V[K2]> extends Primitive | readonly any[] ? never : `${ParentKey}.${K2 & string}.${DeepKeyUnrolled<NonNullable<V[K2]>, Prev2<Depth>> & string}`);
121
+ }[keyof V & (string | number)];
122
+ type Prev2<N extends number> = N extends 20 ? 18 : N extends 19 ? 17 : N extends 18 ? 16 : N extends 17 ? 15 : N extends 16 ? 14 : N extends 15 ? 13 : N extends 14 ? 12 : N extends 13 ? 11 : N extends 12 ? 10 : N extends 11 ? 9 : N extends 10 ? 8 : N extends 9 ? 7 : N extends 8 ? 6 : N extends 7 ? 5 : N extends 6 ? 4 : N extends 5 ? 3 : N extends 4 ? 2 : N extends 3 ? 1 : N extends 2 ? 0 : N extends 1 ? 0 : never;
123
+
124
+ /**
125
+ * DeepKeyFiltered - Filters paths by their resolved value type
126
+ *
127
+ * Returns only paths from DeepKey<T> that resolve to a specific type U.
128
+ * Useful for type-safe filtering of state paths by their value types.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * type Data = {
133
+ * isActive: boolean
134
+ * name: string
135
+ * count: number
136
+ * user: { isAdmin: boolean }
137
+ * }
138
+ *
139
+ * // Only boolean paths
140
+ * type BoolPaths = DeepKeyFiltered<Data, boolean>
141
+ * // Result: "isActive" | "user.isAdmin"
142
+ *
143
+ * // Only string paths
144
+ * type StrPaths = DeepKeyFiltered<Data, string>
145
+ * // Result: "name"
146
+ * ```
147
+ */
148
+
149
+ /**
150
+ * Filters DeepKey<T> to only include paths that resolve to type U.
151
+ *
152
+ * Uses mapped type with conditional filtering - maps over all possible paths,
153
+ * keeps those matching the target type, and extracts the union.
154
+ *
155
+ * @example Custom depth — propagates to DeepKey
156
+ * ```typescript
157
+ * // Only number paths, limited to 10 levels deep
158
+ * type ShallowNumbers = DeepKeyFiltered<State, number, 10>
159
+ * ```
160
+ */
161
+ type DeepKeyFiltered<T, U, Depth extends number = DefaultDepth> = {
162
+ [K in ResolvableDeepKey<T, Depth>]: NonNullable<DeepValue<T, K>> extends U ? K : never;
163
+ }[ResolvableDeepKey<T, Depth>];
164
+
165
+ /**
166
+ * DeepValue utility type
167
+ *
168
+ * Extracts the value type for a given dot-notation path string.
169
+ * Handles nested objects, arrays, and optional properties.
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * type User = {
174
+ * address: {
175
+ * street: string
176
+ * city: string
177
+ * }
178
+ * }
179
+ *
180
+ * // DeepValue<User, "address.street"> = string
181
+ * // DeepValue<User, "address"> = { street: string, city: string }
182
+ * ```
183
+ */
184
+
185
+ type IsAny<T> = 0 extends 1 & T ? true : false;
186
+ type DeepValue<T, Path extends string> = IsAny<T> extends true ? never : T extends readonly any[] ? T[number] : Path extends `${infer First}.${infer Rest}` ? First extends keyof T ? DeepValue<NonNullable<T[First]>, Rest> : string extends keyof T ? First extends HASH_KEY ? DeepValue<T[string], Rest> : unknown : unknown : Path extends HASH_KEY ? string extends keyof T ? T[string] : unknown : Path extends keyof T ? T[Path] : unknown;
187
+
188
+ /**
189
+ * Boolean logic DSL type definitions
190
+ *
191
+ * Type-safe conditional expression DSL used by concerns and side effects
192
+ * for reactive condition checking against state.
193
+ */
194
+
195
+ /**
196
+ * Path-value pair distributed over all valid paths.
197
+ * Each path is paired with its resolved value type, ensuring type safety.
198
+ * The distribution happens inside the tuple, not at the union level —
199
+ * this keeps BoolLogic's top-level union flat so `in` narrowing works.
200
+ */
201
+ type PathValuePair<STATE, Depth extends number> = DeepKey<STATE, Depth> extends infer P ? P extends string ? [P, DeepValue<STATE, P>] : never : never;
202
+ /**
203
+ * Path-value array pair for IN operator.
204
+ * Same distribution as PathValuePair but with array values.
205
+ */
206
+ type PathValueArrayPair<STATE, Depth extends number> = DeepKey<STATE, Depth> extends infer P ? P extends string ? [P, DeepValue<STATE, P>[]] : never : never;
207
+ /**
208
+ * Array-elements pair for CONTAINS_ANY / CONTAINS_ALL operators.
209
+ * Same distribution as PathArrayElementPair but the second element is an array
210
+ * of items, enabling multi-value containment checks.
211
+ */
212
+ type PathArrayElementsPair<STATE, Depth extends number> = DeepKey<STATE, Depth> extends infer P ? P extends string ? NonNullable<DeepValue<STATE, P>> extends readonly (infer Item)[] ? [P, Item[]] : never : never : never;
213
+ /**
214
+ * Paths that resolve to number, plus `.length` on array-valued paths.
215
+ * Allows GT/LT/GTE/LTE to compare against array lengths without
216
+ * polluting DeepKey with virtual paths.
217
+ */
218
+ type NumericPaths<STATE, Depth extends number> = DeepKeyFiltered<STATE, number, Depth> | `${DeepKeyFiltered<STATE, readonly unknown[], Depth>}.length`;
219
+ /**
220
+ * Boolean logic DSL for conditional expressions
221
+ *
222
+ * Provides a declarative way to express conditions against state paths.
223
+ * Used by concerns (disabledWhen, visibleWhen) and side effects.
224
+ *
225
+ * Operators:
226
+ * - IS_EQUAL: Compare path value to expected value (value must match path type)
227
+ * - EXISTS: Check if path value is not null/undefined
228
+ * - IS_EMPTY: Check if path value is empty (string/array/object)
229
+ * - AND/OR/NOT: Boolean combinators
230
+ * - GT/LT/GTE/LTE: Numeric comparisons (only on number paths or array.length)
231
+ * - IN: Check if path value is in allowed list (values must match path type)
232
+ * - CONTAINS_ANY: Check if array at path contains any of the given elements
233
+ * - CONTAINS_ALL: Check if array at path contains all of the given elements
234
+ * - Shorthand: [path, value] tuple as shorthand for IS_EQUAL
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * // Simple equality check
239
+ * const isAdmin: BoolLogic<State> = { IS_EQUAL: ['user.role', 'admin'] }
240
+ *
241
+ * // Shorthand equality (equivalent to IS_EQUAL)
242
+ * const isAdmin2: BoolLogic<State> = ['user.role', 'admin']
243
+ *
244
+ * // Combined conditions with shorthand
245
+ * const canEdit: BoolLogic<State> = {
246
+ * AND: [
247
+ * ['user.role', 'editor'],
248
+ * { EXISTS: 'document.id' },
249
+ * { NOT: ['document.status', 'locked'] }
250
+ * ]
251
+ * }
252
+ *
253
+ * // Numeric comparison
254
+ * const isExpensive: BoolLogic<State> = { GT: ['product.price', 100] }
255
+ *
256
+ * // Array length comparison
257
+ * const hasManyItems: BoolLogic<State> = { GT: ['cart.items.length', 5] }
258
+ * ```
259
+ */
260
+ type BoolLogic<STATE, Depth extends number = DefaultDepth> = {
261
+ IS_EQUAL: PathValuePair<STATE, Depth>;
262
+ } | {
263
+ EXISTS: DeepKey<STATE, Depth>;
264
+ } | {
265
+ IS_EMPTY: DeepKey<STATE, Depth>;
266
+ } | {
267
+ AND: BoolLogic<STATE, Depth>[];
268
+ } | {
269
+ OR: BoolLogic<STATE, Depth>[];
270
+ } | {
271
+ NOT: BoolLogic<STATE, Depth>;
272
+ } | {
273
+ GT: [NumericPaths<STATE, Depth>, number];
274
+ } | {
275
+ LT: [NumericPaths<STATE, Depth>, number];
276
+ } | {
277
+ GTE: [NumericPaths<STATE, Depth>, number];
278
+ } | {
279
+ LTE: [NumericPaths<STATE, Depth>, number];
280
+ } | {
281
+ IN: PathValueArrayPair<STATE, Depth>;
282
+ } | {
283
+ CONTAINS_ANY: PathArrayElementsPair<STATE, Depth>;
284
+ } | {
285
+ CONTAINS_ALL: PathArrayElementsPair<STATE, Depth>;
286
+ } | PathValuePair<STATE, Depth>;
287
+
288
+ /**
289
+ * GenericMeta interface
290
+ *
291
+ * Base metadata type for change tracking with standard properties.
292
+ * Can be extended with custom properties for specific use cases.
293
+ *
294
+ * @example
295
+ * ```typescript
296
+ * interface CustomMeta extends GenericMeta {
297
+ * timestamp: number
298
+ * userId: string
299
+ * }
300
+ * ```
301
+ */
302
+ interface GenericMeta {
303
+ /**
304
+ * Indicates if the change originated from a sync path side-effect.
305
+ * Used to track cascading changes triggered by synchronization logic.
306
+ */
307
+ isSyncPathChange?: boolean;
308
+ /**
309
+ * Indicates if the change originated from a flip path side-effect.
310
+ * Used to track bidirectional synchronization changes.
311
+ */
312
+ isFlipPathChange?: boolean;
313
+ /**
314
+ * Indicates if the change was triggered programmatically rather than by user action.
315
+ * Useful for distinguishing between automated and manual state updates.
316
+ */
317
+ isProgramaticChange?: boolean;
318
+ /**
319
+ * Indicates if the change originated from an aggregation side-effect.
320
+ * Used to track changes triggered by aggregation logic.
321
+ */
322
+ isAggregationChange?: boolean;
323
+ /**
324
+ * Indicates if the change originated from a listener side-effect.
325
+ * Used to track changes triggered by listener callbacks.
326
+ */
327
+ isListenerChange?: boolean;
328
+ /**
329
+ * Indicates if the change originated from a clear paths side-effect.
330
+ * Used to track changes triggered by clear paths logic (WASM-only).
331
+ */
332
+ isClearPathChange?: boolean;
333
+ /**
334
+ * Indicates if the change originated from a computation side-effect (SUM/AVG).
335
+ * Used to track changes triggered by computation logic.
336
+ */
337
+ isComputationChange?: boolean;
338
+ /**
339
+ * Identifies the originator of the change.
340
+ * Can be a user ID, component name, or any identifier string.
341
+ */
342
+ sender?: string;
343
+ }
344
+
345
+ /**
346
+ * ArrayOfChanges type
347
+ *
348
+ * Represents an array of changes with paths, values, and metadata.
349
+ * Each change is a tuple of [path, value, metadata].
350
+ *
351
+ * @example
352
+ * ```typescript
353
+ * type User = {
354
+ * name: string
355
+ * age: number
356
+ * }
357
+ *
358
+ * const changes: ArrayOfChanges<User, GenericMeta> = [
359
+ * ["name", "John", { sender: "user-123" }],
360
+ * ["age", 30, { isProgramaticChange: true }]
361
+ * ]
362
+ * ```
363
+ */
364
+
365
+ /**
366
+ * Represents an array of change tuples.
367
+ * Each tuple contains:
368
+ * - path: A valid deep key path for the data structure
369
+ * - value: The value at that path (properly typed based on the path)
370
+ * - meta: Metadata about the change
371
+ */
372
+ type ArrayOfChanges<DATA, META extends GenericMeta = GenericMeta> = {
373
+ [K in DeepKey<DATA>]: [K, DeepValue<DATA, K>, META] | [K, DeepValue<DATA, K>];
374
+ }[DeepKey<DATA>][];
375
+
376
+ /**
377
+ * Concern type utilities
378
+ *
379
+ * Generic type helpers for working with concern arrays and extracting
380
+ * their return types for proper type-safe concern registration and reading.
381
+ */
382
+
383
+ /**
384
+ * Validation schema interface — the minimal contract for validation.
385
+ *
386
+ * Any library whose schema exposes `safeParse()` with this shape works
387
+ * out of the box (Zod, Valibot, ArkType, or a plain object).
388
+ */
389
+ interface ValidationSchema<T = unknown> {
390
+ safeParse(data: unknown): {
391
+ success: true;
392
+ data: T;
393
+ } | {
394
+ success: false;
395
+ error: {
396
+ errors: {
397
+ path: (string | number)[];
398
+ message: string;
399
+ }[];
400
+ };
401
+ };
402
+ }
403
+ /**
404
+ * Config type for the validationState concern at a specific path.
405
+ *
406
+ * Defined here (not in concerns/prebuilts/validation-state.ts) to avoid
407
+ * circular imports when used in ConcernRegistrationMap.
408
+ *
409
+ * Can be a schema for the path's own value type, or a scoped schema
410
+ * targeting a different path in the same state.
411
+ */
412
+ type ValidationStateInput<DATA, PATH extends DeepKey<DATA, Depth>, Depth extends number = DefaultDepth> = {
413
+ schema: ValidationSchema<DeepValue<DATA, PATH>>;
414
+ } | {
415
+ [SCOPE in ResolvableDeepKey<DATA, Depth>]: {
416
+ scope: SCOPE;
417
+ schema: ValidationSchema<DeepValue<DATA, SCOPE>>;
418
+ };
419
+ }[ResolvableDeepKey<DATA, Depth>];
420
+ /**
421
+ * Get the appropriate registration config type for a concern at a given path.
422
+ *
423
+ * - validationState: schema must match DeepValue<DATA, PATH> — path-dependent
424
+ * - BoolLogic-based concerns: boolLogic paths are typed against DATA
425
+ * - Template-based concerns: fixed { template: string }
426
+ * - Custom concerns: fall back to Record<string, unknown>
427
+ */
428
+ type ConcernConfigFor<C, DATA extends object, PATH extends DeepKey<DATA, Depth>, Depth extends number = DefaultDepth> = C extends {
429
+ name: 'validationState';
430
+ } ? ValidationStateInput<DATA, PATH, Depth> : C extends {
431
+ evaluate: (props: infer P) => any;
432
+ } ? P extends {
433
+ boolLogic: any;
434
+ } ? {
435
+ boolLogic: BoolLogic<DATA, Depth>;
436
+ } : Omit<P, 'state' | 'path' | 'value'> : Record<string, unknown>;
437
+ /**
438
+ * Extract the return type from a concern's evaluate function
439
+ *
440
+ * Used internally to determine what a concern evaluates to,
441
+ * enabling type-safe concern result objects.
442
+ *
443
+ * @example
444
+ * ```typescript
445
+ * type MyConcern = { evaluate: (...args: any[]) => boolean }
446
+ * type Result = ExtractEvaluateReturn<MyConcern> // boolean
447
+ * ```
448
+ */
449
+ type ExtractEvaluateReturn<T> = T extends {
450
+ evaluate: (...args: any[]) => infer R;
451
+ } ? R : never;
452
+ /**
453
+ * Dynamically build an evaluated concerns object from a CONCERNS array
454
+ *
455
+ * Maps each concern's name to its return type, creating a properly typed
456
+ * object that represents all concerns that can be registered/evaluated.
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * const concerns = [
461
+ * { name: 'validationState', evaluate: () => ({ isError: boolean, errors: [] }) },
462
+ * { name: 'tooltip', evaluate: () => string }
463
+ * ] as const
464
+ *
465
+ * type Evaluated = EvaluatedConcerns<typeof concerns>
466
+ * // { validationState?: { isError: boolean, errors: [] }, tooltip?: string }
467
+ * ```
468
+ */
469
+ type EvaluatedConcerns<CONCERNS extends readonly any[]> = {
470
+ [K in CONCERNS[number] as K['name']]?: ExtractEvaluateReturn<K>;
471
+ };
472
+ /**
473
+ * Maps field paths to per-concern config objects.
474
+ *
475
+ * When CONCERNS is provided (e.g., from createGenericStore's CONCERNS generic),
476
+ * each concern config is type-checked against:
477
+ * - The concern's own EXTRA_PROPS (e.g., `{ boolLogic: ... }` for disabledWhen)
478
+ * - The path's value type for validationState (schema must match DeepValue<DATA, PATH>)
479
+ *
480
+ * Without CONCERNS (standalone usage), falls back to loose typing for backward compatibility.
481
+ *
482
+ * @example
483
+ * ```typescript
484
+ * // Works with any library implementing ValidationSchema (Zod, Valibot, ArkType, etc.)
485
+ * const registration: ConcernRegistrationMap<MyFormState> = {
486
+ * email: { validationState: { schema: emailSchema } },
487
+ * name: { validationState: { schema: nameSchema } },
488
+ * }
489
+ * ```
490
+ */
491
+ type ConcernRegistrationMap<DATA extends object, CONCERNS extends readonly any[] = readonly any[], Depth extends number = DefaultDepth> = Partial<{
492
+ [PATH in DeepKey<DATA, Depth>]: Partial<{
493
+ [C in CONCERNS[number] as C extends {
494
+ name: string;
495
+ } ? C['name'] : never]: ConcernConfigFor<C, DATA, PATH, Depth>;
496
+ }>;
497
+ }>;
498
+
499
+ /**
500
+ * Lazy listener validators — O(N) base + O(K) per-listener validation
501
+ *
502
+ * These types power the `listeners()` helper function that scales to large state
503
+ * types without hitting TS2589.
504
+ *
505
+ * Unlike the direct `ListenerRegistration<DATA>[]` type which resolves
506
+ * `DeepKey<DATA>` for path/scope on every element, these validators only evaluate
507
+ * `DeepValue` for the K listeners you actually write.
508
+ *
509
+ * Valid listener combinations:
510
+ * 1. `{ path: string, fn }` — scope defaults to path → scoped state
511
+ * 2. `{ path: string, scope: null, fn }` — explicit null scope → full DATA
512
+ * 3. `{ path: string, scope: string, fn }` — scope must be prefix of path
513
+ * 4. `{ path: null, fn }` — watch everything, scope defaults to null → full DATA
514
+ * 5. `{ path: null, scope: null, fn }` — same as above, explicit
515
+ *
516
+ * **Inline fn restriction**: Fns with untyped (any) parameters are rejected.
517
+ * Use `OnStateListener<DATA, ScopedState>` to explicitly type your fn.
518
+ */
519
+
520
+ /**
521
+ * True if Prefix is a dot-separated ancestor of Path (or equals Path).
522
+ *
523
+ * @example
524
+ * IsPrefixOf<'user', 'user'> → true (equal)
525
+ * IsPrefixOf<'user', 'user.name'> → true (parent)
526
+ * IsPrefixOf<'user', 'username'> → false (different segment)
527
+ * IsPrefixOf<'cart', 'user.name'> → false (unrelated)
528
+ */
529
+ type IsPrefixOf<Prefix extends string, Path extends string> = Path extends Prefix ? true : Path extends `${Prefix}.${string}` ? true : false;
530
+ /**
531
+ * Derive the sub-state type from scope.
532
+ * - null scope → full DATA
533
+ * - string scope → DeepValue<DATA, Scope>
534
+ *
535
+ * Uses `Scope & string` to satisfy DeepValue's string constraint
536
+ * when Scope is inferred from a mapped type.
537
+ */
538
+ type ScopedState<DATA extends object, Scope> = Scope extends null ? DATA : Scope extends string ? DeepValue<DATA, Scope & string> : DATA;
539
+ /**
540
+ * Extract the effective scope from a listener element.
541
+ *
542
+ * When 'scope' key exists with a non-undefined value, returns that value.
543
+ * When 'scope' key is missing or undefined, returns the path as default.
544
+ */
545
+ type EffectiveScope<T, P> = 'scope' extends keyof T ? Exclude<T[keyof T & 'scope'], undefined> extends never ? P : Exclude<T[keyof T & 'scope'], undefined> : P;
546
+ /**
547
+ * Detect if a function's first parameter is `any`.
548
+ * Uses the `0 extends 1 & T` trick: only true when T is `any`.
549
+ *
550
+ * When true, the fn has untyped parameters (e.g., `(_changes, _state) => ...`
551
+ * without explicit typing). We reject these to force users to use
552
+ * `OnStateListener<DATA, ScopedState>` for type safety.
553
+ */
554
+ type HasAnyFirstParam<F> = F extends (...args: infer A) => any ? A extends [infer P1, ...any[]] ? 0 extends 1 & P1 ? true : false : false : false;
555
+ /**
556
+ * Error marker type for untyped listener fns.
557
+ * Produces a clear error message when the user passes an untyped inline fn.
558
+ */
559
+ type TypedFnRequired<DATA extends object, SUB_STATE, META extends GenericMeta> = OnStateListener<DATA, SUB_STATE, META> & {
560
+ __error: 'Listener fn must be explicitly typed. Use OnStateListener<DATA, ScopedState> or type the parameters directly.';
561
+ };
562
+ /**
563
+ * Returns the fn type for a listener element, rejecting untyped fns.
564
+ *
565
+ * When the user's fn has `any` params (implicit from inference), returns
566
+ * a branded error type that produces a clear type error.
567
+ * When the fn is explicitly typed (standalone or annotated), returns the
568
+ * expected OnStateListener type for assignability checking.
569
+ */
570
+ type ValidatedFn<DATA extends object, META extends GenericMeta, SUB_STATE, F> = HasAnyFirstParam<F> extends true ? TypedFnRequired<DATA, SUB_STATE, META> : OnStateListener<DATA, SUB_STATE, META>;
571
+ /**
572
+ * Validates a single listener element.
573
+ *
574
+ * When scope is omitted (undefined), it defaults to path:
575
+ * - path is string → fn gets DeepValue<DATA, path>
576
+ * - path is null → fn gets full DATA
577
+ *
578
+ * When scope is explicitly provided:
579
+ * - scope: null → fn gets full DATA
580
+ * - scope: string → must be prefix of path, fn gets DeepValue<DATA, scope>
581
+ *
582
+ * Rejects fns with untyped (any) parameters — forces explicit typing via
583
+ * OnStateListener<DATA, ScopedState>.
584
+ */
585
+ type CheckListenerElement<DATA extends object, META extends GenericMeta, T> = T extends {
586
+ path: infer P;
587
+ fn: infer F;
588
+ } ? EffectiveScope<T, P> extends infer ES ? [
589
+ P,
590
+ ES
591
+ ] extends [string, string] ? IsPrefixOf<ES & string, P & string> extends true ? 'scope' extends keyof T ? {
592
+ path: P;
593
+ scope: ES;
594
+ fn: ValidatedFn<DATA, META, ScopedState<DATA, ES>, F>;
595
+ } : {
596
+ path: P;
597
+ scope?: undefined;
598
+ fn: ValidatedFn<DATA, META, ScopedState<DATA, ES>, F>;
599
+ } : {
600
+ path: P;
601
+ scope: never;
602
+ fn: OnStateListener<DATA, never, META>;
603
+ } : [
604
+ P,
605
+ ES
606
+ ] extends [string, null] ? {
607
+ path: P;
608
+ scope: null;
609
+ fn: ValidatedFn<DATA, META, DATA, F>;
610
+ } : [
611
+ P,
612
+ ES
613
+ ] extends [null, null] ? 'scope' extends keyof T ? {
614
+ path: null;
615
+ scope: null;
616
+ fn: ValidatedFn<DATA, META, DATA, F>;
617
+ } : {
618
+ path: null;
619
+ scope?: undefined;
620
+ fn: ValidatedFn<DATA, META, DATA, F>;
621
+ } : T : T : T;
622
+ /**
623
+ * Validates an array of listener objects lazily — O(K) where K = listeners written.
624
+ *
625
+ * Per element:
626
+ * 1. path must be ResolvableDeepKey<DATA> | null (enforced by function constraint)
627
+ * 2. scope is optional — defaults to path when omitted
628
+ * 3. When both non-null: scope must be prefix of path
629
+ * 4. fn must be explicitly typed (rejects untyped `any` params)
630
+ * 5. fn receives correctly-typed scoped state
631
+ */
632
+ type CheckListeners<DATA extends object, META extends GenericMeta, T extends readonly {
633
+ path: string | null;
634
+ scope?: string | null | undefined;
635
+ fn: (...args: any[]) => any;
636
+ }[], _Depth extends number = DefaultDepth> = {
637
+ [I in keyof T]: CheckListenerElement<DATA, META, T[I]>;
638
+ };
639
+
640
+ /**
641
+ * Direct pair types — O(N²) path unions for side effects
642
+ *
643
+ * These types enumerate all valid path combinations eagerly.
644
+ * Simple to use as type annotations but hit TS2589 at ~1,500 paths.
645
+ *
646
+ * For large state types, use the curried helper functions (syncPairs, flipPairs, etc.)
647
+ * which use lazy validators from `pair-validators.ts` instead.
648
+ *
649
+ * @example
650
+ * ```typescript
651
+ * type State = {
652
+ * user: { email: string }
653
+ * profile: { email: string }
654
+ * count: number
655
+ * }
656
+ *
657
+ * // ✓ Valid: both paths are string
658
+ * const sync: SyncPair<State> = ['user.email', 'profile.email']
659
+ *
660
+ * // ✗ Error: 'user.email' (string) can't sync with 'count' (number)
661
+ * const invalid: SyncPair<State> = ['user.email', 'count']
662
+ * ```
663
+ */
664
+
665
+ /**
666
+ * Get all paths in DATA that have the same value type as the value at PATH
667
+ */
668
+ type PathsWithSameValueAs<DATA extends object, PATH extends ResolvableDeepKey<DATA, Depth>, Depth extends number = DefaultDepth> = {
669
+ [K in ResolvableDeepKey<DATA, Depth>]: NonNullable<DeepValue<DATA, K>> extends NonNullable<DeepValue<DATA, PATH>> ? NonNullable<DeepValue<DATA, PATH>> extends NonNullable<DeepValue<DATA, K>> ? K : never : never;
670
+ }[ResolvableDeepKey<DATA, Depth>];
671
+ /**
672
+ * A tuple of two paths that must have the same value type.
673
+ * Format: [path1, path2]
674
+ *
675
+ * **Scaling note**: This type is O(N²) where N = number of paths. It hits TS2589
676
+ * at ~1,500 paths. For large state types, use the `syncPairs()` helper function
677
+ * or `store.syncPairs()` (pre-warmed from `createGenericStore`) instead —
678
+ * they scale to ~50K–80K paths.
679
+ *
680
+ * @example
681
+ * const pair: SyncPair<State> = ['user.email', 'profile.email']
682
+ *
683
+ * @example Custom depth — propagates to DeepKey and PathsWithSameValueAs
684
+ * ```typescript
685
+ * // Limit path traversal to 10 levels
686
+ * const shallow: SyncPair<State, 10> = ['user.email', 'profile.email']
687
+ * ```
688
+ */
689
+ type SyncPair<DATA extends object, Depth extends number = DefaultDepth> = {
690
+ [P1 in ResolvableDeepKey<DATA, Depth>]: [
691
+ P1,
692
+ PathsWithSameValueAs<DATA, P1, Depth>
693
+ ];
694
+ }[ResolvableDeepKey<DATA, Depth>];
695
+ /**
696
+ * A tuple of two paths for flip (alias for SyncPair).
697
+ * Format: [path1, path2]
698
+ *
699
+ * **Scaling note**: O(N²) — hits TS2589 at ~1,500 paths. Use `flipPairs()` helper
700
+ * or `store.flipPairs()` for large state types.
701
+ *
702
+ * @example
703
+ * const pair: FlipPair<State> = ['isActive', 'isInactive']
704
+ */
705
+ type FlipPair<DATA extends object, Depth extends number = DefaultDepth> = SyncPair<DATA, Depth>;
706
+ /**
707
+ * A tuple for aggregation: [target, source] or [target, source, excludeWhen]
708
+ * First element (left) is ALWAYS the target (aggregated) path.
709
+ * Second element is a source path.
710
+ * Optional third element is a BoolLogic condition — when true, this source is excluded.
711
+ *
712
+ * Multiple pairs can point to same target for multi-source aggregation.
713
+ *
714
+ * **Scaling note**: O(N²) — hits TS2589 at ~1,500 paths. Use `aggregationPairs()` helper
715
+ * or `store.aggregationPairs()` for large state types.
716
+ *
717
+ * @example
718
+ * // target <- source (target is always first/left)
719
+ * const aggs: AggregationPair<State>[] = [
720
+ * ['total', 'price1'],
721
+ * ['total', 'price2', { IS_EQUAL: ['price2.disabled', true] }],
722
+ * ]
723
+ */
724
+ type AggregationPair<DATA extends object, Depth extends number = DefaultDepth> = {
725
+ [P1 in ResolvableDeepKey<DATA, Depth>]: [P1, PathsWithSameValueAs<DATA, P1, Depth>] | [P1, PathsWithSameValueAs<DATA, P1, Depth>, BoolLogic<DATA, Depth>];
726
+ }[ResolvableDeepKey<DATA, Depth>];
727
+ /**
728
+ * Supported computation operations for numeric reduction.
729
+ */
730
+ type ComputationOp = 'SUM' | 'AVG';
731
+ /**
732
+ * A tuple for computation: [operation, target, source] or [operation, target, source, excludeWhen]
733
+ * First element is the operation (SUM, AVG).
734
+ * Second element is the target path (must be a number path).
735
+ * Third element is a source path (must be a number path).
736
+ * Optional fourth element is a BoolLogic condition — when true, this source is excluded.
737
+ *
738
+ * Multiple pairs can point to same target for multi-source computation.
739
+ *
740
+ * **Scaling note**: O(N²) — hits TS2589 at ~1,500 paths. Use `computationPairs()` helper
741
+ * or `store.computationPairs()` for large state types.
742
+ *
743
+ * @example
744
+ * const comps: ComputationPair<State>[] = [
745
+ * ['SUM', 'total', 'price1'],
746
+ * ['SUM', 'total', 'price2', { IS_EQUAL: ['price2.disabled', true] }],
747
+ * ['AVG', 'average', 'score1'],
748
+ * ['AVG', 'average', 'score2'],
749
+ * ]
750
+ */
751
+ type ComputationPair<DATA extends object, Depth extends number = DefaultDepth> = {
752
+ [TARGET in DeepKeyFiltered<DATA, number, Depth>]: [ComputationOp, TARGET, DeepKeyFiltered<DATA, number, Depth>] | [
753
+ ComputationOp,
754
+ TARGET,
755
+ DeepKeyFiltered<DATA, number, Depth>,
756
+ BoolLogic<DATA, Depth>
757
+ ];
758
+ }[DeepKeyFiltered<DATA, number, Depth>];
759
+
760
+ /**
761
+ * Lazy pair validators — O(N) base + O(K) per-pair DeepValue check
762
+ *
763
+ * These types power the helper functions (syncPairs, flipPairs, etc.)
764
+ * that scale to large state types without hitting TS2589.
765
+ *
766
+ * Unlike the direct pair types (SyncPair, FlipPair, etc.) which are O(N²),
767
+ * these validators only evaluate DeepValue for the K pairs you actually write.
768
+ */
769
+
770
+ /**
771
+ * Validates that two paths resolve to the same value type.
772
+ * Only evaluates DeepValue when P1, P2 are concrete literals — O(1) per pair.
773
+ * Wraps in [T] extends [U] to prevent distributive conditional.
774
+ *
775
+ * Returns [P1, P2] on match, [P1, never] on mismatch.
776
+ */
777
+ type CheckPairValueMatch<DATA extends object, P1 extends string, P2 extends string, Depth extends number = DefaultDepth> = [P1] extends [ResolvableDeepKey<DATA, Depth>] ? [P2] extends [ResolvableDeepKey<DATA, Depth>] ? [NonNullable<DeepValue<DATA, P1>>] extends [
778
+ NonNullable<DeepValue<DATA, P2>>
779
+ ] ? [NonNullable<DeepValue<DATA, P2>>] extends [
780
+ NonNullable<DeepValue<DATA, P1>>
781
+ ] ? [P1, P2] : [P1, never] : [P1, never] : never : never;
782
+ /**
783
+ * Validates an array of [P1, P2] sync/flip pairs lazily — O(K) where K = pairs written.
784
+ */
785
+ type CheckSyncPairs<DATA extends object, T extends readonly [string, string][], Depth extends number = DefaultDepth> = {
786
+ [I in keyof T]: T[I] extends [
787
+ infer P1 extends string,
788
+ infer P2 extends string
789
+ ] ? CheckPairValueMatch<DATA, P1, P2, Depth> : T[I];
790
+ };
791
+ /**
792
+ * Validates that two paths both resolve to number.
793
+ * Returns [ComputationOp, P1, P2] or [ComputationOp, P1, P2, BoolLogic] on match.
794
+ */
795
+ type CheckComputationPairValueMatch<DATA extends object, P1 extends string, P2 extends string, Depth extends number = DefaultDepth> = [P1] extends [DeepKeyFiltered<DATA, number, Depth>] ? [P2] extends [DeepKeyFiltered<DATA, number, Depth>] ? true : false : false;
796
+ /**
797
+ * Validates an array of aggregation pairs: [target, source] or [target, source, BoolLogic].
798
+ * Each pair checks that target and source resolve to the same value type.
799
+ */
800
+ type CheckAggregationPairs<DATA extends object, T extends readonly (readonly [string, string] | readonly [string, string, BoolLogic<DATA, Depth>])[], Depth extends number = DefaultDepth> = {
801
+ [I in keyof T]: T[I] extends readonly [
802
+ infer P1 extends string,
803
+ infer P2 extends string,
804
+ infer BL
805
+ ] ? CheckPairValueMatch<DATA, P1, P2, Depth> extends [P1, P2] ? [P1, P2, BL] : [P1, never, BL] : T[I] extends readonly [infer P1 extends string, infer P2 extends string] ? CheckPairValueMatch<DATA, P1, P2, Depth> : T[I];
806
+ };
807
+ /**
808
+ * Validates an array of computation pairs: [op, target, source] or [op, target, source, BoolLogic].
809
+ * Both target and source must be number paths.
810
+ */
811
+ type CheckComputationPairs<DATA extends object, T extends readonly (readonly [ComputationOp, string, string] | readonly [ComputationOp, string, string, BoolLogic<DATA, Depth>])[], Depth extends number = DefaultDepth> = {
812
+ [I in keyof T]: T[I] extends readonly [
813
+ infer Op extends ComputationOp,
814
+ infer P1 extends string,
815
+ infer P2 extends string,
816
+ infer BL
817
+ ] ? CheckComputationPairValueMatch<DATA, P1, P2, Depth> extends true ? [Op, P1, P2, BL] : [Op, P1, never, BL] : T[I] extends readonly [
818
+ infer Op extends ComputationOp,
819
+ infer P1 extends string,
820
+ infer P2 extends string
821
+ ] ? CheckComputationPairValueMatch<DATA, P1, P2, Depth> extends true ? [Op, P1, P2] : [Op, P1, never] : T[I];
822
+ };
823
+
824
+ /** Recursively makes all properties required, stripping undefined */
825
+ type DeepRequired<T> = {
826
+ [K in keyof T]-?: NonNullable<T[K]> extends object ? DeepRequired<NonNullable<T[K]>> : NonNullable<T[K]>;
827
+ };
828
+ /**
829
+ * Recursively makes all properties optional (allows undefined values).
830
+ *
831
+ * Written as a conditional type so TypeScript distributes it over union members
832
+ * automatically — null/undefined fall through to `: T` and are preserved as-is.
833
+ * Array check comes before object so arrays are not mapped over their keys.
834
+ */
835
+ type DeepPartial<T> = T extends (infer U)[] ? DeepPartial<U>[] : T extends readonly (infer U)[] ? readonly DeepPartial<U>[] : T extends object ? {
836
+ [K in keyof T]?: DeepPartial<T[K]>;
837
+ } : T;
838
+
839
+ /**
840
+ * Validated pair branded types
841
+ *
842
+ * Phantom types for pre-validated pair arrays returned by helper functions
843
+ * (syncPairs, flipPairs, aggregationPairs, computationPairs).
844
+ *
845
+ * Brands serve two purposes:
846
+ * 1. SideEffects accepts them without re-resolving the O(N²) direct pair types
847
+ * 2. DATA generic prevents cross-store use (pairs from StoreA can't go to StoreB)
848
+ *
849
+ * Zero runtime cost — brands are erased at compile time.
850
+ */
851
+
852
+ declare const VALIDATED: unique symbol;
853
+ declare const STORE_DATA: unique symbol;
854
+ /** Pre-validated sync pair array. Returned by `syncPairs()`. Branded with DATA to prevent cross-store use. */
855
+ type ValidatedSyncPairs<DATA extends object = object> = [
856
+ string,
857
+ string
858
+ ][] & {
859
+ [VALIDATED]: 'sync';
860
+ [STORE_DATA]: DATA;
861
+ };
862
+ /** Pre-validated flip pair array. Returned by `flipPairs()`. Branded with DATA to prevent cross-store use. */
863
+ type ValidatedFlipPairs<DATA extends object = object> = [
864
+ string,
865
+ string
866
+ ][] & {
867
+ [VALIDATED]: 'flip';
868
+ [STORE_DATA]: DATA;
869
+ };
870
+ /** Pre-validated aggregation pair array. Returned by `aggregationPairs()`. Branded with DATA to prevent cross-store use. */
871
+ type ValidatedAggregationPairs<DATA extends object = object> = ([string, string] | [string, string, unknown])[] & {
872
+ [VALIDATED]: 'aggregation';
873
+ [STORE_DATA]: DATA;
874
+ };
875
+ /** Pre-validated computation pair array. Returned by `computationPairs()`. Branded with DATA to prevent cross-store use. */
876
+ type ValidatedComputationPairs<DATA extends object = object> = ([ComputationOp, string, string] | [ComputationOp, string, string, unknown])[] & {
877
+ [VALIDATED]: 'computation';
878
+ [STORE_DATA]: DATA;
879
+ };
880
+ /** Pre-validated listener array. Returned by `listeners()`. Branded with DATA to prevent cross-store use.
881
+ * Uses intersection with ListenerRegistration[] so it's assignable to the listeners field
882
+ * without needing a union — preserving contextual typing for inline fn parameters.
883
+ */
884
+ type ValidatedListeners<DATA extends object = object, META extends GenericMeta = GenericMeta> = ListenerRegistration<DATA, META>[] & {
885
+ [VALIDATED]: 'listeners';
886
+ [STORE_DATA]: DATA;
887
+ };
888
+
889
+ interface BaseConcernProps<STATE, PATH extends string> {
890
+ state: STATE;
891
+ path: PATH;
892
+ value: unknown;
893
+ }
894
+ interface ConcernType<NAME extends string = string, EXTRA_PROPS = Record<string, unknown>, RETURN_TYPE = unknown> {
895
+ name: NAME;
896
+ description: string;
897
+ /** Evaluated inside effect() - all state accesses are tracked */
898
+ evaluate: (props: BaseConcernProps<Record<string, unknown>, string> & EXTRA_PROPS) => RETURN_TYPE;
899
+ }
900
+ interface ConcernRegistration {
901
+ id: string;
902
+ path: string;
903
+ concernName: string;
904
+ concern: ConcernType;
905
+ config: Record<string, unknown>;
906
+ dispose: () => void;
907
+ }
908
+
909
+ /**
910
+ * Debug Timing Utilities
911
+ *
912
+ * Provides timing measurement for concerns and listeners
913
+ * to detect slow operations during development.
914
+ */
915
+ type TimingType = 'concerns' | 'listeners' | 'registration';
916
+ interface TimingMeta {
917
+ path: string;
918
+ name: string;
919
+ }
920
+ interface Timing {
921
+ run: <T>(type: TimingType, fn: () => T, meta: TimingMeta) => T;
922
+ reportBatch: (type: TimingType) => void;
923
+ }
924
+
925
+ /**
926
+ * WASM Bridge — Thin namespace over Rust/WASM exports.
927
+ *
928
+ * Uses serde-wasm-bindgen for hot-path functions (processChanges,
929
+ * shadowInit) — JS objects cross the boundary directly without JSON
930
+ * string intermediary. Registration functions still use JSON strings
931
+ * (cold path, simpler).
932
+ *
933
+ * Loading is handled by `wasm/lifecycle.ts`. After loading, all bridge
934
+ * functions are synchronous.
935
+ *
936
+ * @module wasm/bridge
937
+ */
938
+
939
+ /** A single state change (input or output). */
940
+ interface Change {
941
+ path: string;
942
+ value: unknown;
943
+ origin?: string;
944
+ }
945
+ /** A single dispatch entry with sequential ID and input change references. */
946
+ interface DispatchEntry {
947
+ dispatch_id: number;
948
+ subscriber_id: number;
949
+ scope_path: string;
950
+ /** Indexes into ProcessResult.changes array. */
951
+ input_change_ids: number[];
952
+ }
953
+ /** A group of dispatches to execute sequentially. */
954
+ interface DispatchGroup {
955
+ dispatches: DispatchEntry[];
956
+ }
957
+ /** A target for propagating produced changes from child to parent dispatch. */
958
+ interface PropagationTarget {
959
+ target_dispatch_id: number;
960
+ /** Prefix to prepend to child's relative paths for the target's scope. */
961
+ remap_prefix: string;
962
+ }
963
+ /** Pre-computed execution plan with propagation map. */
964
+ interface FullExecutionPlan {
965
+ groups: DispatchGroup[];
966
+ /** propagation_map[dispatch_id] = targets to forward produced changes to. */
967
+ propagation_map: PropagationTarget[][];
968
+ }
969
+ /** Validator dispatch info for JS-side execution. */
970
+ interface ValidatorDispatch {
971
+ validator_id: number;
972
+ output_path: string;
973
+ dependency_values: Record<string, string>;
974
+ }
975
+ /**
976
+ * Extends a base tuple with an optional trailing BoolLogic condition (JSON-serialized).
977
+ * Used by aggregation and computation pairs to share the "optional excludeWhen" pattern.
978
+ */
979
+ type WasmPairWithCondition<Base extends [...string[]]> = [...Base] | [...Base, condition: string];
980
+ /** WASM-side aggregation pair: [target, source] with optional excludeWhen condition. */
981
+ type WasmAggregationPair = WasmPairWithCondition<[
982
+ target: string,
983
+ source: string
984
+ ]>;
985
+ /** WASM-side computation pair: [operation, target, source] with optional excludeWhen condition. */
986
+ type WasmComputationPair = WasmPairWithCondition<[
987
+ op: string,
988
+ target: string,
989
+ source: string
990
+ ]>;
991
+ /** WASM-side sync pair: [source, target] — bidirectional sync. */
992
+ type WasmSyncPair = [source: string, target: string];
993
+ /** WASM-side flip pair: [source, target] — inverted boolean sync. */
994
+ type WasmFlipPair = [source: string, target: string];
995
+ /** WASM-side clear path rule: trigger paths → target paths to null. */
996
+ interface WasmClearPathRule {
997
+ triggers: string[];
998
+ targets: string[];
999
+ }
1000
+ /** WASM-side listener entry for topic-based dispatch. */
1001
+ interface WasmListenerEntry {
1002
+ subscriber_id: number;
1003
+ topic_path: string;
1004
+ scope_path: string;
1005
+ }
1006
+ /** Consolidated registration input for side effects (sync, flip, aggregation, computation, clear, listeners). */
1007
+ interface SideEffectsRegistration {
1008
+ registration_id: string;
1009
+ sync_pairs?: WasmSyncPair[];
1010
+ flip_pairs?: WasmFlipPair[];
1011
+ aggregation_pairs?: WasmAggregationPair[];
1012
+ computation_pairs?: WasmComputationPair[];
1013
+ clear_paths?: WasmClearPathRule[];
1014
+ listeners?: WasmListenerEntry[];
1015
+ }
1016
+ /** Consolidated registration output from side effects registration. */
1017
+ interface SideEffectsResult {
1018
+ sync_changes: Change[];
1019
+ aggregation_changes: Change[];
1020
+ computation_changes: Change[];
1021
+ registered_listener_ids: number[];
1022
+ }
1023
+ /** WASM-side BoolLogic entry for declarative boolean evaluation. */
1024
+ interface WasmBoolLogicEntry {
1025
+ output_path: string;
1026
+ tree_json: string;
1027
+ }
1028
+ /** WASM-side validator entry for validation orchestration. */
1029
+ interface WasmValidatorEntry {
1030
+ validator_id: number;
1031
+ output_path: string;
1032
+ dependency_paths: string[];
1033
+ scope: string;
1034
+ }
1035
+ /** WASM-side ValueLogic entry for declarative value computation. */
1036
+ interface WasmValueLogicEntry {
1037
+ output_path: string;
1038
+ tree_json: string;
1039
+ }
1040
+ /** Consolidated registration input for concerns (BoolLogic, validators, and ValueLogic). */
1041
+ interface ConcernsRegistration {
1042
+ registration_id: string;
1043
+ bool_logics?: WasmBoolLogicEntry[];
1044
+ validators?: WasmValidatorEntry[];
1045
+ value_logics?: WasmValueLogicEntry[];
1046
+ }
1047
+ /** Consolidated registration output from concerns registration. */
1048
+ interface ConcernsResult {
1049
+ bool_logic_changes: Change[];
1050
+ registered_logic_ids: number[];
1051
+ registered_validator_ids: number[];
1052
+ value_logic_changes: Change[];
1053
+ registered_value_logic_ids: number[];
1054
+ }
1055
+ /** Result of processChanges (Phase 1). */
1056
+ interface ProcessChangesResult {
1057
+ state_changes: Change[];
1058
+ changes: Change[];
1059
+ validators_to_run: ValidatorDispatch[];
1060
+ execution_plan: FullExecutionPlan | null;
1061
+ has_work: boolean;
1062
+ }
1063
+ /**
1064
+ * An isolated WASM pipeline instance.
1065
+ * Each store gets its own pipeline so multiple Providers don't interfere.
1066
+ * All methods are pre-bound to the pipeline's ID — consumers never pass IDs.
1067
+ */
1068
+ interface WasmPipeline {
1069
+ readonly id: number;
1070
+ shadowInit: (state: object) => void;
1071
+ shadowDump: () => unknown;
1072
+ processChanges: (changes: Change[]) => ProcessChangesResult;
1073
+ pipelineFinalize: (jsChanges: Change[]) => {
1074
+ state_changes: Change[];
1075
+ };
1076
+ registerSideEffects: (reg: SideEffectsRegistration) => SideEffectsResult;
1077
+ unregisterSideEffects: (registrationId: string) => void;
1078
+ registerConcerns: (reg: ConcernsRegistration) => ConcernsResult;
1079
+ unregisterConcerns: (registrationId: string) => void;
1080
+ registerBoolLogic: (outputPath: string, tree: unknown) => number;
1081
+ unregisterBoolLogic: (logicId: number) => void;
1082
+ pipelineReset: () => void;
1083
+ destroy: () => void;
1084
+ /** Per-instance storage for validation schemas (can't cross WASM boundary). */
1085
+ validatorSchemas: Map<number, ValidationSchema>;
1086
+ }
1087
+
1088
+ /**
1089
+ * PathGroups Data Structure
1090
+ *
1091
+ * A custom data structure that provides O(1) connected component lookups
1092
+ * instead of O(V+E) recomputation on every change like graphology's connectedComponents.
1093
+ *
1094
+ * When wasmGraphType is set ('sync' | 'flip'), addEdge/removeEdge automatically
1095
+ * mirror registrations to WASM bridge for pipeline processing.
1096
+ *
1097
+ * Operations complexity:
1098
+ * - getAllGroups(): O(G) where G is number of groups (typically small)
1099
+ * - getGroupPaths(path): O(1) lookup
1100
+ * - addEdge(p1, p2): O(n) where n is smaller group size (merge)
1101
+ * - removeEdge(p1, p2): O(n) for affected component
1102
+ * - hasPath(path): O(1)
1103
+ * - hasEdge(p1, p2): O(1)
1104
+ */
1105
+ /** Graph type for WASM mirroring. When set, addEdge/removeEdge mirror to WASM. */
1106
+ type WasmGraphType = 'sync' | 'flip';
1107
+ /**
1108
+ * PathGroups maintains connected components with O(1) lookups.
1109
+ *
1110
+ * Internal structure:
1111
+ * - pathToGroup: Maps each path to its group ID
1112
+ * - groupToPaths: Maps each group ID to the set of paths in that group
1113
+ * - edges: Set of edge keys for edge existence checks and proper removal
1114
+ * - adjacency: Maps each path to its direct neighbors (for split detection on removal)
1115
+ * - nextGroupId: Counter for generating unique group IDs
1116
+ */
1117
+ interface PathGroups {
1118
+ pathToGroup: Map<string, number>;
1119
+ groupToPaths: Map<number, Set<string>>;
1120
+ edges: Set<string>;
1121
+ adjacency: Map<string, Set<string>>;
1122
+ nextGroupId: number;
1123
+ wasmGraphType?: WasmGraphType;
1124
+ }
1125
+
1126
+ /**
1127
+ * Graph Type Definitions
1128
+ *
1129
+ * Type aliases for the PathGroups data structure used in sync and flip operations.
1130
+ * These aliases maintain backward compatibility with the previous graphology-based API.
1131
+ */
1132
+
1133
+ /**
1134
+ * Sync graph: Paths that must have synchronized values
1135
+ * Type alias for PathGroups - maintains backward compatibility
1136
+ */
1137
+ type SyncGraph = PathGroups;
1138
+ /**
1139
+ * Flip graph: Paths with inverted boolean values
1140
+ * Type alias for PathGroups - maintains backward compatibility
1141
+ */
1142
+ type FlipGraph = PathGroups;
1143
+
1144
+ /**
1145
+ * Core Store Types
1146
+ *
1147
+ * Foundational type definitions for the store instance.
1148
+ * These types are used throughout the library.
1149
+ */
1150
+
1151
+ /**
1152
+ * Debug configuration for development tooling
1153
+ */
1154
+ interface DebugConfig {
1155
+ /** Enable timing measurement for concerns and listeners */
1156
+ timing?: boolean;
1157
+ /** Threshold in milliseconds for slow operation warnings (default: 5ms) */
1158
+ timingThreshold?: number;
1159
+ /** Enable tracking of processChanges calls and applied changes for testing/debugging */
1160
+ track?: boolean;
1161
+ }
1162
+ /**
1163
+ * A single recorded processChanges invocation
1164
+ */
1165
+ interface DebugTrackEntry {
1166
+ /** Input changes passed to processChanges as [path, value, meta] tuples */
1167
+ input: [string, unknown, unknown][];
1168
+ /** Changes actually applied to state proxy */
1169
+ applied: {
1170
+ path: string;
1171
+ value: unknown;
1172
+ }[];
1173
+ /** Changes applied to _concerns proxy */
1174
+ appliedConcerns: {
1175
+ path: string;
1176
+ value: unknown;
1177
+ }[];
1178
+ /** Timestamp of the call */
1179
+ timestamp: number;
1180
+ }
1181
+ /**
1182
+ * Debug tracking data exposed on StoreInstance when debug.track is enabled.
1183
+ * Provides an append-only log of all processChanges calls and their effects.
1184
+ */
1185
+ interface DebugTrack {
1186
+ /** All recorded processChanges calls (append-only) */
1187
+ calls: DebugTrackEntry[];
1188
+ /** Reset all tracking data */
1189
+ clear: () => void;
1190
+ }
1191
+ interface StoreConfig {
1192
+ /** Error storage path (default: "_errors") */
1193
+ errorStorePath?: string;
1194
+ /** Max iterations for change processing (default: 100) */
1195
+ maxIterations?: number;
1196
+ /** Debug configuration for development tooling */
1197
+ debug?: DebugConfig;
1198
+ /** Use legacy TypeScript implementation instead of WASM (default: false) */
1199
+ useLegacyImplementation?: boolean;
1200
+ }
1201
+ interface ProviderProps<DATA extends object> {
1202
+ initialState: DATA;
1203
+ children: ReactNode;
1204
+ }
1205
+ interface Aggregation {
1206
+ id?: string;
1207
+ targetPath: string;
1208
+ sourcePaths: string[];
1209
+ }
1210
+ /** Reacts to scoped changes - receives relative paths and scoped state. Only fires for NESTED paths, not the path itself.
1211
+ * Both input changes and return changes use paths relative to scope (or full paths when scope is null).
1212
+ *
1213
+ * When SUB_STATE is `any` (as in ListenerRegistration's default), the return type falls back to
1214
+ * ArrayOfChanges<DATA> to avoid DeepKey<any> resolving to never.
1215
+ */
1216
+ type IsAnyState<T> = 0 extends 1 & T ? true : false;
1217
+ type OnStateListener<DATA extends object = object, SUB_STATE = DATA, META extends GenericMeta = GenericMeta> = (changes: ArrayOfChanges<SUB_STATE, META>, state: SUB_STATE) => IsAnyState<SUB_STATE> extends true ? ArrayOfChanges<DATA, META> | undefined : ArrayOfChanges<SUB_STATE, META> | undefined;
1218
+ /**
1219
+ * Listener registration with path (what to watch) and scope (how to present data)
1220
+ *
1221
+ * @example
1222
+ * ```typescript
1223
+ * // Watch user.profile.name, get full state
1224
+ * {
1225
+ * path: 'user.profile.name',
1226
+ * scope: null,
1227
+ * fn: (changes, state) => {
1228
+ * // changes: [['user.profile.name', 'Alice', {}]] - FULL path
1229
+ * // state: full DATA object
1230
+ * }
1231
+ * }
1232
+ *
1233
+ * // Watch user.profile.*, get scoped state
1234
+ * {
1235
+ * path: 'user.profile',
1236
+ * scope: 'user.profile',
1237
+ * fn: (changes, state) => {
1238
+ * // changes: [['name', 'Alice', {}]] - RELATIVE to scope
1239
+ * // state: user.profile object
1240
+ * }
1241
+ * }
1242
+ *
1243
+ * // Watch deep path, get parent scope
1244
+ * {
1245
+ * path: 'p.123.g.abc.data.strike',
1246
+ * scope: 'p.123.g.abc',
1247
+ * fn: (changes, state) => {
1248
+ * // changes: [['data.strike', value, {}]] - relative to scope
1249
+ * // state: p.123.g.abc object
1250
+ * }
1251
+ * }
1252
+ * ```
1253
+ */
1254
+ interface ListenerRegistration<DATA extends object = object, META extends GenericMeta = GenericMeta, Depth extends number = DefaultDepth> {
1255
+ /**
1256
+ * Path to watch - only changes under this path will trigger the listener
1257
+ * null = watch all top-level paths
1258
+ */
1259
+ path: DeepKey<DATA, Depth> | null;
1260
+ /**
1261
+ * Scope for state and changes presentation
1262
+ * - If omitted/undefined: defaults to `path` (scoped state matching the watched path)
1263
+ * - If null: state is full DATA, changes use FULL paths
1264
+ * - If set: state is value at scope, changes use paths RELATIVE to scope
1265
+ *
1266
+ * Note: Changes are filtered based on `path`, even when scope is null
1267
+ */
1268
+ scope?: DeepKey<DATA, Depth> | null;
1269
+ fn: OnStateListener<DATA, any, META>;
1270
+ }
1271
+ interface ListenerHandlerRef {
1272
+ scope: string | null;
1273
+ fn: (...args: unknown[]) => unknown;
1274
+ }
1275
+ interface SideEffectGraphs<DATA extends object = object, META extends GenericMeta = GenericMeta> {
1276
+ sync: SyncGraph;
1277
+ flip: FlipGraph;
1278
+ listeners: Map<string, ListenerRegistration<DATA, META>[]>;
1279
+ sortedListenerPaths: string[];
1280
+ /** O(1) lookup: subscriber_id -> handler ref. Populated by registerListener. */
1281
+ listenerHandlers: Map<number, ListenerHandlerRef>;
1282
+ }
1283
+ interface Registrations {
1284
+ concerns: Map<string, ConcernType[]>;
1285
+ effectCleanups: Set<() => void>;
1286
+ sideEffectCleanups: Map<string, () => void>;
1287
+ aggregations: Map<string, Aggregation[]>;
1288
+ }
1289
+ interface ProcessingState<DATA extends object = object, META extends GenericMeta = GenericMeta> {
1290
+ queue: ArrayOfChanges<DATA, META>;
1291
+ }
1292
+ /** Internal store state (NOT tracked - wrapped in ref()) */
1293
+ interface InternalState<DATA extends object = object, META extends GenericMeta = GenericMeta> {
1294
+ graphs: SideEffectGraphs<DATA, META>;
1295
+ registrations: Registrations;
1296
+ processing: ProcessingState<DATA, META>;
1297
+ timing: Timing;
1298
+ config: DeepRequired<StoreConfig>;
1299
+ /** Per-store WASM pipeline instance (null when using legacy implementation). */
1300
+ pipeline: WasmPipeline | null;
1301
+ /** Pending deferred destroy timer — cancelled on StrictMode re-mount. */
1302
+ _destroyTimer?: ReturnType<typeof setTimeout> | undefined;
1303
+ }
1304
+ type ConcernValues = Record<string, Record<string, unknown>>;
1305
+ /** Two-proxy pattern: state and _concerns are independent to prevent infinite loops */
1306
+ interface StoreInstance<DATA extends object, META extends GenericMeta = GenericMeta> {
1307
+ state: DATA;
1308
+ _concerns: ConcernValues;
1309
+ _internal: InternalState<DATA, META>;
1310
+ /** Debug tracking data, only populated when debug.track is enabled */
1311
+ _debug: DebugTrack | null;
1312
+ }
1313
+
1314
+ interface ValidationError {
1315
+ field?: string;
1316
+ message: string;
1317
+ }
1318
+ interface ValidationStateResult {
1319
+ isError: boolean;
1320
+ errors: ValidationError[];
1321
+ }
1322
+ interface ValidationStateConcern {
1323
+ name: 'validationState';
1324
+ description: string;
1325
+ evaluate: <SUB_STATE, PATH extends DeepKey<SUB_STATE>>(props: BaseConcernProps<SUB_STATE, PATH> & ValidationStateInput<SUB_STATE, PATH>) => ValidationStateResult;
1326
+ }
1327
+ declare const validationState: ValidationStateConcern;
1328
+
1329
+ declare const disabledWhen: ConcernType<'disabledWhen', {
1330
+ boolLogic: BoolLogic<any>;
1331
+ }, boolean>;
1332
+
1333
+ /**
1334
+ * Read-only condition concern
1335
+ *
1336
+ * Evaluates a boolean logic expression to determine if a field should be read-only.
1337
+ * Automatically tracks all state paths accessed in the condition.
1338
+ *
1339
+ * Returns true if read-only, false if editable.
1340
+ *
1341
+ * @example
1342
+ * ```typescript
1343
+ * store.useConcerns('my-concerns', {
1344
+ * 'productId': {
1345
+ * readonlyWhen: { boolLogic: { IS_EQUAL: ['order.status', 'completed'] } }
1346
+ * }
1347
+ * })
1348
+ * // Returns: true if order status is 'completed', false otherwise
1349
+ * ```
1350
+ */
1351
+
1352
+ declare const readonlyWhen: ConcernType<'readonlyWhen', {
1353
+ boolLogic: BoolLogic<any>;
1354
+ }, boolean>;
1355
+
1356
+ /**
1357
+ * Visibility condition concern
1358
+ *
1359
+ * Evaluates a boolean logic expression to determine if a field should be visible.
1360
+ * Automatically tracks all state paths accessed in the condition.
1361
+ *
1362
+ * Returns true if visible, false if hidden.
1363
+ *
1364
+ * @example
1365
+ * ```typescript
1366
+ * store.useConcerns('my-concerns', {
1367
+ * 'advancedOptions': {
1368
+ * visibleWhen: { boolLogic: { IS_EQUAL: ['settings.mode', 'advanced'] } }
1369
+ * }
1370
+ * })
1371
+ * // Returns: true if settings.mode is 'advanced', false otherwise
1372
+ * ```
1373
+ */
1374
+
1375
+ declare const visibleWhen: ConcernType<'visibleWhen', {
1376
+ boolLogic: BoolLogic<any>;
1377
+ }, boolean>;
1378
+
1379
+ /**
1380
+ * Dynamic label template concern
1381
+ *
1382
+ * Interpolates a template string with values from state.
1383
+ * Automatically tracks all state paths referenced in the template.
1384
+ *
1385
+ * Returns the interpolated string.
1386
+ *
1387
+ * @example
1388
+ * ```typescript
1389
+ * store.useConcerns('my-concerns', {
1390
+ * 'priceField': {
1391
+ * dynamicLabel: { template: "Price: ${{product.price}}" }
1392
+ * }
1393
+ * })
1394
+ * // Result: "Price: $99.99"
1395
+ * ```
1396
+ */
1397
+
1398
+ declare const dynamicLabel: ConcernType<'dynamicLabel', {
1399
+ template: string;
1400
+ }, string>;
1401
+
1402
+ /**
1403
+ * Dynamic placeholder template concern
1404
+ *
1405
+ * Interpolates a template string with values from state.
1406
+ * Automatically tracks all state paths referenced in the template.
1407
+ *
1408
+ * Returns the interpolated string.
1409
+ *
1410
+ * @example
1411
+ * ```typescript
1412
+ * store.useConcerns('my-concerns', {
1413
+ * 'inputField': {
1414
+ * dynamicPlaceholder: { template: "Enter {{field.name}}" }
1415
+ * }
1416
+ * })
1417
+ * // Result: "Enter email address"
1418
+ * ```
1419
+ */
1420
+
1421
+ declare const dynamicPlaceholder: ConcernType<'dynamicPlaceholder', {
1422
+ template: string;
1423
+ }, string>;
1424
+
1425
+ /**
1426
+ * Dynamic tooltip template concern
1427
+ *
1428
+ * Interpolates a template string with values from state.
1429
+ * Automatically tracks all state paths referenced in the template.
1430
+ *
1431
+ * Returns the interpolated string.
1432
+ *
1433
+ * @example
1434
+ * ```typescript
1435
+ * store.useConcerns('my-concerns', {
1436
+ * 'strikePrice': {
1437
+ * dynamicTooltip: { template: "Strike at {{market.spot}}" }
1438
+ * }
1439
+ * })
1440
+ * // Result: "Strike at 105"
1441
+ * ```
1442
+ */
1443
+
1444
+ declare const dynamicTooltip: ConcernType<'dynamicTooltip', {
1445
+ template: string;
1446
+ }, string>;
1447
+
1448
+ /**
1449
+ * All pre-built concerns as a tuple (for use with findConcern)
1450
+ */
1451
+ declare const prebuilts: readonly [ValidationStateConcern, ConcernType<"disabledWhen", {
1452
+ boolLogic: BoolLogic<any>;
1453
+ }, boolean>, ConcernType<"readonlyWhen", {
1454
+ boolLogic: BoolLogic<any>;
1455
+ }, boolean>, ConcernType<"visibleWhen", {
1456
+ boolLogic: BoolLogic<any>;
1457
+ }, boolean>, ConcernType<"dynamicTooltip", {
1458
+ template: string;
1459
+ }, string>, ConcernType<"dynamicLabel", {
1460
+ template: string;
1461
+ }, string>, ConcernType<"dynamicPlaceholder", {
1462
+ template: string;
1463
+ }, string>];
1464
+ /**
1465
+ * Namespace style access for pre-builts
1466
+ */
1467
+ declare const prebuiltsNamespace: {
1468
+ validationState: ValidationStateConcern;
1469
+ disabledWhen: ConcernType<"disabledWhen", {
1470
+ boolLogic: BoolLogic<any>;
1471
+ }, boolean>;
1472
+ readonlyWhen: ConcernType<"readonlyWhen", {
1473
+ boolLogic: BoolLogic<any>;
1474
+ }, boolean>;
1475
+ visibleWhen: ConcernType<"visibleWhen", {
1476
+ boolLogic: BoolLogic<any>;
1477
+ }, boolean>;
1478
+ dynamicTooltip: ConcernType<"dynamicTooltip", {
1479
+ template: string;
1480
+ }, string>;
1481
+ dynamicLabel: ConcernType<"dynamicLabel", {
1482
+ template: string;
1483
+ }, string>;
1484
+ dynamicPlaceholder: ConcernType<"dynamicPlaceholder", {
1485
+ template: string;
1486
+ }, string>;
1487
+ };
1488
+
1489
+ type index_ValidationError = ValidationError;
1490
+ type index_ValidationStateConcern = ValidationStateConcern;
1491
+ type index_ValidationStateInput<DATA, PATH extends DeepKey<DATA, Depth>, Depth extends number = DefaultDepth> = ValidationStateInput<DATA, PATH, Depth>;
1492
+ type index_ValidationStateResult = ValidationStateResult;
1493
+ declare const index_disabledWhen: typeof disabledWhen;
1494
+ declare const index_dynamicLabel: typeof dynamicLabel;
1495
+ declare const index_dynamicPlaceholder: typeof dynamicPlaceholder;
1496
+ declare const index_dynamicTooltip: typeof dynamicTooltip;
1497
+ declare const index_prebuilts: typeof prebuilts;
1498
+ declare const index_prebuiltsNamespace: typeof prebuiltsNamespace;
1499
+ declare const index_readonlyWhen: typeof readonlyWhen;
1500
+ declare const index_validationState: typeof validationState;
1501
+ declare const index_visibleWhen: typeof visibleWhen;
1502
+ declare namespace index {
1503
+ export { type index_ValidationError as ValidationError, type index_ValidationStateConcern as ValidationStateConcern, type index_ValidationStateInput as ValidationStateInput, type index_ValidationStateResult as ValidationStateResult, index_disabledWhen as disabledWhen, index_dynamicLabel as dynamicLabel, index_dynamicPlaceholder as dynamicPlaceholder, index_dynamicTooltip as dynamicTooltip, index_prebuilts as prebuilts, index_prebuiltsNamespace as prebuiltsNamespace, index_readonlyWhen as readonlyWhen, index_validationState as validationState, index_visibleWhen as visibleWhen };
1504
+ }
1505
+
1506
+ /**
1507
+ * Concern lookup by name
1508
+ *
1509
+ * @param name The concern name to look up
1510
+ * @param concerns Optional array of concerns to search (defaults to prebuilts)
1511
+ * @returns The concern definition, or undefined if not found
1512
+ */
1513
+ declare const findConcern: (name: string, concerns?: readonly any[]) => ConcernType | undefined;
1514
+ /**
1515
+ * Default concerns provided by apex-state
1516
+ */
1517
+ declare const defaultConcerns: readonly [ValidationStateConcern, ConcernType<"disabledWhen", {
1518
+ boolLogic: BoolLogic<any>;
1519
+ }, boolean>, ConcernType<"readonlyWhen", {
1520
+ boolLogic: BoolLogic<any>;
1521
+ }, boolean>, ConcernType<"visibleWhen", {
1522
+ boolLogic: BoolLogic<any>;
1523
+ }, boolean>, ConcernType<"dynamicTooltip", {
1524
+ template: string;
1525
+ }, string>, ConcernType<"dynamicLabel", {
1526
+ template: string;
1527
+ }, string>, ConcernType<"dynamicPlaceholder", {
1528
+ template: string;
1529
+ }, string>];
1530
+
1531
+ /**
1532
+ * SideEffects type definition
1533
+ *
1534
+ * Configuration types for side effects passed to useSideEffects hook.
1535
+ * Simple tuple-based API: [path1, path2]
1536
+ */
1537
+
1538
+ /**
1539
+ * Clear path rule - "when trigger paths change, set target paths to null"
1540
+ *
1541
+ * Format: [triggers[], targets[], options?]
1542
+ * - triggers: paths that activate the rule
1543
+ * - targets: paths to set to null
1544
+ * - expandMatch: if true, [*] in targets expands to ALL keys (not just matched key)
1545
+ */
1546
+ type ClearPathRule<DATA extends object, Depth extends number = DefaultDepth> = [DeepKey<DATA, Depth>[], DeepKey<DATA, Depth>[], {
1547
+ expandMatch?: boolean;
1548
+ }?];
1549
+ /**
1550
+ * Side effects configuration for useSideEffects hook
1551
+ *
1552
+ * @example
1553
+ * ```typescript
1554
+ * useSideEffects('my-effects', {
1555
+ * syncPaths: [
1556
+ * ['user.email', 'profile.email'],
1557
+ * ],
1558
+ * flipPaths: [
1559
+ * ['isActive', 'isInactive'],
1560
+ * ],
1561
+ * aggregations: [
1562
+ * ['total', 'price1'], // target <- source (target always first)
1563
+ * ['total', 'price2'],
1564
+ * ],
1565
+ * listeners: [
1566
+ * {
1567
+ * path: 'user.profile', // Watch user.profile.* changes
1568
+ * scope: 'user.profile', // Receive scoped state
1569
+ * fn: (changes, state) => {
1570
+ * // changes: [['name', 'Alice', {}]] // RELATIVE to scope
1571
+ * // state: user.profile sub-object
1572
+ * return [['status', 'updated', {}]] // Return SCOPED paths (relative to scope)
1573
+ * }
1574
+ * },
1575
+ * {
1576
+ * path: 'user.profile.name', // Watch specific path
1577
+ * scope: null, // Get full state
1578
+ * fn: (changes, state) => {
1579
+ * // changes: [['user.profile.name', 'Alice', {}]] // FULL path
1580
+ * // state: full DATA object
1581
+ * return undefined
1582
+ * }
1583
+ * },
1584
+ * {
1585
+ * path: 'p.123.g.abc.data.strike', // Watch deep path
1586
+ * scope: 'p.123.g.abc', // Get parent scope
1587
+ * fn: (changes, state) => {
1588
+ * // changes: [['data.strike', value, {}]] // RELATIVE to scope
1589
+ * // state: p.123.g.abc object
1590
+ * return [['data.computed', computed, {}]] // SCOPED path (relative to scope)
1591
+ * }
1592
+ * }
1593
+ * ]
1594
+ * })
1595
+ * ```
1596
+ */
1597
+ interface SideEffects<DATA extends object, META extends GenericMeta = GenericMeta, Depth extends number = DefaultDepth> {
1598
+ /**
1599
+ * Sync paths - keeps specified paths synchronized
1600
+ * Format: [path1, path2] - both paths stay in sync
1601
+ * Accepts direct `SyncPair<T>[]` or pre-validated result from `syncPairs()`.
1602
+ */
1603
+ syncPaths?: SyncPair<DATA, Depth>[] | ValidatedSyncPairs<DATA>;
1604
+ /**
1605
+ * Flip paths - keeps specified paths with opposite values
1606
+ * Format: [path1, path2] - paths have inverse boolean values
1607
+ * Accepts direct `FlipPair<T>[]` or pre-validated result from `flipPairs()`.
1608
+ */
1609
+ flipPaths?: FlipPair<DATA, Depth>[] | ValidatedFlipPairs<DATA>;
1610
+ /**
1611
+ * Aggregations - aggregates sources into target
1612
+ * Format: [target, source] - target is ALWAYS first (left)
1613
+ * Multiple pairs can point to same target for multi-source aggregation
1614
+ * Accepts direct `AggregationPair<T>[]` or pre-validated result from `aggregationPairs()`.
1615
+ */
1616
+ aggregations?: AggregationPair<DATA, Depth>[] | ValidatedAggregationPairs<DATA>;
1617
+ /**
1618
+ * Clear paths - "when X changes, set Y to null"
1619
+ * Format: [triggers[], targets[], { expandMatch?: boolean }?]
1620
+ * - Default: [*] in target correlates with trigger's [*] (same key)
1621
+ * - expandMatch: true → [*] in target expands to ALL keys
1622
+ */
1623
+ clearPaths?: ClearPathRule<DATA, Depth>[];
1624
+ /**
1625
+ * Computations - numeric reduction operations (SUM, AVG)
1626
+ * Format: [operation, target, source] - target is computed from sources
1627
+ * Multiple pairs can point to same target for multi-source computation
1628
+ * Unidirectional: source → target only (writes to target are no-op)
1629
+ * Accepts direct `ComputationPair<T>[]` or pre-validated result from `computationPairs()`.
1630
+ */
1631
+ computations?: ComputationPair<DATA, Depth>[] | ValidatedComputationPairs<DATA>;
1632
+ /**
1633
+ * Listeners - react to state changes with scoped state
1634
+ * Accepts direct `ListenerRegistration<T>[]` or pre-validated result from `listeners()`.
1635
+ */
1636
+ listeners?: ListenerRegistration<DATA, META>[];
1637
+ }
1638
+
1639
+ declare const createGenericStore: <DATA extends object, META extends GenericMeta = GenericMeta, CONCERNS extends readonly ConcernType<string, any, any>[] = typeof defaultConcerns>(config?: StoreConfig) => {
1640
+ syncPairs: <T extends [Exclude<DeepKey<DATA, 20>, `${string}??`>, Exclude<DeepKey<DATA, 20>, `${string}??`>][]>(pairs: CheckSyncPairs<DATA, T, 20>) => ValidatedSyncPairs<DATA>;
1641
+ flipPairs: <T extends [Exclude<DeepKey<DATA, 20>, `${string}??`>, Exclude<DeepKey<DATA, 20>, `${string}??`>][]>(pairs: CheckSyncPairs<DATA, T, 20>) => ValidatedFlipPairs<DATA>;
1642
+ aggregationPairs: <T extends ([Exclude<DeepKey<DATA, 20>, `${string}??`>, Exclude<DeepKey<DATA, 20>, `${string}??`>] | [Exclude<DeepKey<DATA, 20>, `${string}??`>, Exclude<DeepKey<DATA, 20>, `${string}??`>, BoolLogic<DATA, 20>])[]>(pairs: CheckAggregationPairs<DATA, T, 20>) => ValidatedAggregationPairs<DATA>;
1643
+ computationPairs: <T extends ([ComputationOp, DeepKeyFiltered<DATA, number, 20>, DeepKeyFiltered<DATA, number, 20>] | [ComputationOp, DeepKeyFiltered<DATA, number, 20>, DeepKeyFiltered<DATA, number, 20>, BoolLogic<DATA, 20>])[]>(pairs: CheckComputationPairs<DATA, T, 20>) => ValidatedComputationPairs<DATA>;
1644
+ listeners: <T extends readonly {
1645
+ path: Exclude<DeepKey<DATA, 20>, `${string}??`> | null;
1646
+ scope?: Exclude<DeepKey<DATA, 20>, `${string}??`> | null | undefined;
1647
+ fn: (...args: any[]) => any;
1648
+ }[]>(items: CheckListeners<DATA, META, T, 20>) => ValidatedListeners<DATA, META>;
1649
+ Provider: {
1650
+ (props: ProviderProps<DATA>): react_jsx_runtime.JSX.Element;
1651
+ displayName: string;
1652
+ };
1653
+ useFieldStore: <P extends DeepKey<DATA>>(path: P) => {
1654
+ value: DeepValue<DATA, P>;
1655
+ setValue: (newValue: DeepValue<DATA, P>, meta?: META) => void;
1656
+ } & Record<string, unknown>;
1657
+ useStore: <P extends DeepKey<DATA>>(path: P) => [DeepValue<DATA, P>, (value: DeepValue<DATA, P>, meta?: META) => void];
1658
+ useJitStore: () => {
1659
+ proxyValue: DATA;
1660
+ setChanges: (changes: ArrayOfChanges<DATA, META>) => void;
1661
+ getState: () => DATA;
1662
+ };
1663
+ useSideEffects: (id: string, effects: SideEffects<DATA, META>) => void;
1664
+ useConcerns: <CUSTOM extends readonly ConcernType<string, any, any>[] = readonly []>(id: string, registration: ConcernRegistrationMap<DATA, readonly [...CONCERNS, ...CUSTOM]>, customConcerns?: CUSTOM) => void;
1665
+ withConcerns: <SELECTION extends Partial<Record<Extract<CONCERNS[number], {
1666
+ name: string;
1667
+ }>["name"], boolean>>>(selection: SELECTION) => {
1668
+ useFieldStore: <P extends DeepKey<DATA>>(path: P) => {
1669
+ value: DATA extends readonly any[] ? DATA[number] : P extends `${infer First}.${infer Rest}` ? First extends keyof DATA ? DeepValue<NonNullable<DATA[First]>, Rest> : string extends keyof DATA ? First extends "[*]" ? DeepValue<DATA[keyof DATA & string], Rest> : unknown : unknown : P extends "[*]" ? string extends keyof DATA ? DATA[keyof DATA & string] : unknown : P extends keyof DATA ? DATA[P] : unknown;
1670
+ setValue: (newValue: DATA extends readonly any[] ? DATA[number] : P extends `${infer First}.${infer Rest}` ? First extends keyof DATA ? DeepValue<NonNullable<DATA[First]>, Rest> : string extends keyof DATA ? First extends "[*]" ? DeepValue<DATA[keyof DATA & string], Rest> : unknown : unknown : P extends "[*]" ? string extends keyof DATA ? DATA[keyof DATA & string] : unknown : P extends keyof DATA ? DATA[P] : unknown, meta?: META) => void;
1671
+ } & { [K in keyof SELECTION as SELECTION[K] extends true ? K : never]?: K extends keyof EvaluatedConcerns<CONCERNS> ? EvaluatedConcerns<CONCERNS>[K] : never; };
1672
+ };
1673
+ withMeta: (presetMeta: Partial<META>) => {
1674
+ useFieldStore: <P extends DeepKey<DATA>>(path: P) => {
1675
+ value: DeepValue<DATA, P>;
1676
+ setValue: (newValue: DeepValue<DATA, P>, meta?: META) => void;
1677
+ };
1678
+ };
1679
+ };
1680
+ /** Return type of createGenericStore — used by testing mock for 1:1 type safety */
1681
+ type GenericStoreApi<DATA extends object, META extends GenericMeta = GenericMeta, CONCERNS extends readonly ConcernType<string, any, any>[] = typeof defaultConcerns> = ReturnType<typeof createGenericStore<DATA, META, CONCERNS>>;
1682
+
1683
+ /**
1684
+ * Minimal field interface that useBufferedField accepts
1685
+ */
1686
+ interface FieldInput$2<T> {
1687
+ value: T;
1688
+ setValue: (v: T) => void;
1689
+ }
1690
+ /**
1691
+ * Extended interface with buffering capabilities
1692
+ */
1693
+ interface BufferedField<T> extends FieldInput$2<T> {
1694
+ commit: () => void;
1695
+ cancel: () => void;
1696
+ isDirty: boolean;
1697
+ }
1698
+ /**
1699
+ * Adds buffered editing to any field hook.
1700
+ * Local changes are held until explicitly committed or cancelled.
1701
+ *
1702
+ * @param field - Field hook with { value, setValue }
1703
+ * @returns Buffered field with commit/cancel/isDirty
1704
+ *
1705
+ * @example
1706
+ * ```typescript
1707
+ * const field = useFieldStore('user.name')
1708
+ * const buffered = useBufferedField(field)
1709
+ *
1710
+ * // User types - updates local only
1711
+ * buffered.setValue('new value')
1712
+ *
1713
+ * // Enter/Tab - commit to store
1714
+ * buffered.commit()
1715
+ *
1716
+ * // Esc - revert to stored value
1717
+ * buffered.cancel()
1718
+ *
1719
+ * // Check if user has unsaved changes
1720
+ * if (buffered.isDirty) { ... }
1721
+ * ```
1722
+ */
1723
+ declare const useBufferedField: <T>(field: FieldInput$2<T>) => BufferedField<T>;
1724
+
1725
+ /**
1726
+ * Option for keyboard selection
1727
+ */
1728
+ interface SelectOption<T> {
1729
+ value: T;
1730
+ label: string;
1731
+ }
1732
+ /**
1733
+ * Configuration for keyboard select behavior
1734
+ */
1735
+ interface KeyboardSelectConfig<T> {
1736
+ /** Available options to select from */
1737
+ options: SelectOption<T>[];
1738
+ /** Time window to accumulate keystrokes (ms). Default: 500 */
1739
+ debounceMs?: number;
1740
+ /** Match from start of label only. Default: true */
1741
+ matchFromStart?: boolean;
1742
+ }
1743
+ /**
1744
+ * Minimal field interface that useKeyboardSelect accepts
1745
+ */
1746
+ interface FieldInput$1<T> {
1747
+ value: T;
1748
+ setValue: (v: T) => void;
1749
+ }
1750
+ /**
1751
+ * Adds keyboard-driven selection to any field hook.
1752
+ * Typing letters auto-selects matching options.
1753
+ *
1754
+ * @param field - Field hook with { value, setValue, ...rest }
1755
+ * @param config - Options and behavior configuration
1756
+ * @returns Field with onKeyDown handler added
1757
+ *
1758
+ * @example
1759
+ * ```typescript
1760
+ * const field = useFieldStore('user.country')
1761
+ * const { onKeyDown, ...rest } = useKeyboardSelect(field, {
1762
+ * options: [
1763
+ * { value: 'us', label: 'United States' },
1764
+ * { value: 'uk', label: 'United Kingdom' },
1765
+ * { value: 'ca', label: 'Canada' },
1766
+ * ]
1767
+ * })
1768
+ *
1769
+ * // User types "u" -> selects "United States"
1770
+ * // User types "un" quickly -> still "United States"
1771
+ * // User types "c" -> selects "Canada"
1772
+ *
1773
+ * <input onKeyDown={onKeyDown} {...rest} />
1774
+ * ```
1775
+ */
1776
+ declare const useKeyboardSelect: <T, TField extends FieldInput$1<T>>(field: TField, config: KeyboardSelectConfig<T>) => TField & {
1777
+ onKeyDown: (e: React.KeyboardEvent) => void;
1778
+ };
1779
+
1780
+ /**
1781
+ * Minimal field interface for throttling
1782
+ * Supports setValue with optional additional arguments (e.g., meta)
1783
+ */
1784
+ interface ThrottleFieldInput<T, Args extends unknown[] = unknown[]> {
1785
+ value: T;
1786
+ setValue: (v: T, ...args: Args) => void;
1787
+ }
1788
+ /**
1789
+ * Throttle configuration
1790
+ */
1791
+ interface ThrottleConfig {
1792
+ /** Minimum milliseconds between setValue calls to the underlying field */
1793
+ ms: number;
1794
+ }
1795
+ /**
1796
+ * Adds throttling to any field hook.
1797
+ * First setValue executes immediately, subsequent calls are rate-limited.
1798
+ * Last value wins when multiple calls occur within the throttle window.
1799
+ * Preserves the full setValue signature including additional arguments like meta.
1800
+ *
1801
+ * @param field - Field hook with { value, setValue, ...rest }
1802
+ * @param config - Throttle configuration { ms }
1803
+ * @returns Field with throttled setValue, plus any passthrough props
1804
+ *
1805
+ * @example
1806
+ * ```typescript
1807
+ * const field = useFieldStore('spotPrice')
1808
+ * const throttled = useThrottledField(field, { ms: 100 })
1809
+ *
1810
+ * // Rapid updates from WebSocket
1811
+ * throttled.setValue(1.234) // Immediate
1812
+ * throttled.setValue(1.235) // Buffered
1813
+ * throttled.setValue(1.236) // Buffered (replaces 1.235)
1814
+ * // After 100ms: 1.236 is applied
1815
+ * ```
1816
+ *
1817
+ * @example
1818
+ * ```typescript
1819
+ * // With meta argument
1820
+ * const field = useFieldStore('price')
1821
+ * const throttled = useThrottledField(field, { ms: 100 })
1822
+ * throttled.setValue(42, { source: 'websocket' })
1823
+ * ```
1824
+ *
1825
+ * @example
1826
+ * ```typescript
1827
+ * // Composable with other wrappers
1828
+ * const field = useFieldStore('price')
1829
+ * const transformed = useTransformedField(field, {
1830
+ * to: (cents) => cents / 100,
1831
+ * from: (dollars) => Math.round(dollars * 100)
1832
+ * })
1833
+ * const throttled = useThrottledField(transformed, { ms: 50 })
1834
+ * ```
1835
+ */
1836
+ declare const useThrottledField: <T, Args extends unknown[] = unknown[], TField extends ThrottleFieldInput<T, Args> = ThrottleFieldInput<T, Args>>(field: TField, config: ThrottleConfig) => TField;
1837
+
1838
+ /**
1839
+ * Transform configuration for field values
1840
+ */
1841
+ interface TransformConfig<TStored, TDisplay> {
1842
+ /** Transform from stored value to display value */
1843
+ to: (stored: TStored) => TDisplay;
1844
+ /** Transform from display value to stored value */
1845
+ from: (display: TDisplay) => TStored;
1846
+ }
1847
+ /**
1848
+ * Minimal field interface that useTransformedField accepts
1849
+ */
1850
+ interface FieldInput<T> {
1851
+ value: T;
1852
+ setValue: (v: T) => void;
1853
+ }
1854
+ /**
1855
+ * Adds value transformation to any field hook.
1856
+ * Converts between storage format and display format.
1857
+ * Passes through any additional properties from the input field.
1858
+ *
1859
+ * @param field - Field hook with { value, setValue, ...rest }
1860
+ * @param config - Transform functions { to, from }
1861
+ * @returns Field with transformed types, plus any passthrough props
1862
+ *
1863
+ * @example
1864
+ * ```typescript
1865
+ * const field = useFieldStore('user.birthdate')
1866
+ * const formatted = useTransformedField(field, {
1867
+ * to: (iso) => format(new Date(iso), 'MM/dd/yyyy'),
1868
+ * from: (display) => parse(display, 'MM/dd/yyyy').toISOString()
1869
+ * })
1870
+ *
1871
+ * // formatted.value is "01/15/2024"
1872
+ * // formatted.setValue("01/20/2024") stores ISO string
1873
+ * ```
1874
+ *
1875
+ * @example
1876
+ * ```typescript
1877
+ * // Works with buffered fields - passes through commit/cancel/isDirty
1878
+ * const field = useFieldStore('price')
1879
+ * const buffered = useBufferedField(field)
1880
+ * const formatted = useTransformedField(buffered, {
1881
+ * to: (cents) => (cents / 100).toFixed(2),
1882
+ * from: (dollars) => Math.round(parseFloat(dollars) * 100)
1883
+ * })
1884
+ *
1885
+ * formatted.setValue("15.99") // local only
1886
+ * formatted.commit() // stores 1599
1887
+ * ```
1888
+ */
1889
+ declare const useTransformedField: <TStored, TDisplay, TField extends FieldInput<TStored>>(field: TField, config: TransformConfig<TStored, TDisplay>) => Omit<TField, "value" | "setValue"> & FieldInput<TDisplay>;
1890
+
1891
+ /** Legacy JS implementation - uses JS graph structure */
1892
+ declare const registerFlipPair: <DATA extends object, META extends GenericMeta = GenericMeta>(store: StoreInstance<DATA, META>, path1: string & {}, path2: string & {}) => (() => void);
1893
+
1894
+ /** Legacy JS implementation - uses JS listener maps and sorted paths */
1895
+ declare const registerListenerLegacy: <DATA extends object, META extends GenericMeta = GenericMeta>(store: StoreInstance<DATA, META>, registration: ListenerRegistration<DATA, META>) => (() => void);
1896
+
1897
+ /**
1898
+ * Legacy batch version of registerSyncPair. Adds all edges first, then computes
1899
+ * initial sync changes across all final groups and calls processChanges once.
1900
+ * This avoids cascading effect re-evaluations when registering many pairs.
1901
+ */
1902
+ declare const registerSyncPairsBatch: <DATA extends object, META extends GenericMeta = GenericMeta>(store: StoreInstance<DATA, META>, pairs: [string & {}, string & {}][]) => (() => void);
1903
+
1904
+ declare const registerSideEffects: <DATA extends object, META extends GenericMeta = GenericMeta>(store: StoreInstance<DATA, META>, id: string, effects: SideEffects<DATA, META>) => (() => void);
1905
+
1906
+ declare const evaluateBoolLogic: <STATE extends object>(logic: BoolLogic<STATE>, state: STATE) => boolean;
1907
+
1908
+ /**
1909
+ * Template string interpolation utilities
1910
+ *
1911
+ * Core utility for interpolating state values into template strings.
1912
+ * Used by concerns and side effects for dynamic text generation.
1913
+ */
1914
+ /**
1915
+ * Extract all {{path}} placeholders from a template string
1916
+ *
1917
+ * @param template The template string with {{path}} placeholders
1918
+ * @returns Array of path strings found in the template
1919
+ *
1920
+ * @example
1921
+ * extractPlaceholders("Hello {{user.name}}, you have {{count}} messages")
1922
+ * // ["user.name", "count"]
1923
+ */
1924
+ declare const extractPlaceholders: (template: string) => string[];
1925
+ /**
1926
+ * Interpolate {{path}} placeholders with values from state
1927
+ *
1928
+ * Replaces {{path.to.value}} with actual values from state.
1929
+ * Only replaces if value is a string, number, or boolean.
1930
+ * Missing/null/undefined/object values leave the original {{path}} for debugging.
1931
+ *
1932
+ * @param template The template string with {{path}} placeholders
1933
+ * @param state The state object to read values from
1934
+ * @returns The interpolated string
1935
+ *
1936
+ * @example
1937
+ * interpolateTemplate("Value is {{market.spot}}", state)
1938
+ * // "Value is 105"
1939
+ *
1940
+ * @example
1941
+ * interpolateTemplate("Hello {{user.name}}, missing: {{invalid.path}}", state)
1942
+ * // "Hello Alice, missing: {{invalid.path}}"
1943
+ */
1944
+ declare const interpolateTemplate: <STATE extends object>(template: string, state: STATE) => string;
1945
+
1946
+ /**
1947
+ * Deep access utilities for safe nested object access
1948
+ *
1949
+ * Uses native Reflect for reads (~2x faster) and writes (~3x faster) vs lodash.
1950
+ * Maintains valtio reactivity when setting values.
1951
+ */
1952
+
1953
+ /**
1954
+ * Unified namespace for dot notation path operations
1955
+ *
1956
+ * Provides type-safe and unsafe variants for working with nested objects
1957
+ * using dot notation paths (e.g., 'user.address.city')
1958
+ */
1959
+ declare const dot: {
1960
+ get: <T extends object, P extends DeepKey<T>>(obj: T, path: P) => DeepValue<T, P>;
1961
+ get__unsafe: <P extends string>(obj: unknown, path: P) => unknown;
1962
+ set: <T extends object, P extends DeepKey<T>>(obj: T, path: P, value: DeepValue<T, P>) => void;
1963
+ set__unsafe: <T extends object, P extends string>(obj: T, path: P, value: unknown) => void;
1964
+ has: <T extends object, P extends DeepKey<T>>(obj: T, path: P) => boolean;
1965
+ same: <T extends object, P extends string>(obj: T, ...paths: P[]) => boolean;
1966
+ };
1967
+
1968
+ /**
1969
+ * Hash key utilities
1970
+ *
1971
+ * Utilities for working with hash key notation in Record-based paths.
1972
+ * Hash keys ([*]) are type-level markers for indexing into Records/HashMaps.
1973
+ *
1974
+ * @example
1975
+ * ```typescript
1976
+ * import { _, hashKey } from '@sladg/apex-state'
1977
+ *
1978
+ * // Use _ in template strings
1979
+ * const path = `users.${_('u1')}.posts.${_('p1')}.name`
1980
+ *
1981
+ * // Use hashKey namespace for validation
1982
+ * hashKey.rejectDynamic(path)
1983
+ * ```
1984
+ */
1985
+
1986
+ /**
1987
+ * Converts a concrete ID to hash key notation for inline template string usage
1988
+ * Returns the concrete ID typed as HASH_KEY for Record/HashMap indexing
1989
+ *
1990
+ * @param id - The concrete ID (e.g., "u1", "p1", "c1")
1991
+ * @returns The concrete ID typed as HASH_KEY
1992
+ *
1993
+ * @example
1994
+ * ```typescript
1995
+ * const path = `users.${_('u1')}.posts.${_('p1')}.name`
1996
+ * // → "users.u1.posts.p1.name" (typed as containing HASH_KEY)
1997
+ * ```
1998
+ */
1999
+ declare const _: (id: string) => HASH_KEY;
2000
+ /**
2001
+ * Hash key utilities namespace
2002
+ *
2003
+ * Provides utilities for working with hash keys in Record-based paths
2004
+ */
2005
+ declare const hashKey: {
2006
+ /** Reject paths with dynamic hash keys */
2007
+ readonly rejectDynamic: <P extends string>(path: P) => void;
2008
+ /** Alias for _ function */
2009
+ readonly _: (id: string) => HASH_KEY;
2010
+ };
2011
+
2012
+ /**
2013
+ * Type checking utilities — similar to lodash type guards
2014
+ *
2015
+ * Provides type-safe predicates for common type checks with TypeScript support
2016
+ */
2017
+
2018
+ /**
2019
+ * Unified namespace for type checking
2020
+ *
2021
+ * @example
2022
+ * ```typescript
2023
+ * import { is } from './utils/is'
2024
+ *
2025
+ * if (is.object(value)) { ... }
2026
+ * if (is.array(value)) { ... }
2027
+ * if (is.nil(value)) { ... }
2028
+ *
2029
+ * // Negated versions
2030
+ * if (is.not.object(value)) { ... }
2031
+ * if (is.not.array(value)) { ... }
2032
+ * ```
2033
+ */
2034
+ declare const is: {
2035
+ nil: (value: unknown) => value is null | undefined;
2036
+ undefined: (value: unknown) => value is undefined;
2037
+ null: (value: unknown) => value is null;
2038
+ object: (value: unknown) => value is Record<string, unknown>;
2039
+ objectOrArray: (value: unknown) => value is Record<string, unknown> | unknown[];
2040
+ array: (value: unknown) => value is unknown[];
2041
+ string: (value: unknown) => value is string;
2042
+ number: (value: unknown) => value is number;
2043
+ boolean: (value: unknown) => value is boolean;
2044
+ function: (value: unknown) => value is (...args: unknown[]) => unknown;
2045
+ symbol: (value: unknown) => value is symbol;
2046
+ date: (value: unknown) => value is Date;
2047
+ regexp: (value: unknown) => value is RegExp;
2048
+ numericKey: (value: string) => boolean;
2049
+ primitive: (value: unknown) => value is Primitive;
2050
+ empty: (value: unknown) => boolean;
2051
+ equal: (a: unknown, b: unknown) => boolean;
2052
+ not: {
2053
+ nil: <T>(value: T | null | undefined) => value is T;
2054
+ undefined: <T>(value: T | undefined) => value is T;
2055
+ null: <T>(value: T | null) => value is T;
2056
+ object: <T>(value: T) => value is Exclude<T, Record<string, unknown>>;
2057
+ objectOrArray: <T>(value: T) => value is Exclude<T, Record<string, unknown> | unknown[]>;
2058
+ array: <T>(value: T) => value is Exclude<T, unknown[]>;
2059
+ string: <T>(value: T) => value is Exclude<T, string>;
2060
+ number: <T>(value: T) => value is Exclude<T, number>;
2061
+ boolean: <T>(value: T) => value is Exclude<T, boolean>;
2062
+ function: <T>(value: T) => value is Exclude<T, (...args: unknown[]) => unknown>;
2063
+ symbol: <T>(value: T) => value is Exclude<T, symbol>;
2064
+ date: <T>(value: T) => value is Exclude<T, Date>;
2065
+ regexp: <T>(value: T) => value is Exclude<T, RegExp>;
2066
+ primitive: <T>(value: T) => value is Exclude<T, Primitive>;
2067
+ empty: (value: unknown) => boolean;
2068
+ equal: (a: unknown, b: unknown) => boolean;
2069
+ };
2070
+ };
2071
+
2072
+ /**
2073
+ * Apply Changes Utility
2074
+ *
2075
+ * Applies an array of changes to an object, returning a new object.
2076
+ */
2077
+
2078
+ /**
2079
+ * Applies changes to an object, returning a new object with changes applied.
2080
+ * Does not mutate the original object.
2081
+ *
2082
+ * @param obj - Source object
2083
+ * @param changes - Array of [path, value, meta] tuples
2084
+ * @returns New object with changes applied
2085
+ *
2086
+ * @example
2087
+ * ```typescript
2088
+ * const state = { user: { name: 'Alice', age: 30 } }
2089
+ * const changes: ArrayOfChanges<typeof state> = [
2090
+ * ['user.name', 'Bob', {}],
2091
+ * ['user.age', 31, {}],
2092
+ * ]
2093
+ *
2094
+ * const newState = applyChangesToObject(state, changes)
2095
+ * // newState: { user: { name: 'Bob', age: 31 } }
2096
+ * // state is unchanged
2097
+ * ```
2098
+ */
2099
+ declare const applyChangesToObject: <T extends object>(obj: T, changes: ArrayOfChanges<T>) => T;
2100
+
2101
+ /**
2102
+ * Deep clone utility — single swap point for the cloning implementation.
2103
+ *
2104
+ * Uses @jsbits/deep-clone in "exact" mode which preserves:
2105
+ * - Getter/setter property descriptors
2106
+ * - Property attributes (enumerable, configurable, writable)
2107
+ * - Prototypes
2108
+ *
2109
+ * Swap the implementation here to change cloning behavior everywhere.
2110
+ */
2111
+ /**
2112
+ * Deep clone an object, preserving getters, setters, and property descriptors.
2113
+ * Returns a fully independent copy — mutations to the clone never affect the original.
2114
+ *
2115
+ * Throws if the input contains circular references.
2116
+ */
2117
+ declare const deepClone: <T>(value: T) => T;
2118
+
2119
+ export { type ValidationSchema as $, type Aggregation as A, type BoolLogic as B, type CheckAggregationPairs as C, type DefaultDepth as D, type EvaluatedConcerns as E, type ExtractEvaluateReturn as F, type GenericMeta as G, type FieldInput$2 as H, type FlipPair as I, type GenericStoreApi as J, type HASH_KEY as K, type KeyboardSelectConfig as L, type ListenerRegistration as M, type ProviderProps as N, type OnStateListener as O, type PathsWithSameValueAs as P, type SideEffects as Q, type ResolvableDeepKey as R, type SelectOption as S, type StoreConfig as T, type StoreInstance as U, type ValidatedAggregationPairs as V, type SyncPair as W, type ThrottleConfig as X, type ThrottleFieldInput as Y, type TransformConfig as Z, type ValidationError as _, type ComputationOp as a, type ValidationStateConcern as a0, type ValidationStateInput as a1, type ValidationStateResult as a2, _ as a3, applyChangesToObject as a4, createGenericStore as a5, deepClone as a6, defaultConcerns as a7, dot as a8, evaluateBoolLogic as a9, extractPlaceholders as aa, findConcern as ab, hashKey as ac, interpolateTemplate as ad, is as ae, index as af, registerFlipPair as ag, registerListenerLegacy as ah, registerSideEffects as ai, registerSyncPairsBatch as aj, useBufferedField as ak, useKeyboardSelect as al, useThrottledField as am, useTransformedField as an, type DeepKeyFiltered as b, type CheckComputationPairs as c, type ValidatedComputationPairs as d, type CheckSyncPairs as e, type ValidatedFlipPairs as f, type CheckListeners as g, type ValidatedListeners as h, type ValidatedSyncPairs as i, type AggregationPair as j, type ArrayOfChanges as k, type BaseConcernProps as l, type BufferedField as m, type CheckPairValueMatch as n, type ClearPathRule as o, type ComputationPair as p, type ConcernRegistration as q, type ConcernRegistrationMap as r, type ConcernType as s, type DebugConfig as t, type DebugTrack as u, type DebugTrackEntry as v, type DeepKey as w, type DeepPartial as x, type DeepRequired as y, type DeepValue as z };