@signaltree/core 1.1.7 → 2.0.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.
@@ -1,5 +1,159 @@
1
1
  import { signal, isSignal, computed, effect, inject, DestroyRef } from '@angular/core';
2
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');
3
157
  function equal(a, b) {
4
158
  if (a === b)
5
159
  return true;
@@ -11,12 +165,10 @@ function equal(a, b) {
11
165
  return false;
12
166
  if (typeA !== 'object')
13
167
  return false;
14
- if (a instanceof Date && b instanceof Date) {
168
+ if (a instanceof Date && b instanceof Date)
15
169
  return a.getTime() === b.getTime();
16
- }
17
- if (a instanceof RegExp && b instanceof RegExp) {
170
+ if (a instanceof RegExp && b instanceof RegExp)
18
171
  return a.source === b.source && a.flags === b.flags;
19
- }
20
172
  if (a instanceof Map && b instanceof Map) {
21
173
  if (a.size !== b.size)
22
174
  return false;
@@ -38,7 +190,7 @@ function equal(a, b) {
38
190
  if (Array.isArray(a)) {
39
191
  if (!Array.isArray(b) || a.length !== b.length)
40
192
  return false;
41
- return a.every((item, index) => equal(item, b[index]));
193
+ return a.every((item, i) => equal(item, b[i]));
42
194
  }
43
195
  if (Array.isArray(b))
44
196
  return false;
@@ -48,13 +200,75 @@ function equal(a, b) {
48
200
  const keysB = Object.keys(objB);
49
201
  if (keysA.length !== keysB.length)
50
202
  return false;
51
- return keysA.every((key) => key in objB && equal(objA[key], objB[key]));
203
+ return keysA.every((k) => k in objB && equal(objA[k], objB[k]));
52
204
  }
205
+ const deepEqual = equal;
53
206
  function terminalSignal(value, customEqual) {
54
207
  return signal(value, {
55
208
  equal: customEqual || equal,
56
209
  });
57
210
  }
211
+ function isBuiltInObject(v) {
212
+ if (v === null || v === undefined)
213
+ return false;
214
+ if (v instanceof Date ||
215
+ v instanceof RegExp ||
216
+ typeof v === 'function' ||
217
+ v instanceof Map ||
218
+ v instanceof Set ||
219
+ v instanceof WeakMap ||
220
+ v instanceof WeakSet ||
221
+ v instanceof ArrayBuffer ||
222
+ v instanceof DataView ||
223
+ v instanceof Error ||
224
+ v instanceof Promise) {
225
+ return true;
226
+ }
227
+ if (v instanceof Int8Array ||
228
+ v instanceof Uint8Array ||
229
+ v instanceof Uint8ClampedArray ||
230
+ v instanceof Int16Array ||
231
+ v instanceof Uint16Array ||
232
+ v instanceof Int32Array ||
233
+ v instanceof Uint32Array ||
234
+ v instanceof Float32Array ||
235
+ v instanceof Float64Array ||
236
+ v instanceof BigInt64Array ||
237
+ v instanceof BigUint64Array) {
238
+ return true;
239
+ }
240
+ if (typeof window !== 'undefined') {
241
+ if (v instanceof URL ||
242
+ v instanceof URLSearchParams ||
243
+ v instanceof FormData ||
244
+ v instanceof Blob ||
245
+ (typeof File !== 'undefined' && v instanceof File) ||
246
+ (typeof FileList !== 'undefined' && v instanceof FileList) ||
247
+ (typeof Headers !== 'undefined' && v instanceof Headers) ||
248
+ (typeof Request !== 'undefined' && v instanceof Request) ||
249
+ (typeof Response !== 'undefined' && v instanceof Response) ||
250
+ (typeof AbortController !== 'undefined' &&
251
+ v instanceof AbortController) ||
252
+ (typeof AbortSignal !== 'undefined' && v instanceof AbortSignal)) {
253
+ return true;
254
+ }
255
+ }
256
+ try {
257
+ const NodeBuffer = globalThis?.Buffer;
258
+ if (NodeBuffer &&
259
+ v instanceof NodeBuffer)
260
+ return true;
261
+ }
262
+ catch {
263
+ }
264
+ return false;
265
+ }
266
+ function isNodeAccessor$1(value) {
267
+ return (typeof value === 'function' && value && CALLABLE_SIGNAL_SYMBOL in value);
268
+ }
269
+ function isAnySignal(value) {
270
+ return isSignal(value) || isNodeAccessor$1(value);
271
+ }
58
272
  class LRUCache {
59
273
  maxSize;
60
274
  cache = new Map();
@@ -64,9 +278,8 @@ class LRUCache {
64
278
  set(key, value) {
65
279
  if (this.cache.size >= this.maxSize) {
66
280
  const firstKey = this.cache.keys().next().value;
67
- if (firstKey !== undefined) {
281
+ if (firstKey !== undefined)
68
282
  this.cache.delete(firstKey);
69
- }
70
283
  }
71
284
  this.cache.delete(key);
72
285
  this.cache.set(key, value);
@@ -86,25 +299,26 @@ class LRUCache {
86
299
  return this.cache.size;
87
300
  }
88
301
  }
89
- const MAX_CACHE_SIZE = 1000;
90
- const pathCache = new LRUCache(MAX_CACHE_SIZE);
302
+ const pathCache = new LRUCache(SIGNAL_TREE_CONSTANTS.MAX_PATH_CACHE_SIZE);
91
303
  function parsePath(path) {
92
304
  const cached = pathCache.get(path);
93
- if (cached) {
305
+ if (cached)
94
306
  return cached;
95
- }
96
307
  const parts = path.split('.');
97
308
  pathCache.set(path, parts);
98
309
  return parts;
99
310
  }
311
+ function composeEnhancers(...enhancers) {
312
+ return (tree) => enhancers.reduce((t, e) => e(t), tree);
313
+ }
100
314
  function createLazySignalTree(obj, equalityFn, basePath = '') {
101
315
  const signalCache = new Map();
102
316
  const nestedProxies = new Map();
103
317
  const nestedCleanups = new Map();
104
318
  const cleanup = () => {
105
- nestedCleanups.forEach((cleanupFn) => {
319
+ nestedCleanups.forEach((fn) => {
106
320
  try {
107
- cleanupFn();
321
+ fn();
108
322
  }
109
323
  catch (error) {
110
324
  console.warn('Error during nested cleanup:', error);
@@ -114,31 +328,10 @@ function createLazySignalTree(obj, equalityFn, basePath = '') {
114
328
  signalCache.clear();
115
329
  nestedProxies.clear();
116
330
  };
117
- const isBuiltInObject = (v) => {
118
- if (v === null || v === undefined)
119
- return false;
120
- return (v instanceof Date ||
121
- v instanceof RegExp ||
122
- typeof v === 'function' ||
123
- v instanceof Map ||
124
- v instanceof Set ||
125
- v instanceof WeakMap ||
126
- v instanceof WeakSet ||
127
- v instanceof ArrayBuffer ||
128
- v instanceof DataView ||
129
- v instanceof Error ||
130
- v instanceof Promise ||
131
- v instanceof URL ||
132
- v instanceof URLSearchParams ||
133
- v instanceof FormData ||
134
- v instanceof Blob ||
135
- (typeof File !== 'undefined' && v instanceof File));
136
- };
137
331
  const proxy = new Proxy(obj, {
138
332
  get(target, prop) {
139
- if (prop === '__cleanup__') {
333
+ if (prop === '__cleanup__')
140
334
  return cleanup;
141
- }
142
335
  if (typeof prop === 'symbol') {
143
336
  return target[prop];
144
337
  }
@@ -147,19 +340,15 @@ function createLazySignalTree(obj, equalityFn, basePath = '') {
147
340
  }
148
341
  const key = prop;
149
342
  const path = basePath ? `${basePath}.${key}` : key;
150
- if (!(key in target)) {
343
+ if (!(key in target))
151
344
  return undefined;
152
- }
153
345
  const value = target[key];
154
- if (isSignal(value)) {
346
+ if (isSignal(value))
155
347
  return value;
156
- }
157
- if (signalCache.has(path)) {
348
+ if (signalCache.has(path))
158
349
  return signalCache.get(path);
159
- }
160
- if (nestedProxies.has(path)) {
350
+ if (nestedProxies.has(path))
161
351
  return nestedProxies.get(path);
162
- }
163
352
  if (value &&
164
353
  typeof value === 'object' &&
165
354
  !Array.isArray(value) &&
@@ -231,37 +420,234 @@ function createLazySignalTree(obj, equalityFn, basePath = '') {
231
420
  });
232
421
  return proxy;
233
422
  }
234
- const deepEqual = equal;
235
- function shallowEqual(a, b) {
236
- if (a === b)
237
- return true;
238
- if (a == null || b == null)
239
- return false;
240
- if (Array.isArray(a) && Array.isArray(b)) {
241
- if (a.length !== b.length)
242
- return false;
243
- for (let i = 0; i < a.length; i++) {
244
- if (a[i] !== b[i])
245
- return false;
423
+ function unwrap(node) {
424
+ if (node === null || node === undefined) {
425
+ return node;
426
+ }
427
+ if (isNodeAccessor$1(node)) {
428
+ const result = {};
429
+ for (const key in node) {
430
+ if (!Object.prototype.hasOwnProperty.call(node, key))
431
+ continue;
432
+ if (key === 'length' || key === 'prototype')
433
+ continue;
434
+ if (key === 'name') {
435
+ const value = node[key];
436
+ if (!isSignal(value) && !isNodeAccessor$1(value)) {
437
+ continue;
438
+ }
439
+ }
440
+ const value = node[key];
441
+ if (isNodeAccessor$1(value)) {
442
+ result[key] = unwrap(value);
443
+ }
444
+ else if (isSignal(value)) {
445
+ const unwrappedValue = value();
446
+ if (typeof unwrappedValue === 'object' &&
447
+ unwrappedValue !== null &&
448
+ !Array.isArray(unwrappedValue) &&
449
+ !isBuiltInObject(unwrappedValue)) {
450
+ result[key] = unwrap(unwrappedValue);
451
+ }
452
+ else {
453
+ result[key] = unwrappedValue;
454
+ }
455
+ }
456
+ else if (typeof value === 'object' &&
457
+ value !== null &&
458
+ !Array.isArray(value) &&
459
+ !isBuiltInObject(value)) {
460
+ result[key] = unwrap(value);
461
+ }
462
+ else {
463
+ result[key] = value;
464
+ }
246
465
  }
247
- return true;
466
+ return result;
248
467
  }
249
- if (typeof a === 'object' && typeof b === 'object') {
250
- const keysA = Object.keys(a);
251
- const keysB = Object.keys(b);
252
- if (keysA.length !== keysB.length)
253
- return false;
254
- for (const key of keysA) {
255
- if (a[key] !==
256
- b[key])
257
- return false;
468
+ if (isSignal(node)) {
469
+ const value = node();
470
+ if (typeof value === 'object' &&
471
+ value !== null &&
472
+ !Array.isArray(value) &&
473
+ !isBuiltInObject(value)) {
474
+ return unwrap(value);
258
475
  }
259
- return true;
476
+ return value;
260
477
  }
261
- return false;
478
+ if (typeof node !== 'object') {
479
+ return node;
480
+ }
481
+ if (Array.isArray(node)) {
482
+ return node;
483
+ }
484
+ if (isBuiltInObject(node)) {
485
+ return node;
486
+ }
487
+ const result = {};
488
+ for (const key in node) {
489
+ if (!Object.prototype.hasOwnProperty.call(node, key))
490
+ continue;
491
+ if (key === 'set' || key === 'update') {
492
+ const v = node[key];
493
+ if (typeof v === 'function')
494
+ continue;
495
+ }
496
+ const value = node[key];
497
+ if (isNodeAccessor$1(value)) {
498
+ const unwrappedValue = value();
499
+ if (typeof unwrappedValue === 'object' &&
500
+ unwrappedValue !== null &&
501
+ !Array.isArray(unwrappedValue) &&
502
+ !isBuiltInObject(unwrappedValue)) {
503
+ result[key] = unwrap(unwrappedValue);
504
+ }
505
+ else {
506
+ result[key] = unwrappedValue;
507
+ }
508
+ }
509
+ else if (isSignal(value)) {
510
+ const unwrappedValue = value();
511
+ if (typeof unwrappedValue === 'object' &&
512
+ unwrappedValue !== null &&
513
+ !Array.isArray(unwrappedValue) &&
514
+ !isBuiltInObject(unwrappedValue)) {
515
+ result[key] = unwrap(unwrappedValue);
516
+ }
517
+ else {
518
+ result[key] = unwrappedValue;
519
+ }
520
+ }
521
+ else if (typeof value === 'object' &&
522
+ value !== null &&
523
+ !Array.isArray(value) &&
524
+ !isBuiltInObject(value)) {
525
+ result[key] = unwrap(value);
526
+ }
527
+ else {
528
+ result[key] = value;
529
+ }
530
+ }
531
+ const symbols = Object.getOwnPropertySymbols(node);
532
+ for (const sym of symbols) {
533
+ const value = node[sym];
534
+ if (isNodeAccessor$1(value)) {
535
+ const unwrappedValue = value();
536
+ if (typeof unwrappedValue === 'object' &&
537
+ unwrappedValue !== null &&
538
+ !Array.isArray(unwrappedValue) &&
539
+ !isBuiltInObject(unwrappedValue)) {
540
+ result[sym] = unwrap(unwrappedValue);
541
+ }
542
+ else {
543
+ result[sym] = unwrappedValue;
544
+ }
545
+ }
546
+ else if (isSignal(value)) {
547
+ const unwrappedValue = value();
548
+ if (typeof unwrappedValue === 'object' &&
549
+ unwrappedValue !== null &&
550
+ !Array.isArray(unwrappedValue) &&
551
+ !isBuiltInObject(unwrappedValue)) {
552
+ result[sym] = unwrap(unwrappedValue);
553
+ }
554
+ else {
555
+ result[sym] = unwrappedValue;
556
+ }
557
+ }
558
+ else if (typeof value === 'object' &&
559
+ value !== null &&
560
+ !Array.isArray(value) &&
561
+ !isBuiltInObject(value)) {
562
+ result[sym] = unwrap(value);
563
+ }
564
+ else {
565
+ result[sym] = value;
566
+ }
567
+ }
568
+ return result;
569
+ }
570
+ function cleanUnwrap(node) {
571
+ return unwrap(node);
262
572
  }
263
573
 
264
- function estimateObjectSize(obj, maxDepth = 3, currentDepth = 0) {
574
+ const NODE_ACCESSOR_SYMBOL = Symbol.for('NodeAccessor');
575
+ function makeNodeAccessor() {
576
+ const accessor = function (arg) {
577
+ if (arguments.length === 0) {
578
+ return unwrap(accessor);
579
+ }
580
+ if (typeof arg === 'function') {
581
+ const updater = arg;
582
+ const currentValue = unwrap(accessor);
583
+ const newValue = updater(currentValue);
584
+ recursiveUpdate(accessor, newValue);
585
+ }
586
+ else {
587
+ recursiveUpdate(accessor, arg);
588
+ }
589
+ };
590
+ accessor[NODE_ACCESSOR_SYMBOL] = true;
591
+ return accessor;
592
+ }
593
+ function makeRootNodeAccessor(readSignal, writeSignal) {
594
+ const accessor = function (arg) {
595
+ if (arguments.length === 0) {
596
+ return readSignal();
597
+ }
598
+ if (typeof arg === 'function') {
599
+ const updater = arg;
600
+ writeSignal.set(updater(readSignal()));
601
+ }
602
+ else {
603
+ writeSignal.set(arg);
604
+ }
605
+ };
606
+ accessor[NODE_ACCESSOR_SYMBOL] = true;
607
+ return accessor;
608
+ }
609
+ function recursiveUpdate(target, updates) {
610
+ if (!updates || typeof updates !== 'object') {
611
+ return;
612
+ }
613
+ let targetObj;
614
+ if (isNodeAccessor(target)) {
615
+ targetObj = target;
616
+ }
617
+ else if (target && typeof target === 'object') {
618
+ targetObj = target;
619
+ }
620
+ else {
621
+ return;
622
+ }
623
+ const updatesObj = updates;
624
+ for (const key in updatesObj) {
625
+ if (!(key in targetObj)) {
626
+ continue;
627
+ }
628
+ const targetProp = targetObj[key];
629
+ const updateValue = updatesObj[key];
630
+ if (isSignal(targetProp)) {
631
+ if ('set' in targetProp && typeof targetProp.set === 'function') {
632
+ targetProp.set(updateValue);
633
+ }
634
+ }
635
+ else if (isNodeAccessor(targetProp)) {
636
+ if (updateValue && typeof updateValue === 'object') {
637
+ recursiveUpdate(targetProp, updateValue);
638
+ }
639
+ else {
640
+ targetProp(updateValue);
641
+ }
642
+ }
643
+ }
644
+ }
645
+ function isNodeAccessor(value) {
646
+ return (typeof value === 'function' &&
647
+ value &&
648
+ value[NODE_ACCESSOR_SYMBOL] === true);
649
+ }
650
+ function estimateObjectSize(obj, maxDepth = SIGNAL_TREE_CONSTANTS.ESTIMATE_MAX_DEPTH, currentDepth = 0) {
265
651
  if (currentDepth >= maxDepth)
266
652
  return 1;
267
653
  if (obj === null || obj === undefined)
@@ -272,7 +658,7 @@ function estimateObjectSize(obj, maxDepth = 3, currentDepth = 0) {
272
658
  try {
273
659
  if (Array.isArray(obj)) {
274
660
  size = obj.length;
275
- const sampleSize = Math.min(3, obj.length);
661
+ const sampleSize = Math.min(SIGNAL_TREE_CONSTANTS.ESTIMATE_SAMPLE_SIZE_ARRAY, obj.length);
276
662
  for (let i = 0; i < sampleSize; i++) {
277
663
  size += estimateObjectSize(obj[i], maxDepth, currentDepth + 1) * 0.1;
278
664
  }
@@ -280,7 +666,7 @@ function estimateObjectSize(obj, maxDepth = 3, currentDepth = 0) {
280
666
  else {
281
667
  const keys = Object.keys(obj);
282
668
  size = keys.length;
283
- const sampleSize = Math.min(5, keys.length);
669
+ const sampleSize = Math.min(SIGNAL_TREE_CONSTANTS.ESTIMATE_SAMPLE_SIZE_OBJECT, keys.length);
284
670
  for (let i = 0; i < sampleSize; i++) {
285
671
  const value = obj[keys[i]];
286
672
  size += estimateObjectSize(value, maxDepth, currentDepth + 1) * 0.5;
@@ -292,112 +678,19 @@ function estimateObjectSize(obj, maxDepth = 3, currentDepth = 0) {
292
678
  }
293
679
  return Math.floor(size);
294
680
  }
295
- function shouldUseLazy(obj, config) {
296
- if (config.useLazySignals !== undefined) {
681
+ function shouldUseLazy(obj, config, precomputedSize) {
682
+ if (config.useLazySignals !== undefined)
297
683
  return config.useLazySignals;
298
- }
299
- if (config.debugMode || config.enableDevTools) {
684
+ if (config.debugMode || config.enableDevTools)
300
685
  return false;
301
- }
302
- if (config.batchUpdates && config.useMemoization) {
686
+ if (config.batchUpdates && config.useMemoization)
303
687
  return true;
304
- }
305
- const estimatedSize = estimateObjectSize(obj);
306
- return estimatedSize > 50;
688
+ const estimatedSize = precomputedSize ?? estimateObjectSize(obj);
689
+ return estimatedSize > SIGNAL_TREE_CONSTANTS.LAZY_THRESHOLD;
307
690
  }
308
691
  function createEqualityFn(useShallowComparison) {
309
692
  return useShallowComparison ? Object.is : equal;
310
693
  }
311
- function isBuiltInObject(v) {
312
- if (v === null || v === undefined)
313
- return false;
314
- if (v instanceof Date ||
315
- v instanceof RegExp ||
316
- typeof v === 'function' ||
317
- v instanceof Map ||
318
- v instanceof Set ||
319
- v instanceof WeakMap ||
320
- v instanceof WeakSet ||
321
- v instanceof ArrayBuffer ||
322
- v instanceof DataView ||
323
- v instanceof Error ||
324
- v instanceof Promise) {
325
- return true;
326
- }
327
- if (v instanceof Int8Array ||
328
- v instanceof Uint8Array ||
329
- v instanceof Uint8ClampedArray ||
330
- v instanceof Int16Array ||
331
- v instanceof Uint16Array ||
332
- v instanceof Int32Array ||
333
- v instanceof Uint32Array ||
334
- v instanceof Float32Array ||
335
- v instanceof Float64Array ||
336
- v instanceof BigInt64Array ||
337
- v instanceof BigUint64Array) {
338
- return true;
339
- }
340
- if (typeof window !== 'undefined') {
341
- if (v instanceof URL ||
342
- v instanceof URLSearchParams ||
343
- v instanceof FormData ||
344
- v instanceof Blob ||
345
- (typeof File !== 'undefined' && v instanceof File) ||
346
- (typeof FileList !== 'undefined' && v instanceof FileList) ||
347
- (typeof Headers !== 'undefined' && v instanceof Headers) ||
348
- (typeof Request !== 'undefined' && v instanceof Request) ||
349
- (typeof Response !== 'undefined' && v instanceof Response) ||
350
- (typeof AbortController !== 'undefined' &&
351
- v instanceof AbortController) ||
352
- (typeof AbortSignal !== 'undefined' && v instanceof AbortSignal)) {
353
- return true;
354
- }
355
- }
356
- try {
357
- const NodeBuffer = globalThis?.Buffer;
358
- if (NodeBuffer && v instanceof NodeBuffer) {
359
- return true;
360
- }
361
- }
362
- catch {
363
- }
364
- return false;
365
- }
366
- function create(obj, config = {}) {
367
- if (obj === null || obj === undefined) {
368
- throw new Error('Cannot create SignalTree from null or undefined');
369
- }
370
- const equalityFn = createEqualityFn(config.useShallowComparison ?? false);
371
- const useLazy = shouldUseLazy(obj, config);
372
- if (config.debugMode) {
373
- const estimatedSize = estimateObjectSize(obj);
374
- console.log(`[SignalTree] Creating tree with ${useLazy ? 'lazy' : 'eager'} strategy (estimated size: ${estimatedSize})`);
375
- }
376
- let signalState;
377
- try {
378
- if (useLazy && typeof obj === 'object') {
379
- signalState = createLazySignalTree(obj, equalityFn);
380
- }
381
- else {
382
- signalState = createSignalStore(obj, equalityFn);
383
- }
384
- }
385
- catch (error) {
386
- if (useLazy) {
387
- console.warn('[SignalTree] Lazy creation failed, falling back to eager:', error);
388
- signalState = createSignalStore(obj, equalityFn);
389
- }
390
- else {
391
- throw error;
392
- }
393
- }
394
- const resultTree = {
395
- state: signalState,
396
- $: signalState,
397
- };
398
- enhanceTree(resultTree, config);
399
- return resultTree;
400
- }
401
694
  function createSignalStore(obj, equalityFn) {
402
695
  if (obj === null || obj === undefined || typeof obj !== 'object') {
403
696
  return signal(obj, { equal: equalityFn });
@@ -411,7 +704,7 @@ function createSignalStore(obj, equalityFn) {
411
704
  const store = {};
412
705
  const processedObjects = new WeakSet();
413
706
  if (processedObjects.has(obj)) {
414
- console.warn('[SignalTree] Circular reference detected, creating reference signal');
707
+ console.warn(SIGNAL_TREE_MESSAGES.CIRCULAR_REF);
415
708
  return signal(obj, { equal: equalityFn });
416
709
  }
417
710
  processedObjects.add(obj);
@@ -440,11 +733,26 @@ function createSignalStore(obj, equalityFn) {
440
733
  });
441
734
  }
442
735
  else {
443
- store[key] = createSignalStore(value, equalityFn);
736
+ const branch = createSignalStore(value, equalityFn);
737
+ const callableBranch = makeNodeAccessor();
738
+ for (const branchKey in branch) {
739
+ if (Object.prototype.hasOwnProperty.call(branch, branchKey)) {
740
+ try {
741
+ Object.defineProperty(callableBranch, branchKey, {
742
+ value: branch[branchKey],
743
+ enumerable: true,
744
+ configurable: true,
745
+ });
746
+ }
747
+ catch {
748
+ }
749
+ }
750
+ }
751
+ store[key] = callableBranch;
444
752
  }
445
753
  }
446
754
  catch (error) {
447
- console.warn(`[SignalTree] Failed to create signal for key "${key}":`, error);
755
+ console.warn(`${SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED} "${key}":`, error);
448
756
  store[key] = signal(value, {
449
757
  equal: equalityFn,
450
758
  });
@@ -464,7 +772,7 @@ function createSignalStore(obj, equalityFn) {
464
772
  }
465
773
  }
466
774
  catch (error) {
467
- console.warn(`[SignalTree] Failed to create signal for symbol key:`, error);
775
+ console.warn(SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED, error);
468
776
  }
469
777
  }
470
778
  }
@@ -475,143 +783,81 @@ function createSignalStore(obj, equalityFn) {
475
783
  }
476
784
  function enhanceTree(tree, config = {}) {
477
785
  const isLazy = config.useLazySignals ?? shouldUseLazy(tree.state, config);
478
- tree.unwrap = () => {
479
- const unwrapObject = (obj) => {
480
- if (typeof obj !== 'object' || obj === null) {
481
- return obj;
482
- }
483
- if (isSignal(obj)) {
484
- return obj();
485
- }
486
- if (isSignal(obj)) {
487
- const value = obj();
488
- if (Array.isArray(value)) {
489
- return value;
490
- }
786
+ tree.with = ((...enhancers) => {
787
+ if (enhancers.length === 0) {
788
+ return tree;
789
+ }
790
+ const coreCapabilities = new Set();
791
+ if (config.batchUpdates)
792
+ coreCapabilities.add('batchUpdate');
793
+ if (config.useMemoization)
794
+ coreCapabilities.add('memoize');
795
+ if (config.enableTimeTravel)
796
+ coreCapabilities.add('undo');
797
+ if (config.enableDevTools)
798
+ coreCapabilities.add('connectDevTools');
799
+ try {
800
+ for (const key of Object.keys(tree))
801
+ coreCapabilities.add(String(key));
802
+ }
803
+ catch {
804
+ }
805
+ const hasMetadata = enhancers.some((e) => Boolean(e.metadata && (e.metadata.requires || e.metadata.provides)));
806
+ let orderedEnhancers = enhancers;
807
+ if (hasMetadata) {
808
+ try {
809
+ orderedEnhancers = resolveEnhancerOrder(enhancers, coreCapabilities, config.debugMode);
491
810
  }
492
- const result = {};
493
- for (const key in obj) {
494
- if (!Object.prototype.hasOwnProperty.call(obj, key))
495
- continue;
496
- const value = obj[key];
497
- if (isSignal(value)) {
498
- result[key] = value();
499
- }
500
- else if (typeof value === 'object' &&
501
- value !== null &&
502
- !Array.isArray(value) &&
503
- !isBuiltInObject(value)) {
504
- result[key] = unwrapObject(value);
505
- }
506
- else {
507
- result[key] = value;
508
- }
811
+ catch (err) {
812
+ console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_ORDER_FAILED, err);
509
813
  }
510
- const symbols = Object.getOwnPropertySymbols(obj);
511
- for (const sym of symbols) {
512
- const value = obj[sym];
513
- if (isSignal(value)) {
514
- result[sym] = value();
515
- }
516
- else {
517
- result[sym] = value;
518
- }
814
+ }
815
+ const provided = new Set(coreCapabilities);
816
+ let currentTree = tree;
817
+ for (let i = 0; i < orderedEnhancers.length; i++) {
818
+ const enhancer = orderedEnhancers[i];
819
+ if (typeof enhancer !== 'function') {
820
+ throw new Error(SIGNAL_TREE_MESSAGES.ENHANCER_NOT_FUNCTION.replace('%d', String(i)));
519
821
  }
520
- return result;
521
- };
522
- return unwrapObject(tree.state);
523
- };
524
- tree.update = (updater) => {
525
- const transactionLog = [];
526
- try {
527
- const currentValue = tree.unwrap();
528
- const partialObj = updater(currentValue);
529
- if (!partialObj || typeof partialObj !== 'object') {
530
- throw new Error('Updater must return an object');
531
- }
532
- const updateObject = (target, updates, path = '') => {
533
- for (const key in updates) {
534
- if (!Object.prototype.hasOwnProperty.call(updates, key))
535
- continue;
536
- const updateValue = updates[key];
537
- const currentPath = path ? `${path}.${key}` : key;
538
- const currentSignalOrState = target[key];
539
- try {
540
- if (isSignal(currentSignalOrState)) {
541
- const originalValue = currentSignalOrState();
542
- transactionLog.push({
543
- path: currentPath,
544
- oldValue: originalValue,
545
- newValue: updateValue,
546
- });
547
- currentSignalOrState.set(updateValue);
548
- }
549
- else if (typeof updateValue === 'object' &&
550
- updateValue !== null &&
551
- !Array.isArray(updateValue) &&
552
- !isBuiltInObject(updateValue) &&
553
- typeof currentSignalOrState === 'object' &&
554
- currentSignalOrState !== null &&
555
- !isSignal(currentSignalOrState)) {
556
- updateObject(currentSignalOrState, updateValue, currentPath);
557
- }
558
- else if (currentSignalOrState === undefined) {
559
- console.warn(`[SignalTree] Cannot update non-existent path: ${currentPath}`);
560
- }
822
+ const reqs = enhancer.metadata?.requires ?? [];
823
+ for (const r of reqs) {
824
+ if (!(r in currentTree) && !provided.has(r)) {
825
+ const name = enhancer.metadata?.name ?? `enhancer#${i}`;
826
+ const msg = SIGNAL_TREE_MESSAGES.ENHANCER_REQUIREMENT_MISSING.replace('%s', name).replace('%s', r);
827
+ if (config.debugMode) {
828
+ throw new Error(msg);
561
829
  }
562
- catch (error) {
563
- console.error(`[SignalTree] Failed to update path "${currentPath}":`, error);
564
- throw error;
830
+ else {
831
+ console.warn(msg);
565
832
  }
566
833
  }
567
- };
568
- updateObject(tree.state, partialObj);
569
- if (config.debugMode && transactionLog.length > 0) {
570
- console.log('[SignalTree] Update transaction:', transactionLog);
571
834
  }
572
- }
573
- catch (error) {
574
- console.error('[SignalTree] Update failed, attempting rollback:', error);
575
- for (const { path, oldValue } of transactionLog.reverse()) {
576
- try {
577
- const pathParts = path.split('.');
578
- let current = tree.state;
579
- for (let i = 0; i < pathParts.length - 1; i++) {
580
- current = current[pathParts[i]];
581
- if (!current)
582
- break;
583
- }
584
- if (current) {
585
- const lastKey = pathParts[pathParts.length - 1];
586
- const targetSignal = current[lastKey];
587
- if (isSignal(targetSignal)) {
588
- targetSignal.set(oldValue);
835
+ try {
836
+ const result = enhancer(currentTree);
837
+ if (result !== currentTree)
838
+ currentTree = result;
839
+ const provs = enhancer.metadata?.provides ?? [];
840
+ for (const p of provs)
841
+ provided.add(p);
842
+ if (config.debugMode && provs.length > 0) {
843
+ for (const p of provs) {
844
+ if (!(p in currentTree)) {
845
+ console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_PROVIDES_MISSING.replace('%s', enhancer.metadata?.name ?? String(i)).replace('%s', p));
589
846
  }
590
847
  }
591
848
  }
592
- catch (rollbackError) {
593
- console.error('[SignalTree] Rollback failed for path:', path, rollbackError);
594
- }
595
- }
596
- throw error;
597
- }
598
- };
599
- tree.pipe = ((...fns) => {
600
- if (fns.length === 0) {
601
- return tree;
602
- }
603
- return fns.reduce((acc, fn) => {
604
- if (typeof fn !== 'function') {
605
- throw new Error('All pipe arguments must be functions');
606
- }
607
- try {
608
- return fn(acc);
609
849
  }
610
850
  catch (error) {
611
- console.error('[SignalTree] Pipe function failed:', error);
851
+ const name = enhancer.metadata?.name || `enhancer at index ${i}`;
852
+ console.error(SIGNAL_TREE_MESSAGES.ENHANCER_FAILED.replace('%s', name), error);
853
+ if (config.debugMode) {
854
+ console.error('[SignalTree] Enhancer stack trace:', enhancer);
855
+ console.error('[SignalTree] Tree state at failure:', currentTree);
856
+ }
612
857
  throw error;
613
858
  }
614
- }, tree);
859
+ }
860
+ return currentTree;
615
861
  });
616
862
  tree.destroy = () => {
617
863
  try {
@@ -625,11 +871,11 @@ function enhanceTree(tree, config = {}) {
625
871
  }
626
872
  }
627
873
  if (config.debugMode) {
628
- console.log('[SignalTree] Tree destroyed');
874
+ console.log(SIGNAL_TREE_MESSAGES.TREE_DESTROYED);
629
875
  }
630
876
  }
631
877
  catch (error) {
632
- console.error('[SignalTree] Error during cleanup:', error);
878
+ console.error(SIGNAL_TREE_MESSAGES.CLEANUP_ERROR, error);
633
879
  }
634
880
  };
635
881
  addStubMethods(tree, config);
@@ -637,21 +883,24 @@ function enhanceTree(tree, config = {}) {
637
883
  }
638
884
  function addStubMethods(tree, config) {
639
885
  tree.batchUpdate = (updater) => {
640
- console.warn('⚠️ batchUpdate() called but batching is not enabled.', 'To enable batch updates, install @signaltree/batching');
641
- tree.update(updater);
886
+ console.warn(SIGNAL_TREE_MESSAGES.BATCH_NOT_ENABLED);
887
+ tree((current) => {
888
+ const partial = updater(current);
889
+ return { ...current, ...partial };
890
+ });
642
891
  };
643
892
  tree.memoize = (fn, cacheKey) => {
644
- console.warn('⚠️ memoize() called but memoization is not enabled.', 'To enable memoized computations, install @signaltree/memoization');
893
+ console.warn(SIGNAL_TREE_MESSAGES.MEMOIZE_NOT_ENABLED);
645
894
  void cacheKey;
646
- return computed(() => fn(tree.unwrap()));
895
+ return computed(() => fn(tree()));
647
896
  };
648
897
  tree.effect = (fn) => {
649
898
  try {
650
- effect(() => fn(tree.unwrap()));
899
+ effect(() => fn(tree()));
651
900
  }
652
901
  catch (error) {
653
902
  if (config.debugMode) {
654
- console.warn('Effect requires Angular injection context', error);
903
+ console.warn(SIGNAL_TREE_MESSAGES.EFFECT_NO_CONTEXT, error);
655
904
  }
656
905
  }
657
906
  };
@@ -661,7 +910,7 @@ function addStubMethods(tree, config) {
661
910
  let isDestroyed = false;
662
911
  const effectRef = effect(() => {
663
912
  if (!isDestroyed) {
664
- fn(tree.unwrap());
913
+ fn(tree());
665
914
  }
666
915
  }, ...(ngDevMode ? [{ debugName: "effectRef" }] : []));
667
916
  const unsubscribe = () => {
@@ -673,26 +922,26 @@ function addStubMethods(tree, config) {
673
922
  }
674
923
  catch (error) {
675
924
  if (config.debugMode) {
676
- console.warn('Subscribe requires Angular injection context', error);
925
+ console.warn(SIGNAL_TREE_MESSAGES.SUBSCRIBE_NO_CONTEXT, error);
677
926
  }
678
- fn(tree.unwrap());
927
+ fn(tree());
679
928
  return () => {
680
929
  };
681
930
  }
682
931
  };
683
932
  tree.optimize = () => {
684
933
  if (config.debugMode) {
685
- console.warn('⚠️ optimize() called but tree optimization is not available.');
934
+ console.warn(SIGNAL_TREE_MESSAGES.OPTIMIZE_NOT_AVAILABLE);
686
935
  }
687
936
  };
688
937
  tree.clearCache = () => {
689
938
  if (config.debugMode) {
690
- console.warn('⚠️ clearCache() called but caching is not available.');
939
+ console.warn(SIGNAL_TREE_MESSAGES.CACHE_NOT_AVAILABLE);
691
940
  }
692
941
  };
693
942
  tree.invalidatePattern = () => {
694
943
  if (config.debugMode) {
695
- console.warn('⚠️ invalidatePattern() called but performance optimization is not enabled.');
944
+ console.warn(SIGNAL_TREE_MESSAGES.PERFORMANCE_NOT_ENABLED);
696
945
  }
697
946
  return 0;
698
947
  };
@@ -707,25 +956,25 @@ function addStubMethods(tree, config) {
707
956
  };
708
957
  tree.addTap = (middleware) => {
709
958
  if (config.debugMode) {
710
- console.warn('⚠️ addTap() called but middleware support is not available.');
959
+ console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
711
960
  }
712
961
  void middleware;
713
962
  };
714
963
  tree.removeTap = (id) => {
715
964
  if (config.debugMode) {
716
- console.warn('⚠️ removeTap() called but middleware support is not available.');
965
+ console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
717
966
  }
718
967
  void id;
719
968
  };
720
969
  tree.asCrud = () => {
721
970
  if (config.debugMode) {
722
- console.warn('⚠️ asCrud() called but entity helpers are not available.');
971
+ console.warn(SIGNAL_TREE_MESSAGES.ENTITY_HELPERS_NOT_AVAILABLE);
723
972
  }
724
973
  return {};
725
974
  };
726
975
  tree.asyncAction = (operation, asyncConfig = {}) => {
727
976
  if (config.debugMode) {
728
- console.warn('⚠️ asyncAction() called but async actions are not available.');
977
+ console.warn(SIGNAL_TREE_MESSAGES.ASYNC_ACTIONS_NOT_AVAILABLE);
729
978
  }
730
979
  void operation;
731
980
  void asyncConfig;
@@ -733,55 +982,137 @@ function addStubMethods(tree, config) {
733
982
  };
734
983
  tree.undo = () => {
735
984
  if (config.debugMode) {
736
- console.warn('⚠️ undo() called but time travel is not available.');
985
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
737
986
  }
738
987
  };
739
988
  tree.redo = () => {
740
989
  if (config.debugMode) {
741
- console.warn('⚠️ redo() called but time travel is not available.');
990
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
742
991
  }
743
992
  };
744
993
  tree.getHistory = () => {
745
994
  if (config.debugMode) {
746
- console.warn('⚠️ getHistory() called but time travel is not available.');
995
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
747
996
  }
748
997
  return [];
749
998
  };
750
999
  tree.resetHistory = () => {
751
1000
  if (config.debugMode) {
752
- console.warn('⚠️ resetHistory() called but time travel is not available.');
1001
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
1002
+ }
1003
+ };
1004
+ }
1005
+ function create(obj, config = {}) {
1006
+ if (obj === null || obj === undefined) {
1007
+ throw new Error(SIGNAL_TREE_MESSAGES.NULL_OR_UNDEFINED);
1008
+ }
1009
+ const estimatedSize = estimateObjectSize(obj);
1010
+ const equalityFn = createEqualityFn(config.useShallowComparison ?? false);
1011
+ if (Array.isArray(obj)) {
1012
+ const signalState = signal(obj, {
1013
+ equal: equalityFn,
1014
+ });
1015
+ const tree = makeRootNodeAccessor(signalState, signalState);
1016
+ Object.defineProperty(tree, 'state', {
1017
+ value: signalState,
1018
+ enumerable: false,
1019
+ });
1020
+ Object.defineProperty(tree, '$', { value: signalState, enumerable: false });
1021
+ enhanceTree(tree, config);
1022
+ return tree;
1023
+ }
1024
+ const useLazy = shouldUseLazy(obj, config, estimatedSize);
1025
+ if (config.debugMode) {
1026
+ console.log(SIGNAL_TREE_MESSAGES.STRATEGY_SELECTION.replace('%s', useLazy ? 'lazy' : 'eager').replace('%d', String(estimatedSize)));
1027
+ }
1028
+ let signalState;
1029
+ try {
1030
+ if (useLazy && typeof obj === 'object') {
1031
+ signalState = createLazySignalTree(obj, equalityFn);
1032
+ }
1033
+ else {
1034
+ signalState = createSignalStore(obj, equalityFn);
1035
+ }
1036
+ }
1037
+ catch (error) {
1038
+ if (useLazy) {
1039
+ console.warn(SIGNAL_TREE_MESSAGES.LAZY_FALLBACK, error);
1040
+ signalState = createSignalStore(obj, equalityFn);
1041
+ }
1042
+ else {
1043
+ throw error;
1044
+ }
1045
+ }
1046
+ const tree = function (arg) {
1047
+ if (arguments.length === 0) {
1048
+ return unwrap(signalState);
1049
+ }
1050
+ if (typeof arg === 'function') {
1051
+ const updater = arg;
1052
+ const currentValue = unwrap(signalState);
1053
+ const newValue = updater(currentValue);
1054
+ recursiveUpdate(signalState, newValue);
1055
+ }
1056
+ else {
1057
+ recursiveUpdate(signalState, arg);
753
1058
  }
754
1059
  };
1060
+ Object.defineProperty(tree, NODE_ACCESSOR_SYMBOL, {
1061
+ value: true,
1062
+ enumerable: false,
1063
+ });
1064
+ Object.defineProperty(tree, 'state', {
1065
+ value: signalState,
1066
+ enumerable: false,
1067
+ });
1068
+ Object.defineProperty(tree, '$', { value: signalState, enumerable: false });
1069
+ enhanceTree(tree, config);
1070
+ for (const key in signalState) {
1071
+ if (Object.prototype.hasOwnProperty.call(signalState, key)) {
1072
+ if (!(key in tree)) {
1073
+ try {
1074
+ Object.defineProperty(tree, key, {
1075
+ value: signalState[key],
1076
+ enumerable: true,
1077
+ configurable: true,
1078
+ });
1079
+ }
1080
+ catch {
1081
+ }
1082
+ }
1083
+ }
1084
+ }
1085
+ return tree;
755
1086
  }
1087
+ const presetConfigs = {
1088
+ basic: {
1089
+ useLazySignals: false,
1090
+ debugMode: false,
1091
+ },
1092
+ performance: {
1093
+ useLazySignals: true,
1094
+ batchUpdates: true,
1095
+ useMemoization: true,
1096
+ useShallowComparison: true,
1097
+ },
1098
+ development: {
1099
+ useLazySignals: false,
1100
+ debugMode: true,
1101
+ enableDevTools: true,
1102
+ trackPerformance: true,
1103
+ },
1104
+ production: {
1105
+ useLazySignals: true,
1106
+ batchUpdates: true,
1107
+ useMemoization: true,
1108
+ debugMode: false,
1109
+ },
1110
+ };
756
1111
  function signalTree(obj, configOrPreset) {
757
1112
  if (typeof configOrPreset === 'string') {
758
- const presetConfigs = {
759
- basic: {
760
- useLazySignals: false,
761
- debugMode: false,
762
- },
763
- performance: {
764
- useLazySignals: true,
765
- batchUpdates: true,
766
- useMemoization: true,
767
- useShallowComparison: true,
768
- },
769
- development: {
770
- useLazySignals: false,
771
- debugMode: true,
772
- enableDevTools: true,
773
- trackPerformance: true,
774
- },
775
- production: {
776
- useLazySignals: true,
777
- batchUpdates: true,
778
- useMemoization: true,
779
- debugMode: false,
780
- },
781
- };
782
1113
  const config = presetConfigs[configOrPreset];
783
1114
  if (!config) {
784
- console.warn(`Unknown preset: ${configOrPreset}, using default configuration`);
1115
+ console.warn(SIGNAL_TREE_MESSAGES.PRESET_UNKNOWN.replace('%s', configOrPreset));
785
1116
  return create(obj, {});
786
1117
  }
787
1118
  return create(obj, config);
@@ -789,6 +1120,9 @@ function signalTree(obj, configOrPreset) {
789
1120
  const config = configOrPreset || {};
790
1121
  return create(obj, config);
791
1122
  }
1123
+ function applyEnhancer(tree, enhancer) {
1124
+ return enhancer(tree);
1125
+ }
792
1126
 
793
- export { createLazySignalTree, deepEqual, equal, parsePath, shallowEqual, signalTree, terminalSignal };
1127
+ export { ENHANCER_META, SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, composeEnhancers, createEnhancer, createLazySignalTree, deepEqual, equal, isAnySignal, isBuiltInObject, isNodeAccessor$1 as isNodeAccessor, parsePath, resolveEnhancerOrder, signalTree, terminalSignal, unwrap };
794
1128
  //# sourceMappingURL=signaltree-core.mjs.map