@signaltree/core 1.1.9 → 2.0.1

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,173 +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
- return false;
328
- }
329
- function createCallableProxy(nestedStore, isBuiltInObjectFn) {
330
- const unwrapFunction = () => {
331
- const unwrapObject = (obj) => {
332
- if (typeof obj !== 'object' || obj === null) {
333
- return obj;
334
- }
335
- if (isSignal(obj)) {
336
- return obj();
337
- }
338
- if (typeof obj === 'function' &&
339
- obj
340
- .__isCallableProxy__ === true) {
341
- return obj();
342
- }
343
- const result = {};
344
- for (const key in obj) {
345
- if (key === 'update' || key === '__isCallableProxy__')
346
- continue;
347
- const value = obj[key];
348
- if (isSignal(value)) {
349
- result[key] = value();
350
- }
351
- else if (typeof value === 'function' &&
352
- value
353
- .__isCallableProxy__ === true) {
354
- result[key] = value();
355
- }
356
- else if (typeof value === 'object' &&
357
- value !== null &&
358
- !Array.isArray(value) &&
359
- !isBuiltInObjectFn(value)) {
360
- result[key] = unwrapObject(value);
361
- }
362
- else {
363
- result[key] = value;
364
- }
365
- }
366
- return result;
367
- };
368
- return unwrapObject(nestedStore);
369
- };
370
- const callableProxy = new Proxy(unwrapFunction, {
371
- apply(target) {
372
- return target();
373
- },
374
- get(target, prop) {
375
- if (prop === Symbol.toPrimitive ||
376
- prop === 'valueOf' ||
377
- prop === 'toString') {
378
- return () => unwrapFunction();
379
- }
380
- if (prop === '__isCallableProxy__') {
381
- return true;
382
- }
383
- if (prop === 'update') {
384
- return (updaterOrPartial) => {
385
- let partialObj;
386
- if (typeof updaterOrPartial === 'function') {
387
- const currentValue = unwrapFunction();
388
- partialObj = updaterOrPartial(currentValue);
389
- }
390
- else {
391
- partialObj = updaterOrPartial;
392
- }
393
- if (!partialObj || typeof partialObj !== 'object') {
394
- throw new Error('Update must return/receive an object');
395
- }
396
- const updateObject = (target, updates) => {
397
- for (const key in updates) {
398
- if (!Object.prototype.hasOwnProperty.call(updates, key))
399
- continue;
400
- const updateValue = updates[key];
401
- const currentSignalOrState = target[key];
402
- if (isSignal(currentSignalOrState)) {
403
- currentSignalOrState.set(updateValue);
404
- }
405
- else if (typeof currentSignalOrState === 'function' &&
406
- currentSignalOrState.__isCallableProxy__ === true &&
407
- updateValue !== null &&
408
- typeof updateValue === 'object' &&
409
- !Array.isArray(updateValue) &&
410
- !isBuiltInObjectFn(updateValue)) {
411
- updateObject(currentSignalOrState, updateValue);
412
- }
413
- }
414
- };
415
- updateObject(nestedStore, partialObj);
416
- };
417
- }
418
- if (prop === 'set') {
419
- return (partialObj) => {
420
- if (!partialObj || typeof partialObj !== 'object') {
421
- throw new Error('Set must be called with an object');
422
- }
423
- const updateObject = (target, updates) => {
424
- for (const key in updates) {
425
- if (!Object.prototype.hasOwnProperty.call(updates, key))
426
- continue;
427
- const updateValue = updates[key];
428
- const currentSignalOrState = target[key];
429
- if (isSignal(currentSignalOrState)) {
430
- currentSignalOrState.set(updateValue);
431
- }
432
- else if (typeof currentSignalOrState === 'function' &&
433
- currentSignalOrState.__isCallableProxy__ === true &&
434
- updateValue !== null &&
435
- typeof updateValue === 'object' &&
436
- !Array.isArray(updateValue) &&
437
- !isBuiltInObjectFn(updateValue)) {
438
- updateObject(currentSignalOrState, updateValue);
439
- }
440
- }
441
- };
442
- updateObject(nestedStore, partialObj);
443
- };
444
- }
445
- return nestedStore[prop];
446
- },
447
- has(target, prop) {
448
- return prop in nestedStore;
449
- },
450
- ownKeys() {
451
- return Reflect.ownKeys(nestedStore);
452
- },
453
- getOwnPropertyDescriptor(target, prop) {
454
- return Reflect.getOwnPropertyDescriptor(nestedStore, prop);
455
- },
456
- });
457
- return callableProxy;
458
- }
459
- function enhanceNestedObject(nestedStore, isBuiltInObjectFn) {
460
- return createCallableProxy(nestedStore, isBuiltInObjectFn);
461
- }
462
694
  function createSignalStore(obj, equalityFn) {
463
695
  if (obj === null || obj === undefined || typeof obj !== 'object') {
464
696
  return signal(obj, { equal: equalityFn });
@@ -472,7 +704,7 @@ function createSignalStore(obj, equalityFn) {
472
704
  const store = {};
473
705
  const processedObjects = new WeakSet();
474
706
  if (processedObjects.has(obj)) {
475
- console.warn('[SignalTree] Circular reference detected, creating reference signal');
707
+ console.warn(SIGNAL_TREE_MESSAGES.CIRCULAR_REF);
476
708
  return signal(obj, { equal: equalityFn });
477
709
  }
478
710
  processedObjects.add(obj);
@@ -501,12 +733,26 @@ function createSignalStore(obj, equalityFn) {
501
733
  });
502
734
  }
503
735
  else {
504
- const nestedStore = createSignalStore(value, equalityFn);
505
- store[key] = nestedStore;
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;
506
752
  }
507
753
  }
