@signaltree/core 3.0.2 → 3.1.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.
Files changed (104) hide show
  1. package/package.json +59 -12
  2. package/src/enhancers/batching/index.d.ts +1 -0
  3. package/src/enhancers/batching/index.js +1 -0
  4. package/src/enhancers/batching/jest.config.d.ts +15 -0
  5. package/src/enhancers/batching/jest.config.js +21 -0
  6. package/src/enhancers/batching/lib/batching.d.ts +16 -0
  7. package/src/enhancers/batching/lib/batching.js +155 -0
  8. package/src/enhancers/batching/test-setup.d.ts +1 -0
  9. package/src/enhancers/batching/test-setup.js +5 -0
  10. package/src/enhancers/computed/index.d.ts +1 -0
  11. package/src/enhancers/computed/index.js +1 -0
  12. package/src/enhancers/computed/jest.config.d.ts +15 -0
  13. package/src/enhancers/computed/jest.config.js +21 -0
  14. package/src/enhancers/computed/lib/computed.d.ts +12 -0
  15. package/src/enhancers/computed/lib/computed.js +18 -0
  16. package/src/enhancers/devtools/index.d.ts +1 -0
  17. package/src/enhancers/devtools/index.js +1 -0
  18. package/src/enhancers/devtools/jest.config.d.ts +15 -0
  19. package/src/enhancers/devtools/jest.config.js +21 -0
  20. package/src/enhancers/devtools/lib/devtools.d.ts +77 -0
  21. package/src/enhancers/devtools/lib/devtools.js +278 -0
  22. package/src/enhancers/devtools/test-setup.d.ts +1 -0
  23. package/src/enhancers/devtools/test-setup.js +5 -0
  24. package/src/enhancers/entities/index.d.ts +1 -0
  25. package/src/enhancers/entities/index.js +1 -0
  26. package/src/enhancers/entities/jest.config.d.ts +15 -0
  27. package/src/enhancers/entities/jest.config.js +21 -0
  28. package/src/enhancers/entities/lib/entities.d.ts +22 -0
  29. package/src/enhancers/entities/lib/entities.js +110 -0
  30. package/src/enhancers/entities/test-setup.d.ts +1 -0
  31. package/src/enhancers/entities/test-setup.js +5 -0
  32. package/src/enhancers/index.d.ts +3 -0
  33. package/src/enhancers/index.js +84 -0
  34. package/src/enhancers/memoization/index.d.ts +1 -0
  35. package/src/enhancers/memoization/index.js +1 -0
  36. package/src/enhancers/memoization/jest.config.d.ts +15 -0
  37. package/src/enhancers/memoization/jest.config.js +21 -0
  38. package/src/enhancers/memoization/lib/memoization.d.ts +65 -0
  39. package/src/enhancers/memoization/lib/memoization.js +391 -0
  40. package/src/enhancers/memoization/test-setup.d.ts +1 -0
  41. package/src/enhancers/memoization/test-setup.js +5 -0
  42. package/src/enhancers/middleware/index.d.ts +2 -0
  43. package/src/enhancers/middleware/index.js +2 -0
  44. package/src/enhancers/middleware/jest.config.d.ts +15 -0
  45. package/src/enhancers/middleware/jest.config.js +21 -0
  46. package/src/enhancers/middleware/lib/async-helpers.d.ts +8 -0
  47. package/src/enhancers/middleware/lib/async-helpers.js +85 -0
  48. package/src/enhancers/middleware/lib/middleware.d.ts +11 -0
  49. package/src/enhancers/middleware/lib/middleware.js +179 -0
  50. package/src/enhancers/middleware/test-setup.d.ts +1 -0
  51. package/src/enhancers/middleware/test-setup.js +5 -0
  52. package/src/enhancers/presets/index.d.ts +1 -0
  53. package/src/enhancers/presets/index.js +1 -0
  54. package/src/enhancers/presets/jest.config.d.ts +15 -0
  55. package/src/enhancers/presets/jest.config.js +21 -0
  56. package/src/enhancers/presets/lib/presets.d.ts +11 -0
  57. package/src/enhancers/presets/lib/presets.js +102 -0
  58. package/src/enhancers/presets/test-setup.d.ts +1 -0
  59. package/src/enhancers/presets/test-setup.js +5 -0
  60. package/src/enhancers/serialization/constants.d.ts +14 -0
  61. package/src/enhancers/serialization/constants.js +14 -0
  62. package/src/enhancers/serialization/index.d.ts +2 -0
  63. package/src/enhancers/serialization/index.js +2 -0
  64. package/src/enhancers/serialization/jest.config.d.ts +15 -0
  65. package/src/enhancers/serialization/jest.config.js +21 -0
  66. package/src/enhancers/serialization/lib/serialization.d.ts +59 -0
  67. package/src/enhancers/serialization/lib/serialization.js +668 -0
  68. package/src/enhancers/serialization/test-setup.d.ts +1 -0
  69. package/src/enhancers/serialization/test-setup.js +5 -0
  70. package/src/enhancers/time-travel/index.d.ts +1 -0
  71. package/src/enhancers/time-travel/index.js +1 -0
  72. package/src/enhancers/time-travel/jest.config.d.ts +15 -0
  73. package/src/enhancers/time-travel/jest.config.js +21 -0
  74. package/src/enhancers/time-travel/lib/time-travel.d.ts +36 -0
  75. package/src/enhancers/time-travel/lib/time-travel.js +192 -0
  76. package/src/enhancers/time-travel/lib/utils.d.ts +1 -0
  77. package/src/enhancers/time-travel/lib/utils.js +1 -0
  78. package/src/enhancers/time-travel/test-setup.d.ts +1 -0
  79. package/src/enhancers/time-travel/test-setup.js +5 -0
  80. package/src/enhancers/types.d.ts +105 -0
  81. package/src/enhancers/types.js +0 -0
  82. package/src/index.d.ts +16 -0
  83. package/src/index.js +15 -0
  84. package/src/lib/constants.d.ts +42 -0
  85. package/src/lib/constants.js +61 -0
  86. package/src/lib/memory/memory-manager.d.ts +30 -0
  87. package/src/lib/memory/memory-manager.js +166 -0
  88. package/src/lib/performance/diff-engine.d.ts +33 -0
  89. package/src/lib/performance/diff-engine.js +156 -0
  90. package/src/lib/performance/path-index.d.ts +25 -0
  91. package/src/lib/performance/path-index.js +154 -0
  92. package/src/lib/performance/update-engine.d.ts +32 -0
  93. package/src/lib/performance/update-engine.js +193 -0
  94. package/src/lib/security/security-validator.d.ts +33 -0
  95. package/src/lib/security/security-validator.js +139 -0
  96. package/src/lib/signal-tree.d.ts +8 -0
  97. package/{fesm2022/signaltree-core.mjs → src/lib/signal-tree.js} +100 -573
  98. package/src/lib/types.d.ts +164 -0
  99. package/src/lib/types.js +9 -0
  100. package/src/lib/utils.d.ts +27 -0
  101. package/src/lib/utils.js +286 -0
  102. package/README.md +0 -1455
  103. package/fesm2022/signaltree-core.mjs.map +0 -1
  104. package/index.d.ts +0 -216
