@signaltree/core 5.1.1 → 5.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/constants.js +6 -0
  2. package/dist/deep-clone.js +80 -0
  3. package/dist/deep-equal.js +41 -0
  4. package/dist/enhancers/batching/lib/batching.js +161 -0
  5. package/dist/enhancers/computed/lib/computed.js +21 -0
  6. package/dist/enhancers/devtools/lib/devtools.js +321 -0
  7. package/dist/enhancers/entities/lib/entities.js +93 -0
  8. package/dist/enhancers/index.js +72 -0
  9. package/dist/enhancers/memoization/lib/memoization.js +410 -0
  10. package/dist/enhancers/presets/lib/presets.js +87 -0
  11. package/dist/enhancers/serialization/constants.js +15 -0
  12. package/dist/enhancers/serialization/lib/serialization.js +662 -0
  13. package/dist/enhancers/time-travel/lib/time-travel.js +193 -0
  14. package/dist/index.js +19 -0
  15. package/dist/is-built-in-object.js +23 -0
  16. package/dist/lib/async-helpers.js +77 -0
  17. package/dist/lib/constants.js +56 -0
  18. package/dist/lib/entity-signal.js +280 -0
  19. package/dist/lib/memory/memory-manager.js +164 -0
  20. package/dist/lib/path-notifier.js +106 -0
  21. package/dist/lib/performance/diff-engine.js +156 -0
  22. package/dist/lib/performance/path-index.js +156 -0
  23. package/dist/lib/performance/update-engine.js +188 -0
  24. package/dist/lib/security/security-validator.js +121 -0
  25. package/dist/lib/signal-tree.js +625 -0
  26. package/dist/lib/types.js +9 -0
  27. package/dist/lib/utils.js +258 -0
  28. package/dist/lru-cache.js +64 -0
  29. package/dist/parse-path.js +13 -0
  30. package/package.json +1 -1
  31. package/src/enhancers/batching/index.d.ts +1 -0
  32. package/src/enhancers/batching/lib/batching.d.ts +16 -0
  33. package/src/enhancers/batching/test-setup.d.ts +3 -0
  34. package/src/enhancers/computed/index.d.ts +1 -0
  35. package/src/enhancers/computed/lib/computed.d.ts +12 -0
  36. package/src/enhancers/devtools/index.d.ts +1 -0
  37. package/src/enhancers/devtools/lib/devtools.d.ts +77 -0
  38. package/src/enhancers/devtools/test-setup.d.ts +3 -0
  39. package/src/enhancers/entities/index.d.ts +1 -0
  40. package/src/enhancers/entities/lib/entities.d.ts +20 -0
  41. package/src/enhancers/entities/test-setup.d.ts +3 -0
  42. package/src/enhancers/index.d.ts +3 -0
  43. package/src/enhancers/memoization/index.d.ts +1 -0
  44. package/src/enhancers/memoization/lib/memoization.d.ts +65 -0
  45. package/src/enhancers/memoization/test-setup.d.ts +3 -0
  46. package/src/enhancers/presets/index.d.ts +1 -0
  47. package/src/enhancers/presets/lib/presets.d.ts +11 -0
  48. package/src/enhancers/presets/test-setup.d.ts +3 -0
  49. package/src/enhancers/serialization/constants.d.ts +14 -0
  50. package/src/enhancers/serialization/index.d.ts +2 -0
  51. package/src/enhancers/serialization/lib/serialization.d.ts +59 -0
  52. package/src/enhancers/serialization/test-setup.d.ts +3 -0
  53. package/src/enhancers/time-travel/index.d.ts +1 -0
  54. package/src/enhancers/time-travel/lib/time-travel.d.ts +36 -0
  55. package/src/enhancers/time-travel/lib/utils.d.ts +1 -0
  56. package/src/enhancers/time-travel/test-setup.d.ts +3 -0
  57. package/src/enhancers/types.d.ts +74 -0
  58. package/src/index.d.ts +18 -0
  59. package/src/lib/async-helpers.d.ts +8 -0
  60. package/src/lib/constants.d.ts +41 -0
  61. package/src/lib/entity-signal.d.ts +1 -0
  62. package/src/lib/memory/memory-manager.d.ts +30 -0
  63. package/src/lib/path-notifier.d.ts +4 -0
  64. package/src/lib/performance/diff-engine.d.ts +33 -0
  65. package/src/lib/performance/path-index.d.ts +25 -0
  66. package/src/lib/performance/update-engine.d.ts +32 -0
  67. package/src/lib/security/security-validator.d.ts +33 -0
  68. package/src/lib/signal-tree.d.ts +8 -0
  69. package/src/lib/types.d.ts +278 -0
  70. package/src/lib/utils.d.ts +28 -0