508
754
  catch (error) {
509
- console.warn(`[SignalTree] Failed to create signal for key "${key}":`, error);
755
+ console.warn(`${SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED} "${key}":`, error);
510
756
  store[key] = signal(value, {
511
757
  equal: equalityFn,
512
758
  });
@@ -526,68 +772,92 @@ function createSignalStore(obj, equalityFn) {
526
772
  }
527
773
  }
528
774
  catch (error) {
529
- console.warn(`[SignalTree] Failed to create signal for symbol key:`, error);
775
+ console.warn(SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED, error);
530
776
  }
531
777
  }
532
778
  }
533
779
  catch (error) {
534
780
  throw new Error(`Failed to create signal store: ${error instanceof Error ? error.message : 'Unknown error'}`);
535
781
  }
536
- return enhanceNestedObject(store, isBuiltInObject);
537
- }
538
- function create(obj, config = {}) {
539
- if (obj === null || obj === undefined) {
540
- throw new Error('Cannot create SignalTree from null or undefined');
541
- }
542
- const equalityFn = createEqualityFn(config.useShallowComparison ?? false);
543
- const useLazy = shouldUseLazy(obj, config);
544
- if (config.debugMode) {
545
- const estimatedSize = estimateObjectSize(obj);
546
- console.log(`[SignalTree] Creating tree with ${useLazy ? 'lazy' : 'eager'} strategy (estimated size: ${estimatedSize})`);
547
- }
548
- let signalState;
549
- try {
550
- if (useLazy && typeof obj === 'object') {
551
- signalState = createLazySignalTree(obj, equalityFn);
552
- }
553
- else {
554
- signalState = createSignalStore(obj, equalityFn);
555
- }
556
- }
557
- catch (error) {
558
- if (useLazy) {
559
- console.warn('[SignalTree] Lazy creation failed, falling back to eager:', error);
560
- signalState = createSignalStore(obj, equalityFn);
561
- }
562
- else {
563
- throw error;
564
- }
565
- }
566
- const resultTree = {
567
- state: signalState,
568
- $: signalState,
569
- };
570
- enhanceTree(resultTree, config);
571
- return resultTree;
782
+ return store;
572
783
  }
