@signaltree/core 5.1.1 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -55
- package/dist/constants.js +6 -0
- package/dist/deep-clone.js +80 -0
- package/dist/deep-equal.js +41 -0
- package/dist/enhancers/batching/lib/batching.js +161 -0
- package/dist/enhancers/computed/lib/computed.js +21 -0
- package/dist/enhancers/devtools/lib/devtools.js +321 -0
- package/dist/enhancers/entities/lib/entities.js +93 -0
- package/dist/enhancers/index.js +72 -0
- package/dist/enhancers/memoization/lib/memoization.js +410 -0
- package/dist/enhancers/presets/lib/presets.js +87 -0
- package/dist/enhancers/serialization/constants.js +15 -0
- package/dist/enhancers/serialization/lib/serialization.js +662 -0
- package/dist/enhancers/time-travel/lib/time-travel.js +193 -0
- package/dist/index.js +19 -0
- package/dist/is-built-in-object.js +23 -0
- package/dist/lib/async-helpers.js +77 -0
- package/dist/lib/constants.js +56 -0
- package/dist/lib/entity-signal.js +280 -0
- package/dist/lib/memory/memory-manager.js +164 -0
- package/dist/lib/path-notifier.js +106 -0
- package/dist/lib/performance/diff-engine.js +156 -0
- package/dist/lib/performance/path-index.js +156 -0
- package/dist/lib/performance/update-engine.js +188 -0
- package/dist/lib/security/security-validator.js +121 -0
- package/dist/lib/signal-tree.js +626 -0
- package/dist/lib/types.js +9 -0
- package/dist/lib/utils.js +261 -0
- package/dist/lru-cache.js +64 -0
- package/dist/parse-path.js +13 -0
- package/package.json +1 -1
- package/src/async-helpers.d.ts +8 -0
- package/src/batching.d.ts +16 -0
- package/src/computed.d.ts +12 -0
- package/src/constants.d.ts +14 -0
- package/src/devtools.d.ts +77 -0
- package/src/diff-engine.d.ts +33 -0
- package/src/enhancers/batching/index.d.ts +1 -0
- package/src/enhancers/batching/lib/batching.d.ts +16 -0
- package/src/enhancers/batching/test-setup.d.ts +3 -0
- package/src/enhancers/computed/index.d.ts +1 -0
- package/src/enhancers/computed/lib/computed.d.ts +12 -0
- package/src/enhancers/devtools/index.d.ts +1 -0
- package/src/enhancers/devtools/lib/devtools.d.ts +77 -0
- package/src/enhancers/devtools/test-setup.d.ts +3 -0
- package/src/enhancers/entities/index.d.ts +1 -0
- package/src/enhancers/entities/lib/entities.d.ts +20 -0
- package/src/enhancers/entities/test-setup.d.ts +3 -0
- package/src/enhancers/index.d.ts +3 -0
- package/src/enhancers/memoization/index.d.ts +1 -0
- package/src/enhancers/memoization/lib/memoization.d.ts +65 -0
- package/src/enhancers/memoization/test-setup.d.ts +3 -0
- package/src/enhancers/presets/index.d.ts +1 -0
- package/src/enhancers/presets/lib/presets.d.ts +11 -0
- package/src/enhancers/presets/test-setup.d.ts +3 -0
- package/src/enhancers/serialization/constants.d.ts +14 -0
- package/src/enhancers/serialization/index.d.ts +2 -0
- package/src/enhancers/serialization/lib/serialization.d.ts +59 -0
- package/src/enhancers/serialization/test-setup.d.ts +3 -0
- package/src/enhancers/time-travel/index.d.ts +1 -0
- package/src/enhancers/time-travel/lib/time-travel.d.ts +36 -0
- package/src/enhancers/time-travel/lib/utils.d.ts +1 -0
- package/src/enhancers/time-travel/test-setup.d.ts +3 -0
- package/src/enhancers/types.d.ts +74 -0
- package/src/entities.d.ts +20 -0
- package/src/entity-signal.d.ts +1 -0
- package/src/index.d.ts +18 -0
- package/src/lib/async-helpers.d.ts +8 -0
- package/src/lib/constants.d.ts +41 -0
- package/src/lib/entity-signal.d.ts +1 -0
- package/src/lib/memory/memory-manager.d.ts +30 -0
- package/src/lib/path-notifier.d.ts +4 -0
- package/src/lib/performance/diff-engine.d.ts +33 -0
- package/src/lib/performance/path-index.d.ts +25 -0
- package/src/lib/performance/update-engine.d.ts +32 -0
- package/src/lib/security/security-validator.d.ts +33 -0
- package/src/lib/signal-tree.d.ts +8 -0
- package/src/lib/types.d.ts +278 -0
- package/src/lib/utils.d.ts +28 -0
- package/src/memoization.d.ts +65 -0
- package/src/memory-manager.d.ts +30 -0
- package/src/path-index.d.ts +25 -0
- package/src/path-notifier.d.ts +12 -0
- package/src/presets.d.ts +11 -0
- package/src/security-validator.d.ts +33 -0
- package/src/serialization.d.ts +59 -0
- package/src/signal-tree.d.ts +8 -0
- package/src/test-setup.d.ts +3 -0
- package/src/time-travel.d.ts +36 -0
- package/src/types.d.ts +278 -0
- package/src/update-engine.d.ts +32 -0
- package/src/utils.d.ts +1 -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
|
+
readonly all: Signal<E[]>;
|
|
184
|
+
readonly count: Signal<number>;
|
|
185
|
+
readonly ids: Signal<K[]>;
|
|
186
|
+
has(id: K): Signal<boolean>;
|
|
187
|
+
readonly isEmpty: Signal<boolean>;
|
|
188
|
+
readonly 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;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { SignalTree } from '../../../lib/types';
|
|
2
|
+
export interface MemoizedSignalTree<T> extends SignalTree<T> {
|
|
3
|
+
memoizedUpdate: (updater: (current: T) => Partial<T>, cacheKey?: string) => void;
|
|
4
|
+
clearMemoCache: (key?: string) => void;
|
|
5
|
+
getCacheStats: () => {
|
|
6
|
+
size: number;
|
|
7
|
+
hitRate: number;
|
|
8
|
+
totalHits: number;
|
|
9
|
+
totalMisses: number;
|
|
10
|
+
keys: string[];
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function cleanupMemoizationCache(): void;
|
|
14
|
+
export interface MemoizationConfig {
|
|
15
|
+
enabled?: boolean;
|
|
16
|
+
maxCacheSize?: number;
|
|
17
|
+
ttl?: number;
|
|
18
|
+
equality?: 'deep' | 'shallow' | 'reference';
|
|
19
|
+
enableLRU?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function memoize<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn, keyFn?: (...args: TArgs) => string, config?: MemoizationConfig): (...args: TArgs) => TReturn;
|
|
22
|
+
export declare function memoizeShallow<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn, keyFn?: (...args: TArgs) => string): (...args: TArgs) => TReturn;
|
|
23
|
+
export declare function memoizeReference<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn, keyFn?: (...args: TArgs) => string): (...args: TArgs) => TReturn;
|
|
24
|
+
export declare const MEMOIZATION_PRESETS: {
|
|
25
|
+
readonly selector: {
|
|
26
|
+
readonly equality: "reference";
|
|
27
|
+
readonly maxCacheSize: 10;
|
|
28
|
+
readonly enableLRU: false;
|
|
29
|
+
readonly ttl: undefined;
|
|
30
|
+
};
|
|
31
|
+
readonly computed: {
|
|
32
|
+
readonly equality: "shallow";
|
|
33
|
+
readonly maxCacheSize: 100;
|
|
34
|
+
readonly enableLRU: false;
|
|
35
|
+
readonly ttl: undefined;
|
|
36
|
+
};
|
|
37
|
+
readonly deepState: {
|
|
38
|
+
readonly equality: "deep";
|
|
39
|
+
readonly maxCacheSize: 1000;
|
|
40
|
+
readonly enableLRU: true;
|
|
41
|
+
readonly ttl: number;
|
|
42
|
+
};
|
|
43
|
+
readonly highFrequency: {
|
|
44
|
+
readonly equality: "reference";
|
|
45
|
+
readonly maxCacheSize: 5;
|
|
46
|
+
readonly enableLRU: false;
|
|
47
|
+
readonly ttl: undefined;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export declare function withSelectorMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
51
|
+
export declare function withComputedMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
52
|
+
export declare function withDeepStateMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
53
|
+
export declare function withHighFrequencyMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
54
|
+
export declare function withMemoization<T>(config?: MemoizationConfig): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
55
|
+
export declare function enableMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
56
|
+
export declare function withHighPerformanceMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
57
|
+
export declare function withLightweightMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
58
|
+
export declare function withShallowMemoization<T>(): (tree: SignalTree<T>) => MemoizedSignalTree<T>;
|
|
59
|
+
export declare function clearAllCaches(): void;
|
|
60
|
+
export declare function getGlobalCacheStats(): {
|
|
61
|
+
treeCount: number;
|
|
62
|
+
totalSize: number;
|
|
63
|
+
totalHits: number;
|
|
64
|
+
averageCacheSize: number;
|
|
65
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { WritableSignal } from '@angular/core';
|
|
2
|
+
export interface MemoryStats {
|
|
3
|
+
cachedSignals: number;
|
|
4
|
+
cleanedUpSignals: number;
|
|
5
|
+
peakCachedSignals: number;
|
|
6
|
+
manualDisposes: number;
|
|
7
|
+
estimatedMemoryBytes: number;
|
|
8
|
+
}
|
|
9
|
+
export interface MemoryManagerConfig {
|
|
10
|
+
enableAutoCleanup?: boolean;
|
|
11
|
+
debugMode?: boolean;
|
|
12
|
+
onCleanup?: (path: string, stats: MemoryStats) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare class SignalMemoryManager {
|
|
15
|
+
private cache;
|
|
16
|
+
private registry;
|
|
17
|
+
private config;
|
|
18
|
+
private stats;
|
|
19
|
+
constructor(config?: MemoryManagerConfig);
|
|
20
|
+
cacheSignal<T>(path: string, signal: WritableSignal<T>): void;
|
|
21
|
+
getSignal(path: string): WritableSignal<unknown> | undefined;
|
|
22
|
+
hasSignal(path: string): boolean;
|
|
23
|
+
removeSignal(path: string): boolean;
|
|
24
|
+
private handleCleanup;
|
|
25
|
+
getStats(): MemoryStats;
|
|
26
|
+
dispose(): void;
|
|
27
|
+
getCachedPaths(): string[];
|
|
28
|
+
clearStale(): number;
|
|
29
|
+
resetStats(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { WritableSignal } from '@angular/core';
|
|
2
|
+
export type PathSegment = string | number;
|
|
3
|
+
export type Path = PathSegment[];
|
|
4
|
+
export declare class PathIndex<T extends object = WritableSignal<any>> {
|
|
5
|
+
private root;
|
|
6
|
+
private pathCache;
|
|
7
|
+
private stats;
|
|
8
|
+
set(path: Path, signal: T): void;
|
|
9
|
+
get(path: Path): T | null;
|
|
10
|
+
has(path: Path): boolean;
|
|
11
|
+
getByPrefix(prefix: Path): Map<string, T>;
|
|
12
|
+
delete(path: Path): boolean;
|
|
13
|
+
clear(): void;
|
|
14
|
+
getStats(): {
|
|
15
|
+
hits: number;
|
|
16
|
+
misses: number;
|
|
17
|
+
sets: number;
|
|
18
|
+
cleanups: number;
|
|
19
|
+
hitRate: number;
|
|
20
|
+
cacheSize: number;
|
|
21
|
+
};
|
|
22
|
+
buildFromTree(tree: unknown, path?: Path): void;
|
|
23
|
+
private pathToString;
|
|
24
|
+
private collectDescendants;
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type PathNotifierInterceptor = (value: unknown, prev: unknown, path: string) => {
|
|
2
|
+
block?: boolean;
|
|
3
|
+
transform?: unknown;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export interface PathNotifier {
|
|
7
|
+
subscribe(pattern: string, handler: (value: unknown, prev: unknown, path: string) => void): () => void;
|
|
8
|
+
intercept(pattern: string, fn: PathNotifierInterceptor): () => void;
|
|
9
|
+
notify(path: string, value: unknown, prev: unknown): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getPathNotifier(): PathNotifier;
|
package/src/presets.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TreeConfig } from '../../../lib/types';
|
|
2
|
+
export type TreePreset = 'basic' | 'performance' | 'development' | 'production';
|
|
3
|
+
export declare const TREE_PRESETS: Record<TreePreset, Partial<TreeConfig>>;
|
|
4
|
+
export declare function createPresetConfig(preset: TreePreset, overrides?: Partial<TreeConfig>): TreeConfig;
|
|
5
|
+
export declare function validatePreset(preset: TreePreset): boolean;
|
|
6
|
+
export declare function getAvailablePresets(): TreePreset[];
|
|
7
|
+
export declare function combinePresets(presets: TreePreset[], overrides?: Partial<TreeConfig>): TreeConfig;
|
|
8
|
+
export declare function createDevTree(overrides?: Partial<TreeConfig>): {
|
|
9
|
+
readonly config: TreeConfig;
|
|
10
|
+
readonly enhancer: (tree: import("../../memoization/lib/memoization").MemoizedSignalTree<unknown>) => import("../../memoization/lib/memoization").MemoizedSignalTree<unknown>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type SecurityEventType = 'dangerous-key-blocked' | 'xss-attempt-blocked' | 'function-value-blocked' | 'validation-error';
|
|
2
|
+
export interface SecurityEvent {
|
|
3
|
+
type: SecurityEventType;
|
|
4
|
+
key?: string;
|
|
5
|
+
value?: unknown;
|
|
6
|
+
reason: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
}
|
|
9
|
+
export interface SecurityValidatorConfig {
|
|
10
|
+
preventPrototypePollution?: boolean;
|
|
11
|
+
preventXSS?: boolean;
|
|
12
|
+
preventFunctions?: boolean;
|
|
13
|
+
customDangerousKeys?: string[];
|
|
14
|
+
onSecurityEvent?: (event: SecurityEvent) => void;
|
|
15
|
+
sanitizationMode?: 'strict' | 'permissive';
|
|
16
|
+
}
|
|
17
|
+
export declare class SecurityValidator {
|
|
18
|
+
private readonly config;
|
|
19
|
+
private readonly dangerousKeys;
|
|
20
|
+
constructor(config?: SecurityValidatorConfig);
|
|
21
|
+
validateKey(key: string): void;
|
|
22
|
+
validateValue<T>(value: T): T;
|
|
23
|
+
private sanitize;
|
|
24
|
+
validateKeyValue<T>(key: string, value: T): T;
|
|
25
|
+
isDangerousKey(key: string): boolean;
|
|
26
|
+
getConfig(): Readonly<Required<SecurityValidatorConfig>>;
|
|
27
|
+
}
|
|
28
|
+
export declare const SecurityPresets: {
|
|
29
|
+
strict: () => SecurityValidator;
|
|
30
|
+
standard: () => SecurityValidator;
|
|
31
|
+
permissive: () => SecurityValidator;
|
|
32
|
+
disabled: () => SecurityValidator;
|
|
33
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { SignalTree } from '../../../lib/types';
|
|
2
|
+
import type { EnhancerWithMeta } from '../../../lib/types';
|
|
3
|
+
export interface SerializationConfig {
|
|
4
|
+
includeMetadata?: boolean;
|
|
5
|
+
replacer?: (key: string, value: unknown) => unknown;
|
|
6
|
+
reviver?: (key: string, value: unknown) => unknown;
|
|
7
|
+
preserveTypes?: boolean;
|
|
8
|
+
maxDepth?: number;
|
|
9
|
+
handleCircular?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface SerializedState<T = unknown> {
|
|
12
|
+
data: T;
|
|
13
|
+
metadata?: {
|
|
14
|
+
timestamp: number;
|
|
15
|
+
version: string;
|
|
16
|
+
appVersion?: string;
|
|
17
|
+
types?: Record<string, string>;
|
|
18
|
+
circularRefs?: Array<{
|
|
19
|
+
path: string;
|
|
20
|
+
targetPath: string;
|
|
21
|
+
}>;
|
|
22
|
+
nodeMap?: Record<string, 'b' | 'r'>;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface SerializableSignalTree<T> extends SignalTree<T> {
|
|
26
|
+
$: any;
|
|
27
|
+
serialize(config?: SerializationConfig): string;
|
|
28
|
+
deserialize(json: string, config?: SerializationConfig): void;
|
|
29
|
+
toJSON(): T;
|
|
30
|
+
fromJSON(data: T, metadata?: SerializedState<T>['metadata']): void;
|
|
31
|
+
snapshot(): SerializedState<T>;
|
|
32
|
+
restore(snapshot: SerializedState<T>): void;
|
|
33
|
+
}
|
|
34
|
+
export interface PersistenceMethods {
|
|
35
|
+
save(): Promise<void>;
|
|
36
|
+
load(): Promise<void>;
|
|
37
|
+
clear(): Promise<void>;
|
|
38
|
+
__flushAutoSave?: () => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
export declare function withSerialization<T extends Record<string, unknown> = Record<string, unknown>>(defaultConfig?: SerializationConfig): EnhancerWithMeta<SignalTree<T>, SerializableSignalTree<T>>;
|
|
41
|
+
export declare function enableSerialization<T extends Record<string, unknown> = Record<string, unknown>>(): EnhancerWithMeta<SignalTree<T>, SerializableSignalTree<T>>;
|
|
42
|
+
export interface StorageAdapter {
|
|
43
|
+
getItem(key: string): string | null | Promise<string | null>;
|
|
44
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
45
|
+
removeItem(key: string): void | Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export interface PersistenceConfig extends SerializationConfig {
|
|
48
|
+
key: string;
|
|
49
|
+
storage?: StorageAdapter;
|
|
50
|
+
autoSave?: boolean;
|
|
51
|
+
debounceMs?: number;
|
|
52
|
+
autoLoad?: boolean;
|
|
53
|
+
skipCache?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export declare function withPersistence<T extends Record<string, unknown> = Record<string, unknown>>(config: PersistenceConfig): EnhancerWithMeta<SignalTree<T>, SerializableSignalTree<T> & PersistenceMethods>;
|
|
56
|
+
export declare function createStorageAdapter(getItem: (key: string) => string | null | Promise<string | null>, setItem: (key: string, value: string) => void | Promise<void>, removeItem: (key: string) => void | Promise<void>): StorageAdapter;
|
|
57
|
+
export declare function createIndexedDBAdapter(dbName?: string, storeName?: string): StorageAdapter;
|
|
58
|
+
export declare function applySerialization<T extends Record<string, unknown>>(tree: SignalTree<T>): SerializableSignalTree<T>;
|
|
59
|
+
export declare function applyPersistence<T extends Record<string, unknown>>(tree: SignalTree<T>, cfg: PersistenceConfig): SerializableSignalTree<T> & PersistenceMethods;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SignalTree, TreeConfig, TreePreset, EnhancerWithMeta, NodeAccessor } from './types';
|
|
2
|
+
export declare function isNodeAccessor(value: unknown): value is NodeAccessor<unknown>;
|
|
3
|
+
export declare function signalTree<T>(obj: T): SignalTree<T>;
|
|
4
|
+
export declare function signalTree<T>(obj: T, preset: TreePreset): SignalTree<T>;
|
|
5
|
+
export declare function signalTree<T>(obj: T, config: TreeConfig): SignalTree<T>;
|
|
6
|
+
export declare function signalTree<T extends Record<string, unknown>>(obj: Required<T>, configOrPreset?: TreeConfig | TreePreset): SignalTree<Required<T>>;
|
|
7
|
+
export declare function signalTree<T>(obj: T, configOrPreset?: TreeConfig | TreePreset): SignalTree<T>;
|
|
8
|
+
export declare function applyEnhancer<T, O>(tree: SignalTree<T>, enhancer: EnhancerWithMeta<SignalTree<T>, O>): O;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { SignalTree } from '../../../lib/types';
|
|
2
|
+
export interface TimeTravelEntry<T> {
|
|
3
|
+
state: T;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
action: string;
|
|
6
|
+
payload?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface TimeTravelInterface<T> {
|
|
9
|
+
undo(): boolean;
|
|
10
|
+
redo(): boolean;
|
|
11
|
+
getHistory(): TimeTravelEntry<T>[];
|
|
12
|
+
resetHistory(): void;
|
|
13
|
+
jumpTo(index: number): boolean;
|
|
14
|
+
getCurrentIndex(): number;
|
|
15
|
+
canUndo(): boolean;
|
|
16
|
+
canRedo(): boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface TimeTravelConfig {
|
|
19
|
+
maxHistorySize?: number;
|
|
20
|
+
includePayload?: boolean;
|
|
21
|
+
actionNames?: {
|
|
22
|
+
update?: string;
|
|
23
|
+
set?: string;
|
|
24
|
+
batch?: string;
|
|
25
|
+
[key: string]: string | undefined;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare function withTimeTravel<T>(config?: TimeTravelConfig): (tree: SignalTree<T>) => SignalTree<T> & {
|
|
29
|
+
__timeTravel: TimeTravelInterface<T>;
|
|
30
|
+
};
|
|
31
|
+
export declare function enableTimeTravel<T>(maxHistorySize?: number): (tree: SignalTree<T>) => SignalTree<T> & {
|
|
32
|
+
__timeTravel: TimeTravelInterface<T>;
|
|
33
|
+
};
|
|
34
|
+
export declare function getTimeTravel<T>(tree: SignalTree<T> & {
|
|
35
|
+
__timeTravel?: TimeTravelInterface<T>;
|
|
36
|
+
}): TimeTravelInterface<T> | undefined;
|