@@ -0,0 +1,278 @@
1
+ import { Signal, WritableSignal } from '@angular/core';
2
+ import type { SecurityValidatorConfig } from './security/security-validator';
3
+ export type NotFn<T> = T extends (...args: unknown[]) => unknown ? never : T;
4
+ declare module '@angular/core' {
5
+ interface WritableSignal<T> {
6
+ (value: NotFn<T>): void;
7
+ (updater: (current: T) => T): void;
8
+ }
9
+ }
10
+ export type Primitive = string | number | boolean | null | undefined | bigint | symbol;
11
+ export type BuiltInObject = Date | RegExp | ((...args: unknown[]) => unknown) | Map<unknown, unknown> | Set<unknown> | WeakMap<object, unknown> | WeakSet<object> | ArrayBuffer | DataView | Error | Promise<unknown> | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array | URL | URLSearchParams | FormData | Blob | File | Headers | Request | Response | AbortController | AbortSignal;
12
+ export type Unwrap<T> = [T] extends [WritableSignal<infer U>] ? U : [T] extends [Signal<infer U>] ? U : [T] extends [BuiltInObject] ? T : [T] extends [readonly unknown[]] ? T : [T] extends [EntityMapMarker<infer E, infer K>] ? EntitySignal<E, K> : [T] extends [object] ? {
13
+ [K in keyof T]: Unwrap<T[K]>;
14
+ } : T;
15
+ export interface NodeAccessor<T> {
16
+ (): T;
17
+ (value: T): void;
18
+ (updater: (current: T) => T): void;
19
+ }
20
+ export type AccessibleNode<T> = NodeAccessor<T> & TreeNode<T>;
21
+ export type CallableWritableSignal<T> = WritableSignal<T> & {
22
+ (value: NotFn<T>): void;
23
+ (updater: (current: T) => T): void;
24
+ };
25
+ export type TreeNode<T> = {
26
+ [K in keyof T]: [T[K]] extends [EntityMapMarker<infer E, infer Key>] ? EntitySignal<E, Key> : [T[K]] extends [readonly unknown[]] ? CallableWritableSignal<T[K]> : [T[K]] extends [object] ? [T[K]] extends [Signal<unknown>] ? T[K] : [T[K]] extends [BuiltInObject] ? CallableWritableSignal<T[K]> : [T[K]] extends [(...args: unknown[]) => unknown] ? CallableWritableSignal<T[K]> : AccessibleNode<T[K]> : CallableWritableSignal<T[K]>;
27
+ };
28
+ export type RemoveSignalMethods<T> = T extends infer U ? U : never;
29
+ export type DeepPath<T, Prefix extends string = '', Depth extends readonly number[] = []> = Depth['length'] extends 5 ? never : {
30
+ [K in keyof T]: K extends string ? T[K] extends readonly unknown[] ? `${Prefix}${K}` : T[K] extends object ? T[K] extends Signal<unknown> ? never : T[K] extends BuiltInObject ? never : T[K] extends (...args: unknown[]) => unknown ? never : `${Prefix}${K}` | DeepPath<T[K], `${Prefix}${K}.`, [...Depth, 1]> : never : never;
31
+ }[keyof T];
32
+ export type DeepAccess<T, Path extends string> = Path extends `${infer First}.${infer Rest}` ? First extends keyof T ? DeepAccess<T[First] & object, Rest> : never : Path extends keyof T ? T[Path] : never;
33
+ export interface EnhancerMeta {
34
+ name?: string;
35
+ requires?: string[];
36
+ provides?: string[];
37
+ }
38
+ export type Enhancer<Input = unknown, Output = unknown> = (input: Input) => Output;
39
+ export type EnhancerWithMeta<Input = unknown, Output = unknown> = Enhancer<Input, Output> & {
40
+ metadata?: EnhancerMeta;
41
+ };
42
+ export declare const ENHANCER_META: unique symbol;
43
+ export type ChainResult<Start, E extends Array<EnhancerWithMeta<unknown, unknown>>> = E extends [infer H, ...infer R] ? H extends EnhancerWithMeta<SignalTree<unknown>, infer O> ? R extends Array<EnhancerWithMeta<unknown, unknown>> ? ChainResult<O, R> : O : H extends EnhancerWithMeta<infer I, infer O> ? Start extends I ? R extends Array<EnhancerWithMeta<unknown, unknown>> ? ChainResult<O, R> : O : unknown : unknown : Start;
44
+ export interface WithMethod<T> {
45
+ (): SignalTree<T>;
46
+ <O>(enhancer: (input: SignalTree<T>) => O): O;
47
+ <O1, O2>(e1: (input: SignalTree<T>) => O1, e2: (input: O1) => O2): O2;
48
+ <O1, O2, O3>(e1: (input: SignalTree<T>) => O1, e2: (input: O1) => O2, e3: (input: O2) => O3): O3;
49
+ <O>(enhancer: EnhancerWithMeta<SignalTree<T>, O>): O;
50
+ <O1, O2>(e1: EnhancerWithMeta<SignalTree<T>, O1>, e2: EnhancerWithMeta<O1, O2>): O2;
51
+ <O1, O2, O3>(e1: EnhancerWithMeta<SignalTree<T>, O1>, e2: EnhancerWithMeta<O1, O2>, e3: EnhancerWithMeta<O2, O3>): O3;
52
+ }
53
+ export type SignalTree<T> = NodeAccessor<T> & {
54
+ state: TreeNode<T>;
55
+ $: TreeNode<T>;
56
+ with: WithMethod<T>;
57
+ destroy(): void;
58
+ dispose?(): void;
59
+ effect(fn: (tree: T) => void): void;
60
+ subscribe(fn: (tree: T) => void): () => void;
61
+ batch(updater: (tree: T) => void): void;
62
+ batchUpdate(updater: (current: T) => Partial<T>): void;
63
+ memoize<R>(fn: (tree: T) => R, cacheKey?: string): Signal<R>;
64
+ memoizedUpdate(updater: (current: T) => Partial<T>, cacheKey?: string): void;
65
+ clearMemoCache(key?: string): void;
66
+ getCacheStats(): {
67
+ size: number;
68
+ hitRate: number;
69
+ totalHits: number;
70
+ totalMisses: number;
71
+ keys: string[];
72
+ };
73
+ optimize(): void;
74
+ clearCache(): void;
75
+ invalidatePattern(pattern: string): number;
76
+ updateOptimized?(updates: Partial<T>, options?: {
77
+ batch?: boolean;
78
+ batchSize?: number;
79
+ maxDepth?: number;
80
+ ignoreArrayOrder?: boolean;
81
+ equalityFn?: (a: unknown, b: unknown) => boolean;
82
+ }): {
83
+ changed: boolean;
84
+ duration: number;
85
+ changedPaths: string[];
86
+ stats?: {
87
+ totalPaths: number;
88
+ optimizedPaths: number;
89
+ batchedUpdates: number;
90
+ };
91
+ };
92
+ getMetrics(): PerformanceMetrics;
93
+ entities<E extends {
94
+ id: string | number;
95
+ }>(entityKey?: keyof T): EntityHelpers<E>;
96
+ undo(): void;
97
+ redo(): void;
98
+ getHistory(): TimeTravelEntry<T>[];
99
+ resetHistory(): void;
100
+ jumpTo?: (index: number) => void;
101
+ canUndo?: () => boolean;
102
+ canRedo?: () => boolean;
103
+ getCurrentIndex?: () => number;
104
+ };
105
+ export type TreePreset = 'basic' | 'performance' | 'development' | 'production';
106
+ export interface TreeConfig {
107
+ batchUpdates?: boolean;
108
+ useMemoization?: boolean;
109
+ enableTimeTravel?: boolean;
110
+ useLazySignals?: boolean;
111
+ useShallowComparison?: boolean;
112
+ maxCacheSize?: number;
113
+ trackPerformance?: boolean;
114
+ treeName?: string;
115
+ enableDevTools?: boolean;
116
+ debugMode?: boolean;
117
+ useStructuralSharing?: boolean;
118
+ security?: SecurityValidatorConfig;
119
+ }
120
+ export interface PerformanceMetrics {
121
+ updates: number;
122
+ computations: number;
123
+ cacheHits: number;
124
+ cacheMisses: number;
125
+ averageUpdateTime: number;
126
+ }
127
+ export interface EntityConfig<E, K extends string | number = string> {
128
+ selectId?: (entity: E) => K;
129
+ hooks?: {
130
+ beforeAdd?: (entity: E) => E | false;
131
+ beforeUpdate?: (id: K, changes: Partial<E>) => Partial<E> | false;
132
+ beforeRemove?: (id: K, entity: E) => boolean;
133
+ };
134
+ }
135
+ declare const ENTITY_MAP_BRAND: unique symbol;
136
+ export interface EntityMapMarker<E, K extends string | number> {
137
+ readonly [ENTITY_MAP_BRAND]: {
138
+ __entity: E;
139
+ __key: K;
140
+ };
141
+ readonly __isEntityMap: true;
142
+ readonly __entityMapConfig?: EntityConfig<E, K>;
143
+ }
144
+ export declare function entityMap<E, K extends string | number = E extends {
145
+ id: infer I extends string | number;
146
+ } ? I : string>(config?: EntityConfig<E, K>): EntityMapMarker<E, K>;
147
+ export interface MutationOptions {
148
+ onError?: (error: Error) => void;
149
+ }
150
+ export interface AddOptions<E, K> extends MutationOptions {
151
+ selectId?: (entity: E) => K;
152
+ }
153
+ export interface AddManyOptions<E, K> extends AddOptions<E, K> {
154
+ mode?: 'strict' | 'skip' | 'overwrite';
155
+ }
156
+ export interface TapHandlers<E, K extends string | number> {
157
+ onAdd?: (entity: E, id: K) => void;
158
+ onUpdate?: (id: K, changes: Partial<E>, entity: E) => void;
159
+ onRemove?: (id: K, entity: E) => void;
160
+ onChange?: () => void;
161
+ }
162
+ export interface InterceptContext<T> {
163
+ block(reason?: string): void;
164
+ transform(value: T): void;
165
+ readonly blocked: boolean;
166
+ readonly blockReason: string | undefined;
167
+ }
168
+ export interface InterceptHandlers<E, K extends string | number> {
169
+ onAdd?: (entity: E, ctx: InterceptContext<E>) => void | Promise<void>;
170
+ onUpdate?: (id: K, changes: Partial<E>, ctx: InterceptContext<Partial<E>>) => void | Promise<void>;
171
+ onRemove?: (id: K, entity: E, ctx: InterceptContext<void>) => void | Promise<void>;
172
+ }
173
+ export type EntityNode<E> = {
174
+ (): E;
175
+ (value: E): void;
176
+ (updater: (current: E) => E): void;
177
+ } & {
178
+ [P in keyof E]: E[P] extends object ? E[P] extends readonly unknown[] ? CallableWritableSignal<E[P]> : EntityNode<E[P]> : CallableWritableSignal<E[P]>;
179
+ };
180
+ export interface EntitySignal<E, K extends string | number = string> {
181
+ byId(id: K): EntityNode<E> | undefined;
182
+ byIdOrFail(id: K): EntityNode<E>;
183
+ all(): Signal<E[]>;
184
+ count(): Signal<number>;
185
+ ids(): Signal<K[]>;
186
+ has(id: K): Signal<boolean>;
187
+ isEmpty(): Signal<boolean>;
188
+ map(): Signal<ReadonlyMap<K, E>>;
189
+ where(predicate: (entity: E) => boolean): Signal<E[]>;
190
+ find(predicate: (entity: E) => boolean): Signal<E | undefined>;
191
+ addOne(entity: E, opts?: AddOptions<E, K>): K;
192
+ addMany(entities: E[], opts?: AddManyOptions<E, K>): K[];
193
+ updateOne(id: K, changes: Partial<E>, opts?: MutationOptions): void;
194
+ updateMany(ids: K[], changes: Partial<E>, opts?: MutationOptions): void;
195
+ updateWhere(predicate: (entity: E) => boolean, changes: Partial<E>): number;
196
+ upsertOne(entity: E, opts?: AddOptions<E, K>): K;
197
+ upsertMany(entities: E[], opts?: AddOptions<E, K>): K[];
198
+ removeOne(id: K, opts?: MutationOptions): void;
199
+ removeMany(ids: K[], opts?: MutationOptions): void;
200
+ removeWhere(predicate: (entity: E) => boolean): number;
201
+ clear(): void;
202
+ removeAll(): void;
203
+ setAll(entities: E[], opts?: AddOptions<E, K>): void;
204
+ tap(handlers: TapHandlers<E, K>): () => void;
205
+ intercept(handlers: InterceptHandlers<E, K>): () => void;
206
+ }
207
+ export interface EntityHelpers<E extends {
208
+ id: string | number;
209
+ }> {
210
+ add(entity: E): void;
211
+ update(id: E['id'], updates: Partial<E>): void;
212
+ remove(id: E['id']): void;
213
+ upsert(entity: E): void;
214
+ selectById(id: E['id']): Signal<E | undefined>;
215
+ selectBy(predicate: (entity: E) => boolean): Signal<E[]>;
216
+ selectIds(): Signal<Array<string | number>>;
217
+ selectAll(): Signal<E[]>;
218
+ selectTotal(): Signal<number>;
219
+ clear(): void;
220
+ }
221
+ export interface LoggingConfig {
222
+ name?: string;
223
+ filter?: (path: string) => boolean;
224
+ collapsed?: boolean;
225
+ onLog?: (entry: LogEntry) => void;
226
+ }
227
+ export interface LogEntry {
228
+ path: string;
229
+ prev: unknown;
230
+ value: unknown;
231
+ timestamp: number;
232
+ }
233
+ export interface ValidationConfig<T> {
234
+ validators: Array<{
235
+ match: (path: string) => boolean;
236
+ validate: (value: T, path: string) => void | never;
237
+ }>;
238
+ onError?: (error: Error, path: string) => void;
239
+ }
240
+ export interface PersistenceConfig {
241
+ key: string;
242
+ storage?: Storage;
243
+ debounceMs?: number;
244
+ filter?: (path: string) => boolean;
245
+ serialize?: (state: unknown) => string;
246
+ deserialize?: (json: string) => unknown;
247
+ }
248
+ export interface DevToolsConfig {
249
+ name?: string;
250
+ maxAge?: number;
251
+ features?: {
252
+ jump?: boolean;
253
+ skip?: boolean;
254
+ reorder?: boolean;
255
+ };
256
+ }
257
+ export type EntityType<T> = T extends EntitySignal<infer E, infer K extends string | number> ? E : never;
258
+ export type EntityKeyType<T> = T extends EntitySignal<unknown, infer K extends string | number> ? K : never;
259
+ export type IsEntityMap<T> = T extends EntityMapMarker<unknown, infer K extends string | number> ? true : false;
260
+ export type EntityAwareTreeNode<T> = {
261
+ [K in keyof T]: T[K] extends EntityMapMarker<infer E, infer Key> ? EntitySignal<E, Key> : T[K] extends object ? EntityAwareTreeNode<T[K]> : CallableWritableSignal<T[K]>;
262
+ };
263
+ export type PathHandler = (value: unknown, prev: unknown, path: string) => void;
264
+ export type PathInterceptor = (ctx: {
265
+ path: string;
266
+ value: unknown;
267
+ prev: unknown;
268
+ blocked: boolean;
269
+ blockReason?: string;
270
+ }, next: () => void) => void | Promise<void>;
271
+ export interface TimeTravelEntry<T> {
272
+ action: string;
273
+ timestamp: number;
274
+ state: T;
275
+ payload?: unknown;
276
+ }
277
+ export declare function isSignalTree<T>(value: unknown): value is SignalTree<T>;
278
+ export {};
@@ -0,0 +1,28 @@
1
+ import { Signal, WritableSignal } from '@angular/core';
2
+ import { deepEqual, isBuiltInObject, parsePath } from '@signaltree/shared';
3
+ export { deepEqual };
4
+ export { deepEqual as equal };
5
+ export { isBuiltInObject };
6
+ export { parsePath };
7
+ export interface MemoryManager {
8
+ getSignal(path: string): WritableSignal<unknown> | undefined;
9
+ cacheSignal(path: string, signal: WritableSignal<unknown>): void;
10
+ dispose(): void;
11
+ }
12
+ export interface NodeAccessor<T> {
13
+ (): T;
14
+ (value: T): void;
15
+ (updater: (current: T) => T): void;
16
+ }
17
+ export type TreeNode<T> = {
18
+ [K in keyof T]: T[K] extends readonly unknown[] ? WritableSignal<T[K]> : T[K] extends object ? T[K] extends Signal<unknown> ? T[K] : T[K] extends (...args: unknown[]) => unknown ? WritableSignal<T[K]> : NodeAccessor<T[K]> : WritableSignal<T[K]>;
19
+ };
20
+ export declare function isNodeAccessor(value: unknown): value is NodeAccessor<unknown>;
21
+ export declare function isAnySignal(value: unknown): boolean;
22
+ export declare function toWritableSignal<T>(node: NodeAccessor<T>, injector?: unknown): WritableSignal<T>;
23
+ export declare function composeEnhancers<T>(...enhancers: Array<(tree: T) => T>): (tree: T) => T;
24
+ export declare function createLazySignalTree<T extends object>(obj: T, equalityFn: (a: unknown, b: unknown) => boolean, basePath?: string, memoryManager?: MemoryManager): TreeNode<T>;
25
+ export declare function unwrap<T>(node: TreeNode<T>): T;
26
+ export declare function unwrap<T>(node: NodeAccessor<T> & TreeNode<T>): T;
27
+ export declare function unwrap<T>(node: NodeAccessor<T>): T;
28
+ export declare function unwrap<T>(node: unknown): T;