@@ -1,568 +1,10 @@
1
- import { isSignal, signal, computed, effect, inject, DestroyRef } from '@angular/core';
2
-
3
- const SIGNAL_TREE_CONSTANTS = {
4
- MAX_PATH_CACHE_SIZE: 1000,
5
- LAZY_THRESHOLD: 50,
6
- ESTIMATE_MAX_DEPTH: 3,
7
- ESTIMATE_SAMPLE_SIZE_ARRAY: 3,
8
- ESTIMATE_SAMPLE_SIZE_OBJECT: 5,
9
- DEFAULT_CACHE_SIZE: 100,
10
- DEFAULT_BATCH_SIZE: 10,
11
- };
12
- const DEV_MESSAGES = {
13
- NULL_OR_UNDEFINED: 'null/undefined',
14
- CIRCULAR_REF: 'circular ref',
15
- UPDATER_INVALID: 'updater invalid',
16
- LAZY_FALLBACK: 'lazy fallback',
17
- SIGNAL_CREATION_FAILED: 'signal creation failed',
18
- UPDATE_PATH_NOT_FOUND: 'update path not found',
19
- UPDATE_FAILED: 'update failed',
20
- ROLLBACK_FAILED: 'rollback failed',
21
- CLEANUP_ERROR: 'cleanup error',
22
- PRESET_UNKNOWN: 'unknown preset',
23
- STRATEGY_SELECTION: 'strategy select',
24
- TREE_DESTROYED: 'destroyed',
25
- UPDATE_TRANSACTION: 'update tx',
26
- BATCH_NOT_ENABLED: 'batching disabled',
27
- MEMOIZE_NOT_ENABLED: 'memoize disabled',
28
- MIDDLEWARE_NOT_AVAILABLE: 'middleware missing',
29
- ENTITY_HELPERS_NOT_AVAILABLE: 'entity helpers missing',
30
- ASYNC_ACTIONS_NOT_AVAILABLE: 'async actions missing',
31
- TIME_TRAVEL_NOT_AVAILABLE: 'time travel missing',
32
- OPTIMIZE_NOT_AVAILABLE: 'optimize missing',
33
- CACHE_NOT_AVAILABLE: 'cache missing',
34
- PERFORMANCE_NOT_ENABLED: 'performance disabled',
35
- ENHANCER_ORDER_FAILED: 'enhancer order failed',
36
- ENHANCER_CYCLE_DETECTED: 'enhancer cycle',
37
- ENHANCER_REQUIREMENT_MISSING: 'enhancer req missing',
38
- ENHANCER_PROVIDES_MISSING: 'enhancer provides missing',
39
- ENHANCER_FAILED: 'enhancer failed',
40
- ENHANCER_NOT_FUNCTION: 'enhancer not function',
41
- EFFECT_NO_CONTEXT: 'no angular context',
42
- SUBSCRIBE_NO_CONTEXT: 'no angular context',
43
- };
44
- const PROD_MESSAGES = (() => {
45
- const out = {};
46
- let i = 0;
47
- for (const k of Object.keys(DEV_MESSAGES)) {
48
- out[k] = String(i++);
49
- }
50
- return out;
51
- })();
52
- const _isProdByEnv = Boolean(typeof globalThis === 'object' &&
53
- globalThis !== null &&
54
- 'process' in globalThis &&
55
- typeof globalThis.process === 'object' &&
56
- 'env' in globalThis.process &&
57
- globalThis.process.env.NODE_ENV === 'production');
58
- const _isDev = typeof ngDevMode !== 'undefined' ? Boolean(ngDevMode) : !_isProdByEnv;
59
- const SIGNAL_TREE_MESSAGES = Object.freeze(_isDev
60
- ? DEV_MESSAGES
61
- : PROD_MESSAGES);
62
-
63
- const ENHANCER_META = Symbol('signaltree:enhancer:meta');
64
- function isSignalTree(value) {
65
- return (value !== null &&
66
- typeof value === 'function' &&
67
- 'state' in value &&
68
- '$' in value &&
69
- 'with' in value &&
70
- 'destroy' in value);
71
- }
72
-
73
- function createEnhancer(meta, enhancerFn) {
74
- const fn = enhancerFn;
75
- try {
76
- fn.metadata = meta;
77
- try {
78
- fn[ENHANCER_META] = meta;
79
- }
80
- catch {
81
- }
82
- }
83
- catch {
84
- }
85
- return fn;
86
- }
87
- function resolveEnhancerOrder(enhancers, availableCapabilities = new Set(), debugMode = false) {
88
- const nodes = enhancers.map((e, idx) => ({
89
- fn: e,
90
- name: e.metadata && e.metadata.name
91
- ? String(e.metadata.name)
92
- : `enhancer#${idx}`,
93
- requires: new Set(e.metadata?.requires ?? []),
94
- provides: new Set(e.metadata?.provides ?? []),
95
- }));
96
- const adj = new Map();
97
- const nameToNode = new Map();
98
- for (const n of nodes) {
99
- nameToNode.set(n.name, n);
100
- adj.set(n.name, new Set());
101
- }
102
- for (const a of nodes) {
103
- for (const b of nodes) {
104
- if (a === b)
105
- continue;
106
- for (const req of b.requires) {
107
- if (availableCapabilities.has(req))
108
- continue;
109
- if (a.provides.has(req)) {
110
- const set = adj.get(a.name);
111
- if (set)
112
- set.add(b.name);
113
- }
114
- }
115
- }
116
- }
117
- const inDegree = new Map();
118
- for (const entry of adj.keys())
119
- inDegree.set(entry, 0);
120
- for (const [, outs] of adj) {
121
- for (const to of outs)
122
- inDegree.set(to, (inDegree.get(to) || 0) + 1);
123
- }
124
- const queue = [];
125
- for (const [name, deg] of inDegree.entries()) {
126
- if (deg === 0)
127
- queue.push(name);
128
- }
129
- const ordered = [];
130
- while (queue.length > 0) {
131
- const n = queue.shift();
132
- if (!n)
133
- break;
134
- ordered.push(n);
135
- const outs = adj.get(n);
136
- if (!outs)
137
- continue;
138
- for (const m of outs) {
139
- inDegree.set(m, (inDegree.get(m) || 0) - 1);
140
- if (inDegree.get(m) === 0)
141
- queue.push(m);
142
- }
143
- }
144
- if (ordered.length !== nodes.length) {
145
- if (debugMode) {
146
- console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_CYCLE_DETECTED);
147
- }
148
- return enhancers;
149
- }
150
- return ordered.map((name) => {
151
- const n = nameToNode.get(name);
152
- return (n ? n.fn : enhancers[0]);
153
- });
154
- }
155
-
156
- const CALLABLE_SIGNAL_SYMBOL = Symbol.for('NodeAccessor');
157
- function equal(a, b) {
158
- if (a === b)
159
- return true;
160
- if (a == null || b == null)
161
- return a === b;
162
- const typeA = typeof a;
163
- const typeB = typeof b;
164
- if (typeA !== typeB)
165
- return false;
166
- if (typeA !== 'object')
167
- return false;
168
- if (a instanceof Date && b instanceof Date)
169
- return a.getTime() === b.getTime();
170
- if (a instanceof RegExp && b instanceof RegExp)
171
- return a.source === b.source && a.flags === b.flags;
172
- if (a instanceof Map && b instanceof Map) {
173
- if (a.size !== b.size)
174
- return false;
175
- for (const [key, value] of a) {
176
- if (!b.has(key) || !equal(value, b.get(key)))
177
- return false;
178
- }
179
- return true;
180
- }
181
- if (a instanceof Set && b instanceof Set) {
182
- if (a.size !== b.size)
183
- return false;
184
- for (const value of a) {
185
- if (!b.has(value))
186
- return false;
187
- }
188
- return true;
189
- }
190
- if (Array.isArray(a)) {
191
- if (!Array.isArray(b) || a.length !== b.length)
192
- return false;
193
- return a.every((item, i) => equal(item, b[i]));
194
- }
195
- if (Array.isArray(b))
196
- return false;
197
- const objA = a;
198
- const objB = b;
199
- const keysA = Object.keys(objA);
200
- const keysB = Object.keys(objB);
201
- if (keysA.length !== keysB.length)
202
- return false;
203
- return keysA.every((k) => k in objB && equal(objA[k], objB[k]));
204
- }
205
- const deepEqual = equal;
206
- function isBuiltInObject(v) {
207
- if (v === null || v === undefined)
208
- return false;
209
- if (v instanceof Date ||
210
- v instanceof RegExp ||
211
- typeof v === 'function' ||
212
- v instanceof Map ||
213
- v instanceof Set ||
214
- v instanceof WeakMap ||
215
- v instanceof WeakSet ||
216
- v instanceof ArrayBuffer ||
217
- v instanceof DataView ||
218
- v instanceof Error ||
219
- v instanceof Promise) {
220
- return true;
221
- }
222
- if (v instanceof Int8Array ||
223
- v instanceof Uint8Array ||
224
- v instanceof Uint8ClampedArray ||
225
- v instanceof Int16Array ||
226
- v instanceof Uint16Array ||
227
- v instanceof Int32Array ||
228
- v instanceof Uint32Array ||
229
- v instanceof Float32Array ||
230
- v instanceof Float64Array ||
231
- v instanceof BigInt64Array ||
232
- v instanceof BigUint64Array) {
233
- return true;
234
- }
235
- if (typeof window !== 'undefined') {
236
- if (v instanceof URL ||
237
- v instanceof URLSearchParams ||
238
- v instanceof FormData ||
239
- v instanceof Blob ||
240
- (typeof File !== 'undefined' && v instanceof File) ||
241
- (typeof FileList !== 'undefined' && v instanceof FileList) ||
242
- (typeof Headers !== 'undefined' && v instanceof Headers) ||
243
- (typeof Request !== 'undefined' && v instanceof Request) ||
244
- (typeof Response !== 'undefined' && v instanceof Response) ||
245
- (typeof AbortController !== 'undefined' &&
246
- v instanceof AbortController) ||
247
- (typeof AbortSignal !== 'undefined' && v instanceof AbortSignal)) {
248
- return true;
249
- }
250
- }
251
- try {
252
- const NodeBuffer = globalThis?.Buffer;
253
- if (NodeBuffer &&
254
- v instanceof NodeBuffer)
255
- return true;
256
- }
257
- catch {
258
- }
259
- return false;
260
- }
261
- function isNodeAccessor$1(value) {
262
- return (typeof value === 'function' && value && CALLABLE_SIGNAL_SYMBOL in value);
263
- }
264
- function isAnySignal(value) {
265
- return isSignal(value) || isNodeAccessor$1(value);
266
- }
267
- class LRUCache {
268
- maxSize;
269
- cache = new Map();
270
- constructor(maxSize) {
271
- this.maxSize = maxSize;
272
- }
273
- set(key, value) {
274
- if (this.cache.size >= this.maxSize) {
275
- const firstKey = this.cache.keys().next().value;
276
- if (firstKey !== undefined)
277
- this.cache.delete(firstKey);
278
- }
279
- this.cache.delete(key);
280
- this.cache.set(key, value);
281
- }
282
- get(key) {
283
- const value = this.cache.get(key);
284
- if (value !== undefined) {
285
- this.cache.delete(key);
286
- this.cache.set(key, value);
287
- }
288
- return value;
289
- }
290
- clear() {
291
- this.cache.clear();
292
- }
293
- size() {
294
- return this.cache.size;
295
- }
296
- }
297
- const pathCache = new LRUCache(SIGNAL_TREE_CONSTANTS.MAX_PATH_CACHE_SIZE);
298
- function parsePath(path) {
299
- const cached = pathCache.get(path);
300
- if (cached)
301
- return cached;
302
- const parts = path.split('.');
303
- pathCache.set(path, parts);
304
- return parts;
305
- }
306
- function composeEnhancers(...enhancers) {
307
- return (tree) => enhancers.reduce((t, e) => e(t), tree);
308
- }
309
- function createLazySignalTree(obj, equalityFn, basePath = '') {
310
- const signalCache = new Map();
311
- const nestedProxies = new Map();
312
- const nestedCleanups = new Map();
313
- const cleanup = () => {
314
- nestedCleanups.forEach((fn) => {
315
- try {
316
- fn();
317
- }
318
- catch (error) {
319
- console.warn('Error during nested cleanup:', error);
320
- }
321
- });
322
- nestedCleanups.clear();
323
- signalCache.clear();
324
- nestedProxies.clear();
325
- };
326
- const proxy = new Proxy(obj, {
327
- get(target, prop) {
328
- if (prop === '__cleanup__')
329
- return cleanup;
330
- if (typeof prop === 'symbol') {
331
- return target[prop];
332
- }
333
- if (prop === 'valueOf' || prop === 'toString') {
334
- return target[prop];
335
- }
336
- const key = prop;
337
- const path = basePath ? `${basePath}.${key}` : key;
338
- if (!(key in target))
339
- return undefined;
340
- const value = target[key];
341
- if (isSignal(value))
342
- return value;
343
- if (signalCache.has(path))
344
- return signalCache.get(path);
345
- if (nestedProxies.has(path))
346
- return nestedProxies.get(path);
347
- if (value &&
348
- typeof value === 'object' &&
349
- !Array.isArray(value) &&
350
- !isSignal(value) &&
351
- !isBuiltInObject(value)) {
352
- try {
353
- const nestedProxy = createLazySignalTree(value, equalityFn, path);
354
- nestedProxies.set(path, nestedProxy);
355
- const proxyWithCleanup = nestedProxy;
356
- if (typeof proxyWithCleanup.__cleanup__ === 'function') {
357
- nestedCleanups.set(path, proxyWithCleanup.__cleanup__);
358
- }
359
- return nestedProxy;
360
- }
361
- catch (error) {
362
- console.warn(`Failed to create lazy proxy for path "${path}":`, error);
363
- const fallbackSignal = signal(value, ...(ngDevMode ? [{ debugName: "fallbackSignal", equal: equalityFn }] : [{ equal: equalityFn }]));
364
- signalCache.set(path, fallbackSignal);
365
- return fallbackSignal;
366
- }
367
- }
368
- try {
369
- const newSignal = signal(value, ...(ngDevMode ? [{ debugName: "newSignal", equal: equalityFn }] : [{ equal: equalityFn }]));
370
- signalCache.set(path, newSignal);
371
- return newSignal;
372
- }
373
- catch (error) {
374
- console.warn(`Failed to create signal for path "${path}":`, error);
375
- return value;
376
- }
377
- },
378
- set(target, prop, value) {
379
- if (typeof prop === 'symbol') {
380
- target[prop] = value;
381
- return true;
382
- }
383
- const key = prop;
384
- const path = basePath ? `${basePath}.${key}` : key;
385
- try {
386
- target[key] = value;
387
- const cachedSignal = signalCache.get(path);
388
- if (cachedSignal && 'set' in cachedSignal) {
389
- cachedSignal.set(value);
390
- }
391
- if (nestedProxies.has(path)) {
392
- const nestedCleanup = nestedCleanups.get(path);
393
- if (nestedCleanup) {
394
- nestedCleanup();
395
- nestedCleanups.delete(path);
396
- }
397
- nestedProxies.delete(path);
398
- }
399
- return true;
400
- }
401
- catch (error) {
402
- console.warn(`Failed to set value for path "${path}":`, error);
403
- return false;
404
- }
405
- },
406
- has(target, prop) {
407
- return prop in target;
408
- },
409
- ownKeys(target) {
410
- return Reflect.ownKeys(target);
411
- },
412
- getOwnPropertyDescriptor(target, prop) {
413
- return Reflect.getOwnPropertyDescriptor(target, prop);
414
- },
415
- });
416
- return proxy;
417
- }
418
- function unwrap(node) {
419
- if (node === null || node === undefined) {
420
- return node;
421
- }
422
- if (isNodeAccessor$1(node)) {
423
- const result = {};
424
- for (const key in node) {
425
- if (!Object.prototype.hasOwnProperty.call(node, key))
426
- continue;
427
- if (key === 'length' || key === 'prototype')
428
- continue;
429
- if (key === 'name') {
430
- const value = node[key];
431
- if (!isSignal(value) && !isNodeAccessor$1(value)) {
432
- continue;
433
- }
434
- }
435
- const value = node[key];
436
- if (isNodeAccessor$1(value)) {
437
- result[key] = unwrap(value);
438
- }
439
- else if (isSignal(value)) {
440
- const unwrappedValue = value();
441
- if (typeof unwrappedValue === 'object' &&
442
- unwrappedValue !== null &&
443
- !Array.isArray(unwrappedValue) &&
444
- !isBuiltInObject(unwrappedValue)) {
445
- result[key] = unwrap(unwrappedValue);
446
- }
447
- else {
448
- result[key] = unwrappedValue;
449
- }
450
- }
451
- else if (typeof value === 'object' &&
452
- value !== null &&
453
- !Array.isArray(value) &&
454
- !isBuiltInObject(value)) {
455
- result[key] = unwrap(value);
456
- }
457
- else {
458
- result[key] = value;
459
- }
460
- }
461
- return result;
462
- }
463
- if (isSignal(node)) {
464
- const value = node();
465
- if (typeof value === 'object' &&
466
- value !== null &&
467
- !Array.isArray(value) &&
468
- !isBuiltInObject(value)) {
469
- return unwrap(value);
470
- }
471
- return value;
472
- }
473
- if (typeof node !== 'object') {
474
- return node;
475
- }
476
- if (Array.isArray(node)) {
477
- return node;
478
- }
479
- if (isBuiltInObject(node)) {
480
- return node;
481
- }
482
- const result = {};
483
- for (const key in node) {
484
- if (!Object.prototype.hasOwnProperty.call(node, key))
485
- continue;
486
- if (key === 'set' || key === 'update') {
487
- const v = node[key];
488
- if (typeof v === 'function')
489
- continue;
490
- }
491
- const value = node[key];
492
- if (isNodeAccessor$1(value)) {
493
- const unwrappedValue = value();
494
- if (typeof unwrappedValue === 'object' &&
495
- unwrappedValue !== null &&
496
- !Array.isArray(unwrappedValue) &&
497
- !isBuiltInObject(unwrappedValue)) {
498
- result[key] = unwrap(unwrappedValue);
499
- }
500
- else {
501
- result[key] = unwrappedValue;
502
- }
503
- }
504
- else if (isSignal(value)) {
505
- const unwrappedValue = value();
506
- if (typeof unwrappedValue === 'object' &&
507
- unwrappedValue !== null &&
508
- !Array.isArray(unwrappedValue) &&
509
- !isBuiltInObject(unwrappedValue)) {
510
- result[key] = unwrap(unwrappedValue);
511
- }
512
- else {
513
- result[key] = unwrappedValue;
514
- }
515
- }
516
- else if (typeof value === 'object' &&
517
- value !== null &&
518
- !Array.isArray(value) &&
519
- !isBuiltInObject(value)) {
520
- result[key] = unwrap(value);
521
- }
522
- else {
523
- result[key] = value;
524
- }
525
- }
526
- const symbols = Object.getOwnPropertySymbols(node);
527
- for (const sym of symbols) {
528
- const value = node[sym];
529
- if (isNodeAccessor$1(value)) {
530
- const unwrappedValue = value();
531
- if (typeof unwrappedValue === 'object' &&
532
- unwrappedValue !== null &&
533
- !Array.isArray(unwrappedValue) &&
534
- !isBuiltInObject(unwrappedValue)) {
535
- result[sym] = unwrap(unwrappedValue);
536
- }
537
- else {
538
- result[sym] = unwrappedValue;
539
- }
540
- }
541
- else if (isSignal(value)) {
542
- const unwrappedValue = value();
543
- if (typeof unwrappedValue === 'object' &&
544
- unwrappedValue !== null &&
545
- !Array.isArray(unwrappedValue) &&
546
- !isBuiltInObject(unwrappedValue)) {
547
- result[sym] = unwrap(unwrappedValue);
548
- }
549
- else {
550
- result[sym] = unwrappedValue;
551
- }
552
- }
553
- else if (typeof value === 'object' &&
554
- value !== null &&
555
- !Array.isArray(value) &&
556
- !isBuiltInObject(value)) {
557
- result[sym] = unwrap(value);
558
- }
559
- else {
560
- result[sym] = value;
561
- }
562
- }
563
- return result;
564
- }
565
-
1
+ import { computed, DestroyRef, effect, inject, isSignal, signal } from '@angular/core';
2
+ import { resolveEnhancerOrder } from '../enhancers';
3
+ import { SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES } from './constants';
4
+ import { SignalMemoryManager } from './memory/memory-manager';
5
+ import { OptimizedUpdateEngine } from './performance/update-engine';
6
+ import { SecurityValidator } from './security/security-validator';
7
+ import { createLazySignalTree, equal, isBuiltInObject, unwrap } from './utils';
566
8
  const NODE_ACCESSOR_SYMBOL = Symbol.for('NodeAccessor');