573
784
  function enhanceTree(tree, config = {}) {
574
785
  const isLazy = config.useLazySignals ?? shouldUseLazy(tree.state, config);
575
- tree.pipe = ((...fns) => {
576
- if (fns.length === 0) {
786
+ tree.with = ((...enhancers) => {
787
+ if (enhancers.length === 0) {
577
788
  return tree;
578
789
  }
579
- return fns.reduce((acc, fn) => {
580
- if (typeof fn !== 'function') {
581
- throw new Error('All pipe arguments must be functions');
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);
810
+ }
811
+ catch (err) {
812
+ console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_ORDER_FAILED, err);
813
+ }
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)));
821
+ }
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);
829
+ }
830
+ else {
831
+ console.warn(msg);
832
+ }
833
+ }
582
834
  }
583
835
  try {
584
- return fn(acc);
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));
846
+ }
847
+ }
848
+ }
585
849
  }
586
850
  catch (error) {
587
- 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
+ }
588
857
  throw error;
589
858
  }
590
- }, tree);
859
+ }
860
+ return currentTree;
591
861
  });
592
862
  tree.destroy = () => {
593
863
  try {
@@ -601,29 +871,36 @@ function enhanceTree(tree, config = {}) {
601
871
  }
602
872
  }
603
873
  if (config.debugMode) {
604
- console.log('[SignalTree] Tree destroyed');
874
+ console.log(SIGNAL_TREE_MESSAGES.TREE_DESTROYED);
605
875
  }
606
876
  }
607
877
  catch (error) {
608
- console.error('[SignalTree] Error during cleanup:', error);
878
+ console.error(SIGNAL_TREE_MESSAGES.CLEANUP_ERROR, error);
609
879
  }
610
880
  };
611
881
  addStubMethods(tree, config);
612
882
  return tree;
613
883
  }
614
884
  function addStubMethods(tree, config) {
885
+ tree.batchUpdate = (updater) => {
886
+ console.warn(SIGNAL_TREE_MESSAGES.BATCH_NOT_ENABLED);
887
+ tree((current) => {
888
+ const partial = updater(current);
889
+ return { ...current, ...partial };
890
+ });
891
+ };
615
892
  tree.memoize = (fn, cacheKey) => {
616
- 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);
617
894
  void cacheKey;
618
- return computed(() => fn(tree.$()));
895
+ return computed(() => fn(tree()));
619
896
  };
620
897
  tree.effect = (fn) => {
621
898
  try {
622
- effect(() => fn(tree.$()));
899
+ effect(() => fn(tree()));
623
900
  }
624
901
  catch (error) {
625
902
  if (config.debugMode) {
626
- console.warn('Effect requires Angular injection context', error);
903
+ console.warn(SIGNAL_TREE_MESSAGES.EFFECT_NO_CONTEXT, error);
627
904
  }
628
905
  }
629
906
  };