567
9
  function makeNodeAccessor() {
568
10
  const accessor = function (arg) {
@@ -634,7 +76,7 @@ function recursiveUpdate(target, updates) {
634
76
  }
635
77
  }
636
78
  }
637
- function isNodeAccessor(value) {
79
+ export function isNodeAccessor(value) {
638
80
  return (typeof value === 'function' &&
639
81
  value &&
640
82
  value[NODE_ACCESSOR_SYMBOL] === true);
@@ -680,6 +122,56 @@ function shouldUseLazy(obj, config, precomputedSize) {
680
122
  const estimatedSize = precomputedSize ?? estimateObjectSize(obj);
681
123
  return estimatedSize > SIGNAL_TREE_CONSTANTS.LAZY_THRESHOLD;
682
124
  }
125
+ function validateTree(obj, config, path = []) {
126
+ if (!config.security) {
127
+ return;
128
+ }
129
+ const validator = new SecurityValidator(config.security);
130
+ function validate(value, currentPath) {
131
+ if (value === null || value === undefined) {
132
+ return;
133
+ }
134
+ if (typeof value !== 'object') {
135
+ validator.validateValue(value);
136
+ return;
137
+ }
138
+ if (isBuiltInObject(value)) {
139
+ return;
140
+ }
141
+ if (Array.isArray(value)) {
142
+ value.forEach((item, index) => {
143
+ validate(item, [...currentPath, String(index)]);
144
+ });
145
+ return;
146
+ }
147
+ const keys = [
148
+ ...Object.keys(value),
149
+ ...Object.getOwnPropertyNames(value),
150
+ ];
151
+ const uniqueKeys = [...new Set(keys)];
152
+ for (const key of uniqueKeys) {
153
+ if (typeof key === 'symbol')
154
+ continue;
155
+ try {
156
+ validator.validateKey(key);
157
+ }
158
+ catch (error) {
159
+ const err = error;
160
+ throw new Error(`${err.message}\nPath: ${[...currentPath, key].join('.')}`);
161
+ }
162
+ const val = value[key];
163
+ try {
164
+ validator.validateValue(val);
165
+ }
166
+ catch (error) {
167
+ const err = error;
168
+ throw new Error(`${err.message}\nPath: ${[...currentPath, key].join('.')}`);
169
+ }
170
+ validate(val, [...currentPath, key]);
171
+ }
172
+ }
173
+ validate(obj, path);
174
+ }
683
175
  function createEqualityFn(useShallowComparison) {
684
176
  return useShallowComparison ? Object.is : equal;
685
177
  }
@@ -922,7 +414,7 @@ function addStubMethods(tree, config) {
922
414
  if (!isDestroyed) {
923
415
  fn(tree());
924
416
  }
925
- }, ...(ngDevMode ? [{ debugName: "effectRef" }] : []));
417
+ });
926
418
  const unsubscribe = () => {
927
419
  isDestroyed = true;
928
420
  effectRef.destroy();
@@ -955,6 +447,27 @@ function addStubMethods(tree, config) {
955
447
  }
956
448
  return 0;
957
449
  };