@@ -633,7 +910,7 @@ function addStubMethods(tree, config) {
633
910
  let isDestroyed = false;
634
911
  const effectRef = effect(() => {
635
912
  if (!isDestroyed) {
636
- fn(tree.$());
913
+ fn(tree());
637
914
  }
638
915
  }, ...(ngDevMode ? [{ debugName: "effectRef" }] : []));
639
916
  const unsubscribe = () => {
@@ -645,26 +922,26 @@ function addStubMethods(tree, config) {
645
922
  }
646
923
  catch (error) {
647
924
  if (config.debugMode) {
648
- console.warn('Subscribe requires Angular injection context', error);
925
+ console.warn(SIGNAL_TREE_MESSAGES.SUBSCRIBE_NO_CONTEXT, error);
649
926
  }
650
- fn(tree.$());
927
+ fn(tree());
651
928
  return () => {
652
929
  };
653
930
  }
654
931
  };
655
932
  tree.optimize = () => {
656
933
  if (config.debugMode) {
657
- console.warn('⚠️ optimize() called but tree optimization is not available.');
934
+ console.warn(SIGNAL_TREE_MESSAGES.OPTIMIZE_NOT_AVAILABLE);
658
935
  }
659
936
  };
660
937
  tree.clearCache = () => {
661
938
  if (config.debugMode) {
662
- console.warn('⚠️ clearCache() called but caching is not available.');
939
+ console.warn(SIGNAL_TREE_MESSAGES.CACHE_NOT_AVAILABLE);
663
940
  }
664
941
  };
665
942
  tree.invalidatePattern = () => {
666
943
  if (config.debugMode) {
667
- console.warn('⚠️ invalidatePattern() called but performance optimization is not enabled.');
944
+ console.warn(SIGNAL_TREE_MESSAGES.PERFORMANCE_NOT_ENABLED);
668
945
  }
669
946
  return 0;
670
947
  };
@@ -679,25 +956,25 @@ function addStubMethods(tree, config) {
679
956
  };
680
957
  tree.addTap = (middleware) => {
681
958
  if (config.debugMode) {
682
- console.warn('⚠️ addTap() called but middleware support is not available.');
959
+ console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
683
960
  }
684
961
  void middleware;
685
962
  };
686
963
  tree.removeTap = (id) => {
687
964
  if (config.debugMode) {
688
- console.warn('⚠️ removeTap() called but middleware support is not available.');
965
+ console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
689
966
  }
690
967
  void id;
691
968
  };
692
969
  tree.asCrud = () => {
693
970
  if (config.debugMode) {
694
- console.warn('⚠️ asCrud() called but entity helpers are not available.');
971
+ console.warn(SIGNAL_TREE_MESSAGES.ENTITY_HELPERS_NOT_AVAILABLE);
695
972
  }
696
973
  return {};
697
974
  };
698
975
  tree.asyncAction = (operation, asyncConfig = {}) => {
699
976
  if (config.debugMode) {
700
- console.warn('⚠️ asyncAction() called but async actions are not available.');
977
+ console.warn(SIGNAL_TREE_MESSAGES.ASYNC_ACTIONS_NOT_AVAILABLE);
701
978
  }
702
979
  void operation;
703
980
  void asyncConfig;
@@ -705,55 +982,137 @@ function addStubMethods(tree, config) {
705
982
  };
706
983
  tree.undo = () => {
707
984
  if (config.debugMode) {
708
- console.warn('⚠️ undo() called but time travel is not available.');
985
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
709
986
  }
710
987
  };
711
988
  tree.redo = () => {
712
989
  if (config.debugMode) {
713
- console.warn('⚠️ redo() called but time travel is not available.');
990
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
714
991
  }
715
992
  };
716
993
  tree.getHistory = () => {
717
994
  if (config.debugMode) {
718
- console.warn('⚠️ getHistory() called but time travel is not available.');
995
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
719
996
  }
720
997
  return [];
721
998
  };
722
999
  tree.resetHistory = () => {
723
1000
  if (config.debugMode) {
724
- console.warn('⚠️ resetHistory() called but time travel is not available.');
1001
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
725
1002
  }
726
1003
  };
727
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);
1058
+ }
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;
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
+ };
728
1111
  function signalTree(obj, configOrPreset) {
729
1112
  if (typeof configOrPreset === 'string') {
730
- const presetConfigs = {
731
- basic: {
732
- useLazySignals: false,
733
- debugMode: false,
734
- },
735
- performance: {
736
- useLazySignals: true,
737
- batchUpdates: true,
738
- useMemoization: true,
739
- useShallowComparison: true,
740
- },
741
- development: {
742
- useLazySignals: false,
743
- debugMode: true,
744
- enableDevTools: true,
745
- trackPerformance: true,
746
- },
747
- production: {
748
- useLazySignals: true,
749
- batchUpdates: true,
750
- useMemoization: true,
751
- debugMode: false,
752
- },
753
- };
754
1113
  const config = presetConfigs[configOrPreset];
755
1114
  if (!config) {
756
- console.warn(`Unknown preset: ${configOrPreset}, using default configuration`);
1115
+ console.warn(SIGNAL_TREE_MESSAGES.PRESET_UNKNOWN.replace('%s', configOrPreset));
757
1116
  return create(obj, {});
758
1117
  }
759
1118
  return create(obj, config);
@@ -761,6 +1120,9 @@ function signalTree(obj, configOrPreset) {
761
1120
  const config = configOrPreset || {};
762
1121
  return create(obj, config);
763
1122
  }
1123
+ function applyEnhancer(tree, enhancer) {
1124
+ return enhancer(tree);
1125
+ }
764
1126
 
765
- 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 };
766
1128
  //# sourceMappingURL=signaltree-core.mjs.map