450
+ const treeWithEngine = tree;
451
+ if (!treeWithEngine.updateEngine) {
452
+ treeWithEngine.updateEngine = new OptimizedUpdateEngine(tree);
453
+ }
454
+ tree.updateOptimized = (updates, options = {}) => {
455
+ const treeWithEngine = tree;
456
+ const engine = treeWithEngine.updateEngine;
457
+ if (!engine) {
458
+ if (config.debugMode) {
459
+ console.warn(SIGNAL_TREE_MESSAGES.UPDATE_OPTIMIZED_NOT_AVAILABLE);
460
+ }
461
+ tree((current) => ({ ...current, ...updates }));
462
+ return {
463
+ changed: true,
464
+ duration: 0,
465
+ changedPaths: Object.keys(updates),
466
+ stats: undefined,
467
+ };
468
+ }
469
+ return engine.update(tree(), updates, options);
470
+ };
958
471
  tree.getMetrics = () => {
959
472
  return {
960
473
  updates: 0,
@@ -1016,6 +529,7 @@ function create(obj, config = {}) {
1016
529
  if (obj === null || obj === undefined) {
1017
530
  throw new Error(SIGNAL_TREE_MESSAGES.NULL_OR_UNDEFINED);
1018
531
  }
532
+ validateTree(obj, config);
1019
533
  const estimatedSize = estimateObjectSize(obj);
1020
534
  const equalityFn = createEqualityFn(config.useShallowComparison ?? false);
1021
535
  if (Array.isArray(obj)) {
@@ -1036,9 +550,11 @@ function create(obj, config = {}) {
1036
550
  console.log(SIGNAL_TREE_MESSAGES.STRATEGY_SELECTION.replace('%s', useLazy ? 'lazy' : 'eager').replace('%d', String(estimatedSize)));
1037
551
  }
1038
552
  let signalState;
553
+ let memoryManager;
1039
554
  try {
1040
555
  if (useLazy && typeof obj === 'object') {
1041
- signalState = createLazySignalTree(obj, equalityFn);
556
+ memoryManager = new SignalMemoryManager();
557
+ signalState = createLazySignalTree(obj, equalityFn, '', memoryManager);
1042
558
  }
1043
559
  else {
1044
560
  signalState = createSignalStore(obj, equalityFn);
@@ -1048,6 +564,7 @@ function create(obj, config = {}) {
1048
564
  if (useLazy) {
1049
565
  console.warn(SIGNAL_TREE_MESSAGES.LAZY_FALLBACK, error);
1050
566
  signalState = createSignalStore(obj, equalityFn);
567
+ memoryManager = undefined;
1051
568
  }
1052
569
  else {
1053
570
  throw error;
@@ -1076,6 +593,19 @@ function create(obj, config = {}) {
1076
593
  enumerable: false,
1077
594
  });
1078
595
  Object.defineProperty(tree, '$', { value: signalState, enumerable: false });
596
+ if (memoryManager) {
597
+ Object.defineProperty(tree, 'dispose', {
598
+ value: () => {
599
+ memoryManager?.dispose();
600
+ const cleanup = signalState.__cleanup__;
601
+ if (typeof cleanup === 'function') {
602
+ cleanup();
603
+ }
604
+ },
605
+ enumerable: false,
606
+ writable: false,
607
+ });
608
+ }
1079
609
  enhanceTree(tree, config);
1080
610
  for (const key in signalState) {
1081
611
  if (Object.prototype.hasOwnProperty.call(signalState, key)) {
@@ -1118,7 +648,7 @@ const presetConfigs = {
1118
648
  debugMode: false,
1119
649
  },
1120
650
  };
1121
- function signalTree(obj, configOrPreset) {
651
+ export function signalTree(obj, configOrPreset) {
1122
652
  if (typeof configOrPreset === 'string') {
1123
653
  const config = presetConfigs[configOrPreset];
1124
654
  if (!config) {
@@ -1130,9 +660,6 @@ function signalTree(obj, configOrPreset) {
1130
660
  const config = configOrPreset || {};
1131
661
  return create(obj, config);
1132
662
  }
1133
- function applyEnhancer(tree, enhancer) {
663
+ export function applyEnhancer(tree, enhancer) {
1134
664
  return enhancer(tree);
1135
665
  }
1136
-
1137
- export { ENHANCER_META, SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, composeEnhancers, createEnhancer, createLazySignalTree, deepEqual, equal, isAnySignal, isBuiltInObject, isNodeAccessor$1 as isNodeAccessor, parsePath, resolveEnhancerOrder, signalTree };
1138
- //# sourceMappingURL=signaltree-core.mjs.map