@blac/core 2.0.0-rc.0 → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1361 -38
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +868 -0
- package/dist/index.d.ts +867 -16
- package/dist/index.js +1315 -37
- package/dist/index.js.map +1 -1
- package/package.json +19 -11
- package/dist/.tsbuildinfo +0 -1
- package/dist/Blac.d.ts +0 -246
- package/dist/Blac.d.ts.map +0 -1
- package/dist/Blac.js +0 -625
- package/dist/Blac.js.map +0 -1
- package/dist/Bloc.d.ts +0 -41
- package/dist/Bloc.d.ts.map +0 -1
- package/dist/Bloc.js +0 -140
- package/dist/Bloc.js.map +0 -1
- package/dist/BlocBase.d.ts +0 -110
- package/dist/BlocBase.d.ts.map +0 -1
- package/dist/BlocBase.js +0 -287
- package/dist/BlocBase.js.map +0 -1
- package/dist/Cubit.d.ts +0 -25
- package/dist/Cubit.d.ts.map +0 -1
- package/dist/Cubit.js +0 -64
- package/dist/Cubit.js.map +0 -1
- package/dist/adapter/BlacAdapter.d.ts +0 -71
- package/dist/adapter/BlacAdapter.d.ts.map +0 -1
- package/dist/adapter/BlacAdapter.js +0 -373
- package/dist/adapter/BlacAdapter.js.map +0 -1
- package/dist/adapter/ProxyFactory.d.ts +0 -50
- package/dist/adapter/ProxyFactory.d.ts.map +0 -1
- package/dist/adapter/ProxyFactory.js +0 -150
- package/dist/adapter/ProxyFactory.js.map +0 -1
- package/dist/adapter/index.d.ts +0 -3
- package/dist/adapter/index.d.ts.map +0 -1
- package/dist/adapter/index.js +0 -19
- package/dist/adapter/index.js.map +0 -1
- package/dist/errors/BlacError.d.ts +0 -38
- package/dist/errors/BlacError.d.ts.map +0 -1
- package/dist/errors/BlacError.js +0 -55
- package/dist/errors/BlacError.js.map +0 -1
- package/dist/errors/ErrorManager.d.ts +0 -39
- package/dist/errors/ErrorManager.d.ts.map +0 -1
- package/dist/errors/ErrorManager.js +0 -91
- package/dist/errors/ErrorManager.js.map +0 -1
- package/dist/errors/handleError.d.ts +0 -24
- package/dist/errors/handleError.d.ts.map +0 -1
- package/dist/errors/handleError.js +0 -62
- package/dist/errors/handleError.js.map +0 -1
- package/dist/errors/index.d.ts +0 -5
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js +0 -13
- package/dist/errors/index.js.map +0 -1
- package/dist/events.d.ts +0 -11
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js +0 -17
- package/dist/events.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lifecycle/BlocLifecycle.d.ts +0 -51
- package/dist/lifecycle/BlocLifecycle.d.ts.map +0 -1
- package/dist/lifecycle/BlocLifecycle.js +0 -123
- package/dist/lifecycle/BlocLifecycle.js.map +0 -1
- package/dist/lifecycle/index.d.ts +0 -2
- package/dist/lifecycle/index.d.ts.map +0 -1
- package/dist/lifecycle/index.js +0 -18
- package/dist/lifecycle/index.js.map +0 -1
- package/dist/plugins/BlocPluginRegistry.d.ts +0 -58
- package/dist/plugins/BlocPluginRegistry.d.ts.map +0 -1
- package/dist/plugins/BlocPluginRegistry.js +0 -201
- package/dist/plugins/BlocPluginRegistry.js.map +0 -1
- package/dist/plugins/SystemPluginRegistry.d.ts +0 -79
- package/dist/plugins/SystemPluginRegistry.d.ts.map +0 -1
- package/dist/plugins/SystemPluginRegistry.js +0 -184
- package/dist/plugins/SystemPluginRegistry.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -4
- package/dist/plugins/index.d.ts.map +0 -1
- package/dist/plugins/index.js +0 -26
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/types.d.ts +0 -103
- package/dist/plugins/types.d.ts.map +0 -1
- package/dist/plugins/types.js +0 -3
- package/dist/plugins/types.js.map +0 -1
- package/dist/subscription/SubscriptionManager.d.ts +0 -67
- package/dist/subscription/SubscriptionManager.d.ts.map +0 -1
- package/dist/subscription/SubscriptionManager.js +0 -317
- package/dist/subscription/SubscriptionManager.js.map +0 -1
- package/dist/subscription/index.d.ts +0 -3
- package/dist/subscription/index.d.ts.map +0 -1
- package/dist/subscription/index.js +0 -19
- package/dist/subscription/index.js.map +0 -1
- package/dist/subscription/types.d.ts +0 -65
- package/dist/subscription/types.d.ts.map +0 -1
- package/dist/subscription/types.js +0 -3
- package/dist/subscription/types.js.map +0 -1
- package/dist/testing.d.ts +0 -85
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js +0 -186
- package/dist/testing.js.map +0 -1
- package/dist/types.d.ts +0 -57
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/utils/BatchingManager.d.ts +0 -28
- package/dist/utils/BatchingManager.d.ts.map +0 -1
- package/dist/utils/BatchingManager.js +0 -48
- package/dist/utils/BatchingManager.js.map +0 -1
- package/dist/utils/RerenderLogger.d.ts +0 -60
- package/dist/utils/RerenderLogger.d.ts.map +0 -1
- package/dist/utils/RerenderLogger.js +0 -205
- package/dist/utils/RerenderLogger.js.map +0 -1
- package/dist/utils/generateInstanceId.d.ts +0 -11
- package/dist/utils/generateInstanceId.d.ts.map +0 -1
- package/dist/utils/generateInstanceId.js +0 -50
- package/dist/utils/generateInstanceId.js.map +0 -1
- package/dist/utils/shallowEqual.d.ts +0 -9
- package/dist/utils/shallowEqual.d.ts.map +0 -1
- package/dist/utils/shallowEqual.js +0 -35
- package/dist/utils/shallowEqual.js.map +0 -1
- package/dist/utils/uuid.d.ts +0 -10
- package/dist/utils/uuid.d.ts.map +0 -1
- package/dist/utils/uuid.js +0 -24
- package/dist/utils/uuid.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,38 +1,1361 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
|
|
2
|
+
//#region src/utils/idGenerator.ts
|
|
3
|
+
/**
|
|
4
|
+
* Centralized ID Generation
|
|
5
|
+
*
|
|
6
|
+
* Provides consistent, collision-resistant ID generation for all BlaC subsystems.
|
|
7
|
+
* Uses timestamp + counter + random suffix for uniqueness.
|
|
8
|
+
*/
|
|
9
|
+
const globalCounters = /* @__PURE__ */ new Map();
|
|
10
|
+
/**
|
|
11
|
+
* Creates an ID generator with isolated counter state
|
|
12
|
+
*
|
|
13
|
+
* @param prefix - Prefix for generated IDs
|
|
14
|
+
* @returns Object with next(), nextSimple(), and reset() methods
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const generator = createIdGenerator('sub');
|
|
19
|
+
* const id1 = generator.next(); // "sub_1698765432100_1_a3k9d7f2q"
|
|
20
|
+
* const id2 = generator.next(); // "sub_1698765432101_2_b4n8e9g3r"
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
function createIdGenerator(prefix) {
|
|
24
|
+
let counter = 0;
|
|
25
|
+
return {
|
|
26
|
+
next: () => `${prefix}_${Date.now()}_${++counter}_${Math.random().toString(36).substring(2, 11)}`,
|
|
27
|
+
nextSimple: () => `${prefix}_${++counter}`,
|
|
28
|
+
reset: () => {
|
|
29
|
+
counter = 0;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate ID with timestamp, counter, and random suffix (tree-shakeable)
|
|
35
|
+
*
|
|
36
|
+
* Format: `${prefix}_${timestamp}_${counter}_${random}`
|
|
37
|
+
*
|
|
38
|
+
* @param prefix - Prefix for the ID (e.g., 'sub', 'consumer', 'stage')
|
|
39
|
+
* @returns Branded ID string
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const id = generateId('sub');
|
|
44
|
+
* // Returns: "sub_1698765432100_1_a3k9d7f2q"
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function generateId(prefix) {
|
|
48
|
+
const counter = (globalCounters.get(prefix) ?? 0) + 1;
|
|
49
|
+
globalCounters.set(prefix, counter);
|
|
50
|
+
return `${prefix}_${Date.now()}_${counter}_${Math.random().toString(36).substring(2, 11)}`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Generate simple ID with timestamp and random (no counter tracking)
|
|
54
|
+
*
|
|
55
|
+
* Format: `${prefix}_${timestamp}_${random}`
|
|
56
|
+
*
|
|
57
|
+
* @param prefix - Prefix for the ID
|
|
58
|
+
* @returns Branded ID string
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* const id = generateSimpleId('CounterBloc');
|
|
63
|
+
* // Returns: "CounterBloc_1698765432100_a3k9d7f2q"
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
function generateSimpleId(prefix) {
|
|
67
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Reset all counters for testing purposes
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
function __resetIdCounters() {
|
|
74
|
+
globalCounters.clear();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/core/StateContainerRegistry.ts
|
|
79
|
+
/**
|
|
80
|
+
* Registry for managing StateContainer instances
|
|
81
|
+
*/
|
|
82
|
+
var StateContainerRegistry = class {
|
|
83
|
+
instances = /* @__PURE__ */ new Map();
|
|
84
|
+
types = /* @__PURE__ */ new Map();
|
|
85
|
+
/**
|
|
86
|
+
* Register a type with isolation mode
|
|
87
|
+
*/
|
|
88
|
+
register(constructor, isolated = false) {
|
|
89
|
+
const className = constructor.name;
|
|
90
|
+
if (!isolated && constructor.isolated === true) isolated = true;
|
|
91
|
+
if (this.types.has(className)) throw new Error(`Type "${className}" is already registered`);
|
|
92
|
+
this.types.set(className, { isolated });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get or create a StateContainer instance
|
|
96
|
+
* For isolated: always creates new
|
|
97
|
+
* For shared: singleton per key
|
|
98
|
+
*/
|
|
99
|
+
getOrCreate(constructor, key, ...args) {
|
|
100
|
+
const className = constructor.name;
|
|
101
|
+
let config = this.types.get(className);
|
|
102
|
+
if (!config) {
|
|
103
|
+
const isolated = constructor.isolated === true;
|
|
104
|
+
this.types.set(className, { isolated });
|
|
105
|
+
config = this.types.get(className);
|
|
106
|
+
}
|
|
107
|
+
if (config.isolated) return new constructor(...args);
|
|
108
|
+
const instanceKey = `${className}:${key || "default"}`;
|
|
109
|
+
const existing = this.instances.get(instanceKey);
|
|
110
|
+
if (existing) {
|
|
111
|
+
existing.refCount++;
|
|
112
|
+
return existing.instance;
|
|
113
|
+
}
|
|
114
|
+
const instance = new constructor(...args);
|
|
115
|
+
this.instances.set(instanceKey, {
|
|
116
|
+
instance,
|
|
117
|
+
refCount: 1
|
|
118
|
+
});
|
|
119
|
+
return instance;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Release a reference to an instance
|
|
123
|
+
* Disposes when ref count reaches zero (unless keepAlive)
|
|
124
|
+
*/
|
|
125
|
+
release(constructor, key, forceDispose = false) {
|
|
126
|
+
const instanceKey = `${constructor.name}:${key || "default"}`;
|
|
127
|
+
const entry = this.instances.get(instanceKey);
|
|
128
|
+
if (!entry) return;
|
|
129
|
+
if (forceDispose) {
|
|
130
|
+
entry.instance.dispose();
|
|
131
|
+
this.instances.delete(instanceKey);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
entry.refCount--;
|
|
135
|
+
if (entry.refCount <= 0 && !entry.instance.keepAlive) {
|
|
136
|
+
entry.instance.dispose();
|
|
137
|
+
this.instances.delete(instanceKey);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get all instances of a type (shared only, isolated aren't tracked)
|
|
142
|
+
*/
|
|
143
|
+
getAll(constructor) {
|
|
144
|
+
const prefix = `${constructor.name}:`;
|
|
145
|
+
const results = [];
|
|
146
|
+
for (const [key, entry] of this.instances) if (key.startsWith(prefix)) results.push(entry.instance);
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Clear all instances of a type
|
|
151
|
+
*/
|
|
152
|
+
clear(constructor) {
|
|
153
|
+
const prefix = `${constructor.name}:`;
|
|
154
|
+
const toDelete = [];
|
|
155
|
+
for (const [key, entry] of this.instances) if (key.startsWith(prefix)) {
|
|
156
|
+
if (!entry.instance.isDisposed) entry.instance.dispose();
|
|
157
|
+
toDelete.push(key);
|
|
158
|
+
}
|
|
159
|
+
for (const key of toDelete) this.instances.delete(key);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Clear all instances from all types (for testing)
|
|
163
|
+
*/
|
|
164
|
+
clearAll() {
|
|
165
|
+
for (const entry of this.instances.values()) if (!entry.instance.isDisposed) entry.instance.dispose();
|
|
166
|
+
this.instances.clear();
|
|
167
|
+
this.types.clear();
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get registry statistics (for debugging)
|
|
171
|
+
*/
|
|
172
|
+
getStats() {
|
|
173
|
+
const typeBreakdown = {};
|
|
174
|
+
for (const key of this.instances.keys()) {
|
|
175
|
+
const typeName = key.split(":")[0];
|
|
176
|
+
typeBreakdown[typeName] = (typeBreakdown[typeName] || 0) + 1;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
registeredTypes: this.types.size,
|
|
180
|
+
totalInstances: this.instances.size,
|
|
181
|
+
typeBreakdown
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get reference count for an instance
|
|
186
|
+
*/
|
|
187
|
+
getRefCount(constructor, key) {
|
|
188
|
+
const instanceKey = `${constructor.name}:${key || "default"}`;
|
|
189
|
+
return this.instances.get(instanceKey)?.refCount ?? 0;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Check if an instance exists
|
|
193
|
+
*/
|
|
194
|
+
hasInstance(constructor, key) {
|
|
195
|
+
const instanceKey = `${constructor.name}:${key || "default"}`;
|
|
196
|
+
return this.instances.has(instanceKey);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* Global default registry instance
|
|
201
|
+
*/
|
|
202
|
+
const globalRegistry = new StateContainerRegistry();
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/core/StateContainer.ts
|
|
206
|
+
/**
|
|
207
|
+
* Base abstract class for all state containers
|
|
208
|
+
*/
|
|
209
|
+
var StateContainer = class StateContainer {
|
|
210
|
+
static _registry = globalRegistry;
|
|
211
|
+
/**
|
|
212
|
+
* Set a custom registry (mainly for testing)
|
|
213
|
+
*/
|
|
214
|
+
static setRegistry(registry) {
|
|
215
|
+
StateContainer._registry = registry;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Register a type as isolated or shared
|
|
219
|
+
*/
|
|
220
|
+
static register(isolated = false) {
|
|
221
|
+
StateContainer._registry.register(this, isolated);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get or create an instance
|
|
225
|
+
* @param key - Optional instance key for shared instances
|
|
226
|
+
* @param args - Constructor arguments
|
|
227
|
+
*/
|
|
228
|
+
static getOrCreate(key, ...args) {
|
|
229
|
+
return StateContainer._registry.getOrCreate(this, key, ...args);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Release a reference to an instance
|
|
233
|
+
* @param key - Optional instance key
|
|
234
|
+
* @param forceDispose - Force dispose regardless of ref count or keepAlive
|
|
235
|
+
*/
|
|
236
|
+
static release(key, forceDispose = false) {
|
|
237
|
+
StateContainer._registry.release(this, key, forceDispose);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get all instances of this type
|
|
241
|
+
*/
|
|
242
|
+
static getAll() {
|
|
243
|
+
return StateContainer._registry.getAll(this);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Clear all instances of this type
|
|
247
|
+
*/
|
|
248
|
+
static clear() {
|
|
249
|
+
StateContainer._registry.clear(this);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Clear all instances from all types (for testing)
|
|
253
|
+
*/
|
|
254
|
+
static clearAllInstances() {
|
|
255
|
+
StateContainer._registry.clearAll();
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Get registry statistics (for debugging)
|
|
259
|
+
*/
|
|
260
|
+
static getStats() {
|
|
261
|
+
return StateContainer._registry.getStats();
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Get reference count for an instance
|
|
265
|
+
* @param key - Optional instance key
|
|
266
|
+
*/
|
|
267
|
+
static getRefCount(key) {
|
|
268
|
+
return StateContainer._registry.getRefCount(this, key);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Check if an instance exists
|
|
272
|
+
* @param key - Optional instance key
|
|
273
|
+
*/
|
|
274
|
+
static hasInstance(key) {
|
|
275
|
+
return StateContainer._registry.hasInstance(this, key);
|
|
276
|
+
}
|
|
277
|
+
_state;
|
|
278
|
+
listeners = /* @__PURE__ */ new Set();
|
|
279
|
+
_disposed = false;
|
|
280
|
+
config;
|
|
281
|
+
name;
|
|
282
|
+
keepAlive;
|
|
283
|
+
debug;
|
|
284
|
+
instanceId;
|
|
285
|
+
/**
|
|
286
|
+
* Create a new StateContainer
|
|
287
|
+
*/
|
|
288
|
+
constructor(initialState, config = {}) {
|
|
289
|
+
this._state = initialState;
|
|
290
|
+
this.config = config;
|
|
291
|
+
this.name = config.name || this.constructor.name;
|
|
292
|
+
this.keepAlive = config.keepAlive ?? false;
|
|
293
|
+
this.debug = config.debug ?? false;
|
|
294
|
+
this.instanceId = config.instanceId || generateSimpleId(this.constructor.name);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get the current state
|
|
298
|
+
*/
|
|
299
|
+
get state() {
|
|
300
|
+
return this._state;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Check if disposed
|
|
304
|
+
*/
|
|
305
|
+
get isDisposed() {
|
|
306
|
+
return this._disposed;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Subscribe to state changes
|
|
310
|
+
* @returns Unsubscribe function
|
|
311
|
+
*/
|
|
312
|
+
subscribe(listener) {
|
|
313
|
+
if (this._disposed) throw new Error(`Cannot subscribe to disposed container ${this.name}`);
|
|
314
|
+
this.listeners.add(listener);
|
|
315
|
+
return () => this.listeners.delete(listener);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Dispose the container
|
|
319
|
+
*/
|
|
320
|
+
dispose() {
|
|
321
|
+
if (this._disposed) return;
|
|
322
|
+
if (this.debug) console.log(`[${this.name}] Disposing...`);
|
|
323
|
+
this._disposed = true;
|
|
324
|
+
this.onDispose?.();
|
|
325
|
+
this.listeners.clear();
|
|
326
|
+
if (this.debug) console.log(`[${this.name}] Disposed successfully`);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Emit a new state (with change detection)
|
|
330
|
+
*/
|
|
331
|
+
emit(newState) {
|
|
332
|
+
if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this.name}`);
|
|
333
|
+
if (this._state === newState) return;
|
|
334
|
+
const previousState = this._state;
|
|
335
|
+
this._state = newState;
|
|
336
|
+
this.onStateChange?.(newState, previousState);
|
|
337
|
+
for (const listener of this.listeners) try {
|
|
338
|
+
listener(newState);
|
|
339
|
+
} catch (error$1) {
|
|
340
|
+
console.error(`[${this.name}] Error in listener:`, error$1);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Update state using a function
|
|
345
|
+
*/
|
|
346
|
+
update(updater) {
|
|
347
|
+
if (this._disposed) throw new Error(`Cannot update state from disposed container ${this.name}`);
|
|
348
|
+
this.emit(updater(this._state));
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region src/core/Cubit.ts
|
|
354
|
+
/**
|
|
355
|
+
* Cubit is a simple state container that allows direct state emission
|
|
356
|
+
*
|
|
357
|
+
* Unlike StateContainer (where emit is protected), Cubit exposes emit and update
|
|
358
|
+
* as public methods to allow direct state management.
|
|
359
|
+
*/
|
|
360
|
+
var Cubit = class extends StateContainer {
|
|
361
|
+
/**
|
|
362
|
+
* Create a new Cubit
|
|
363
|
+
* @param initialState Initial state value
|
|
364
|
+
* @param config Configuration options
|
|
365
|
+
*/
|
|
366
|
+
constructor(initialState, config) {
|
|
367
|
+
super(initialState, config);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Emit a new state (public override of protected parent method)
|
|
371
|
+
*/
|
|
372
|
+
emit(newState) {
|
|
373
|
+
super["emit"](newState);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Update state using a function (public override of protected parent method)
|
|
377
|
+
*/
|
|
378
|
+
update(updater) {
|
|
379
|
+
super["update"](updater);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Patch state with partial updates (shallow merge)
|
|
383
|
+
* Only available when state is an object type
|
|
384
|
+
* Arrow function to maintain correct 'this' binding in React
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```typescript
|
|
388
|
+
* // Update single field
|
|
389
|
+
* this.patch({ count: 5 });
|
|
390
|
+
*
|
|
391
|
+
* // Update multiple fields
|
|
392
|
+
* this.patch({ count: 5, name: 'Updated' });
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
patch = ((partial) => {
|
|
396
|
+
if (typeof this.state !== "object" || this.state === null) throw new Error("patch() is only available for object state types");
|
|
397
|
+
this.update((current) => ({
|
|
398
|
+
...current,
|
|
399
|
+
...partial
|
|
400
|
+
}));
|
|
401
|
+
});
|
|
402
|
+
};
|
|
403
|
+
/**
|
|
404
|
+
* Example: Counter Cubit
|
|
405
|
+
*/
|
|
406
|
+
var CounterCubit = class extends Cubit {
|
|
407
|
+
constructor() {
|
|
408
|
+
super(0, { name: "CounterCubit" });
|
|
409
|
+
}
|
|
410
|
+
increment = () => {
|
|
411
|
+
this.emit(this.state + 1);
|
|
412
|
+
};
|
|
413
|
+
decrement = () => {
|
|
414
|
+
this.emit(this.state - 1);
|
|
415
|
+
};
|
|
416
|
+
reset = () => {
|
|
417
|
+
this.emit(0);
|
|
418
|
+
};
|
|
419
|
+
addAmount = (amount) => {
|
|
420
|
+
this.emit(this.state + amount);
|
|
421
|
+
};
|
|
422
|
+
};
|
|
423
|
+
var TodoCubit = class extends Cubit {
|
|
424
|
+
nextId = 0;
|
|
425
|
+
constructor() {
|
|
426
|
+
super({
|
|
427
|
+
todos: [],
|
|
428
|
+
filter: "all",
|
|
429
|
+
isLoading: false
|
|
430
|
+
}, {
|
|
431
|
+
name: "TodoCubit",
|
|
432
|
+
keepAlive: true
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
addTodo = (text) => {
|
|
436
|
+
this.update((state) => ({
|
|
437
|
+
...state,
|
|
438
|
+
todos: [...state.todos, {
|
|
439
|
+
id: `todo-${Date.now()}-${this.nextId++}`,
|
|
440
|
+
text,
|
|
441
|
+
done: false
|
|
442
|
+
}]
|
|
443
|
+
}));
|
|
444
|
+
};
|
|
445
|
+
toggleTodo = (id) => {
|
|
446
|
+
this.update((state) => ({
|
|
447
|
+
...state,
|
|
448
|
+
todos: state.todos.map((todo) => todo.id === id ? {
|
|
449
|
+
...todo,
|
|
450
|
+
done: !todo.done
|
|
451
|
+
} : todo)
|
|
452
|
+
}));
|
|
453
|
+
};
|
|
454
|
+
removeTodo = (id) => {
|
|
455
|
+
this.update((state) => ({
|
|
456
|
+
...state,
|
|
457
|
+
todos: state.todos.filter((todo) => todo.id !== id)
|
|
458
|
+
}));
|
|
459
|
+
};
|
|
460
|
+
setFilter = (filter) => {
|
|
461
|
+
this.patch({ filter });
|
|
462
|
+
};
|
|
463
|
+
setLoading = (isLoading) => {
|
|
464
|
+
this.patch({ isLoading });
|
|
465
|
+
};
|
|
466
|
+
get visibleTodos() {
|
|
467
|
+
const todos = this.state.todos;
|
|
468
|
+
switch (this.state.filter) {
|
|
469
|
+
case "active": return todos.filter((t) => !t.done);
|
|
470
|
+
case "completed": return todos.filter((t) => t.done);
|
|
471
|
+
case "all":
|
|
472
|
+
default: return todos;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
get activeTodoCount() {
|
|
476
|
+
return this.state.todos.filter((t) => !t.done).length;
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
//#endregion
|
|
481
|
+
//#region src/core/Vertex.ts
|
|
482
|
+
/**
|
|
483
|
+
* Vertex is an event-driven state container (Bloc pattern)
|
|
484
|
+
*
|
|
485
|
+
* Includes its own simple event system since events are only needed
|
|
486
|
+
* for the Vertex pattern, not for the base StateContainer.
|
|
487
|
+
*/
|
|
488
|
+
var Vertex = class extends StateContainer {
|
|
489
|
+
eventHandlers = /* @__PURE__ */ new Map();
|
|
490
|
+
isProcessing = false;
|
|
491
|
+
eventQueue = [];
|
|
492
|
+
/**
|
|
493
|
+
* Create a new Vertex
|
|
494
|
+
* @param initialState Initial state value
|
|
495
|
+
* @param config Configuration options
|
|
496
|
+
*/
|
|
497
|
+
constructor(initialState, config) {
|
|
498
|
+
super(initialState, config);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Register an event handler
|
|
502
|
+
* Arrow function to maintain correct 'this' binding
|
|
503
|
+
*/
|
|
504
|
+
on = (EventClass, handler) => {
|
|
505
|
+
const className = EventClass.name;
|
|
506
|
+
const registrations = this.eventHandlers.get(className) || [];
|
|
507
|
+
registrations.push({
|
|
508
|
+
eventClass: EventClass,
|
|
509
|
+
handler
|
|
510
|
+
});
|
|
511
|
+
this.eventHandlers.set(className, registrations);
|
|
512
|
+
};
|
|
513
|
+
/**
|
|
514
|
+
* Add an event to be processed
|
|
515
|
+
* Arrow function to maintain correct 'this' binding in React
|
|
516
|
+
*/
|
|
517
|
+
add = (event) => {
|
|
518
|
+
this.processEvent(event);
|
|
519
|
+
};
|
|
520
|
+
/**
|
|
521
|
+
* Process an event (synchronously)
|
|
522
|
+
*/
|
|
523
|
+
processEvent(event) {
|
|
524
|
+
if (this.isProcessing) {
|
|
525
|
+
this.eventQueue.push(event);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
this.isProcessing = true;
|
|
529
|
+
try {
|
|
530
|
+
this.handleEvent(event);
|
|
531
|
+
while (this.eventQueue.length > 0) {
|
|
532
|
+
const nextEvent = this.eventQueue.shift();
|
|
533
|
+
this.handleEvent(nextEvent);
|
|
534
|
+
}
|
|
535
|
+
} finally {
|
|
536
|
+
this.isProcessing = false;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Handle a single event (synchronously)
|
|
541
|
+
*/
|
|
542
|
+
handleEvent(event) {
|
|
543
|
+
const className = event.constructor.name;
|
|
544
|
+
const registrations = this.eventHandlers.get(className);
|
|
545
|
+
if (!registrations || registrations.length === 0) {
|
|
546
|
+
if (this.debug) console.warn(`No handler registered for event: ${className}`);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const emitFn = (state) => {
|
|
550
|
+
this.emit(state);
|
|
551
|
+
};
|
|
552
|
+
for (const registration of registrations) try {
|
|
553
|
+
registration.handler(event, emitFn);
|
|
554
|
+
} catch (error$1) {
|
|
555
|
+
if (this.debug) console.error(`Error handling event ${className}:`, error$1);
|
|
556
|
+
this.onEventError(event, error$1);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Hook for handling event processing errors
|
|
561
|
+
*/
|
|
562
|
+
onEventError(event, error$1) {}
|
|
563
|
+
};
|
|
564
|
+
/**
|
|
565
|
+
* Example: Counter Events
|
|
566
|
+
*/
|
|
567
|
+
var IncrementEvent = class {
|
|
568
|
+
type = "increment";
|
|
569
|
+
timestamp = Date.now();
|
|
570
|
+
constructor(amount = 1) {
|
|
571
|
+
this.amount = amount;
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
var DecrementEvent = class {
|
|
575
|
+
type = "decrement";
|
|
576
|
+
timestamp = Date.now();
|
|
577
|
+
constructor(amount = 1) {
|
|
578
|
+
this.amount = amount;
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
var ResetEvent = class {
|
|
582
|
+
type = "reset";
|
|
583
|
+
timestamp = Date.now();
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Example: Counter Vertex
|
|
587
|
+
* Demonstrates proper typing and event handling
|
|
588
|
+
*/
|
|
589
|
+
var CounterVertex = class extends Vertex {
|
|
590
|
+
constructor() {
|
|
591
|
+
super(0);
|
|
592
|
+
this.on(IncrementEvent, (event, emit) => {
|
|
593
|
+
emit(this.state + event.amount);
|
|
594
|
+
});
|
|
595
|
+
this.on(DecrementEvent, (event, emit) => {
|
|
596
|
+
emit(this.state - event.amount);
|
|
597
|
+
});
|
|
598
|
+
this.on(ResetEvent, (_, emit) => {
|
|
599
|
+
emit(0);
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
increment = (amount = 1) => {
|
|
603
|
+
this.add(new IncrementEvent(amount));
|
|
604
|
+
};
|
|
605
|
+
decrement = (amount = 1) => {
|
|
606
|
+
this.add(new DecrementEvent(amount));
|
|
607
|
+
};
|
|
608
|
+
reset = () => {
|
|
609
|
+
this.add(new ResetEvent());
|
|
610
|
+
};
|
|
611
|
+
};
|
|
612
|
+
var LoginEvent = class {
|
|
613
|
+
type = "login";
|
|
614
|
+
timestamp = Date.now();
|
|
615
|
+
constructor(email, password) {
|
|
616
|
+
this.email = email;
|
|
617
|
+
this.password = password;
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
var LogoutEvent = class {
|
|
621
|
+
type = "logout";
|
|
622
|
+
timestamp = Date.now();
|
|
623
|
+
};
|
|
624
|
+
var AuthVertex = class extends Vertex {
|
|
625
|
+
constructor() {
|
|
626
|
+
super({
|
|
627
|
+
isAuthenticated: false,
|
|
628
|
+
isLoading: false,
|
|
629
|
+
user: null,
|
|
630
|
+
error: null
|
|
631
|
+
});
|
|
632
|
+
this.on(LoginEvent, (event, emit) => {
|
|
633
|
+
emit({
|
|
634
|
+
...this.state,
|
|
635
|
+
isLoading: true,
|
|
636
|
+
error: null
|
|
637
|
+
});
|
|
638
|
+
if (event.email === "user@example.com" && event.password === "password") emit({
|
|
639
|
+
isAuthenticated: true,
|
|
640
|
+
isLoading: false,
|
|
641
|
+
user: {
|
|
642
|
+
id: "123",
|
|
643
|
+
name: "Test User",
|
|
644
|
+
email: "user@example.com"
|
|
645
|
+
},
|
|
646
|
+
error: null
|
|
647
|
+
});
|
|
648
|
+
else emit({
|
|
649
|
+
isAuthenticated: false,
|
|
650
|
+
isLoading: false,
|
|
651
|
+
user: null,
|
|
652
|
+
error: "Invalid credentials"
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
this.on(LogoutEvent, (_, emit) => {
|
|
656
|
+
emit({
|
|
657
|
+
isAuthenticated: false,
|
|
658
|
+
isLoading: false,
|
|
659
|
+
user: null,
|
|
660
|
+
error: null
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
login = (email, password) => {
|
|
665
|
+
this.add(new LoginEvent(email, password));
|
|
666
|
+
};
|
|
667
|
+
logout = () => {
|
|
668
|
+
this.add(new LogoutEvent());
|
|
669
|
+
};
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
//#endregion
|
|
673
|
+
//#region src/tracking/proxy-tracker.ts
|
|
674
|
+
/**
|
|
675
|
+
* Functional proxy tracker for automatic dependency tracking
|
|
676
|
+
*
|
|
677
|
+
* This module provides a functional approach to proxy-based dependency tracking.
|
|
678
|
+
* Unlike the class-based ProxyTracker, this uses a state object pattern that's
|
|
679
|
+
* easier to integrate with functional programming patterns and framework hooks.
|
|
680
|
+
*/
|
|
681
|
+
/**
|
|
682
|
+
* Array methods that should trigger tracking of the entire array
|
|
683
|
+
*/
|
|
684
|
+
const ARRAY_METHODS = new Set([
|
|
685
|
+
"map",
|
|
686
|
+
"filter",
|
|
687
|
+
"forEach",
|
|
688
|
+
"find",
|
|
689
|
+
"some",
|
|
690
|
+
"every",
|
|
691
|
+
"reduce"
|
|
692
|
+
]);
|
|
693
|
+
/**
|
|
694
|
+
* Check if a value can be proxied
|
|
695
|
+
*
|
|
696
|
+
* Returns true for plain objects and arrays only.
|
|
697
|
+
* Excludes built-in objects like Date, Map, Set, etc.
|
|
698
|
+
*/
|
|
699
|
+
function isProxyable(value) {
|
|
700
|
+
if (typeof value !== "object" || value === null) return false;
|
|
701
|
+
const proto = Object.getPrototypeOf(value);
|
|
702
|
+
return proto === Object.prototype || proto === Array.prototype;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Create a new proxy tracker state
|
|
706
|
+
*
|
|
707
|
+
* @example
|
|
708
|
+
* const state = createProxyTrackerState<MyState>();
|
|
709
|
+
* startProxyTracking(state);
|
|
710
|
+
* const proxy = createProxyForTarget(state, myObject);
|
|
711
|
+
* // ... use proxy ...
|
|
712
|
+
* const paths = stopProxyTracking(state);
|
|
713
|
+
*/
|
|
714
|
+
function createProxyTrackerState() {
|
|
715
|
+
return {
|
|
716
|
+
trackedPaths: /* @__PURE__ */ new Set(),
|
|
717
|
+
isTracking: false,
|
|
718
|
+
proxyCache: /* @__PURE__ */ new WeakMap(),
|
|
719
|
+
boundFunctionsCache: null,
|
|
720
|
+
lastProxiedState: null,
|
|
721
|
+
lastProxy: null,
|
|
722
|
+
maxDepth: 10
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Start tracking property accesses
|
|
727
|
+
*
|
|
728
|
+
* Clears previous tracked paths and enables tracking mode.
|
|
729
|
+
*/
|
|
730
|
+
function startProxyTracking(state) {
|
|
731
|
+
state.isTracking = true;
|
|
732
|
+
state.trackedPaths.clear();
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Stop tracking and return the tracked paths
|
|
736
|
+
*
|
|
737
|
+
* Returns a new Set containing all tracked paths.
|
|
738
|
+
*/
|
|
739
|
+
function stopProxyTracking(state) {
|
|
740
|
+
state.isTracking = false;
|
|
741
|
+
return new Set(state.trackedPaths);
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Create a proxy for an array with property access tracking
|
|
745
|
+
*
|
|
746
|
+
* Tracks:
|
|
747
|
+
* - Array element access (arr[0])
|
|
748
|
+
* - Length access (arr.length)
|
|
749
|
+
* - Array method calls (arr.map, arr.filter, etc.)
|
|
750
|
+
*/
|
|
751
|
+
function createArrayProxy(state, target, path, depth = 0) {
|
|
752
|
+
const proxy = new Proxy(target, { get: (arr, prop) => {
|
|
753
|
+
if (typeof prop === "symbol") return Reflect.get(arr, prop);
|
|
754
|
+
const value = Reflect.get(arr, prop);
|
|
755
|
+
if (typeof value === "function") {
|
|
756
|
+
if (ARRAY_METHODS.has(prop)) {
|
|
757
|
+
if (state.isTracking && path) state.trackedPaths.add(path);
|
|
758
|
+
}
|
|
759
|
+
if (!state.boundFunctionsCache) state.boundFunctionsCache = /* @__PURE__ */ new WeakMap();
|
|
760
|
+
const cached = state.boundFunctionsCache.get(value);
|
|
761
|
+
if (cached) return cached;
|
|
762
|
+
const bound = value.bind(arr);
|
|
763
|
+
state.boundFunctionsCache.set(value, bound);
|
|
764
|
+
return bound;
|
|
765
|
+
}
|
|
766
|
+
let fullPath;
|
|
767
|
+
if (prop === "length") fullPath = path ? `${path}.length` : "length";
|
|
768
|
+
else if (typeof prop === "string") {
|
|
769
|
+
const index = Number(prop);
|
|
770
|
+
if (!isNaN(index) && index >= 0) fullPath = path ? `${path}[${index}]` : `[${index}]`;
|
|
771
|
+
else fullPath = path ? `${path}.${prop}` : prop;
|
|
772
|
+
} else return value;
|
|
773
|
+
if (isProxyable(value)) return createProxyInternal(state, value, fullPath, depth + 1);
|
|
774
|
+
if (state.isTracking) state.trackedPaths.add(fullPath);
|
|
775
|
+
return value;
|
|
776
|
+
} });
|
|
777
|
+
state.proxyCache.set(target, proxy);
|
|
778
|
+
return proxy;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Create a proxy for an object with property access tracking
|
|
782
|
+
*
|
|
783
|
+
* This is the core proxy creation function that recursively creates proxies
|
|
784
|
+
* for nested objects and arrays.
|
|
785
|
+
*
|
|
786
|
+
* Tracks:
|
|
787
|
+
* - Property access (obj.prop)
|
|
788
|
+
* - Nested property access (obj.nested.prop)
|
|
789
|
+
* - 'in' operator usage ('prop' in obj)
|
|
790
|
+
* - Object.keys, Object.entries, etc.
|
|
791
|
+
*/
|
|
792
|
+
function createProxyInternal(state, target, path = "", depth = 0) {
|
|
793
|
+
if (!state.isTracking || !isProxyable(target)) return target;
|
|
794
|
+
if (depth >= state.maxDepth) return target;
|
|
795
|
+
if (state.proxyCache.has(target)) return state.proxyCache.get(target);
|
|
796
|
+
if (Array.isArray(target)) return createArrayProxy(state, target, path, depth);
|
|
797
|
+
const proxy = new Proxy(target, {
|
|
798
|
+
get: (obj, prop) => {
|
|
799
|
+
if (typeof prop === "symbol") return Reflect.get(obj, prop);
|
|
800
|
+
const value = Reflect.get(obj, prop);
|
|
801
|
+
if (typeof value === "function") {
|
|
802
|
+
if (!state.boundFunctionsCache) state.boundFunctionsCache = /* @__PURE__ */ new WeakMap();
|
|
803
|
+
const cached = state.boundFunctionsCache.get(value);
|
|
804
|
+
if (cached) return cached;
|
|
805
|
+
const bound = value.bind(obj);
|
|
806
|
+
state.boundFunctionsCache.set(value, bound);
|
|
807
|
+
return bound;
|
|
808
|
+
}
|
|
809
|
+
const fullPath = path ? `${path}.${String(prop)}` : String(prop);
|
|
810
|
+
if (isProxyable(value)) return createProxyInternal(state, value, fullPath, depth + 1);
|
|
811
|
+
if (typeof prop === "string" && state.isTracking) {
|
|
812
|
+
if (!prop.startsWith("_") && !prop.startsWith("$$")) state.trackedPaths.add(fullPath);
|
|
813
|
+
}
|
|
814
|
+
return value;
|
|
815
|
+
},
|
|
816
|
+
has: (obj, prop) => {
|
|
817
|
+
if (typeof prop === "string" && state.isTracking) {
|
|
818
|
+
const fullPath = path ? `${path}.${prop}` : prop;
|
|
819
|
+
state.trackedPaths.add(fullPath);
|
|
820
|
+
}
|
|
821
|
+
return Reflect.has(obj, prop);
|
|
822
|
+
},
|
|
823
|
+
ownKeys: (obj) => {
|
|
824
|
+
if (state.isTracking && path) state.trackedPaths.add(path);
|
|
825
|
+
return Reflect.ownKeys(obj);
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
state.proxyCache.set(target, proxy);
|
|
829
|
+
return proxy;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Create a proxy for a target with caching
|
|
833
|
+
*
|
|
834
|
+
* If the target hasn't changed since the last call, returns the cached proxy.
|
|
835
|
+
* Otherwise, creates a new proxy and caches it.
|
|
836
|
+
*
|
|
837
|
+
* This is the main entry point for creating tracked proxies.
|
|
838
|
+
*/
|
|
839
|
+
function createProxyForTarget(state, target) {
|
|
840
|
+
if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
|
|
841
|
+
state.proxyCache = /* @__PURE__ */ new WeakMap();
|
|
842
|
+
state.boundFunctionsCache = null;
|
|
843
|
+
const proxy = createProxyInternal(state, target, "", 0);
|
|
844
|
+
state.lastProxiedState = target;
|
|
845
|
+
state.lastProxy = proxy;
|
|
846
|
+
return proxy;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
//#endregion
|
|
850
|
+
//#region src/tracking/path-utils.ts
|
|
851
|
+
/**
|
|
852
|
+
* Path utilities for dependency tracking
|
|
853
|
+
*
|
|
854
|
+
* Provides utilities for parsing property paths and extracting values
|
|
855
|
+
* from nested objects using path strings.
|
|
856
|
+
*/
|
|
857
|
+
/**
|
|
858
|
+
* Parse a property path string into an array of segments
|
|
859
|
+
*
|
|
860
|
+
* Handles both dot notation (a.b.c) and bracket notation (a[0].b)
|
|
861
|
+
*
|
|
862
|
+
* @example
|
|
863
|
+
* parsePath('user.name') // ['user', 'name']
|
|
864
|
+
* parsePath('items[0].name') // ['items', '0', 'name']
|
|
865
|
+
* parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
|
|
866
|
+
*/
|
|
867
|
+
function parsePath(path) {
|
|
868
|
+
const segments = [];
|
|
869
|
+
let current = "";
|
|
870
|
+
let i = 0;
|
|
871
|
+
while (i < path.length) {
|
|
872
|
+
const char = path[i];
|
|
873
|
+
if (char === ".") {
|
|
874
|
+
if (current) segments.push(current);
|
|
875
|
+
current = "";
|
|
876
|
+
} else if (char === "[") {
|
|
877
|
+
if (current) segments.push(current);
|
|
878
|
+
current = "";
|
|
879
|
+
i++;
|
|
880
|
+
while (i < path.length && path[i] !== "]") current += path[i++];
|
|
881
|
+
if (current) segments.push(current);
|
|
882
|
+
current = "";
|
|
883
|
+
} else current += char;
|
|
884
|
+
i++;
|
|
885
|
+
}
|
|
886
|
+
if (current) segments.push(current);
|
|
887
|
+
return segments;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Get a value from an object using a path of segments
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* const obj = { user: { name: 'Alice', age: 30 } }
|
|
894
|
+
* getValueAtPath(obj, ['user', 'name']) // 'Alice'
|
|
895
|
+
* getValueAtPath(obj, ['user', 'age']) // 30
|
|
896
|
+
* getValueAtPath(obj, ['user', 'missing']) // undefined
|
|
897
|
+
*/
|
|
898
|
+
function getValueAtPath(obj, segments) {
|
|
899
|
+
if (obj == null) return void 0;
|
|
900
|
+
let current = obj;
|
|
901
|
+
for (let i = 0; i < segments.length; i++) {
|
|
902
|
+
current = current[segments[i]];
|
|
903
|
+
if (current == null) return void 0;
|
|
904
|
+
}
|
|
905
|
+
return current;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Shallow equality comparison for arrays
|
|
909
|
+
*
|
|
910
|
+
* Compares two arrays element-by-element using Object.is
|
|
911
|
+
*
|
|
912
|
+
* @example
|
|
913
|
+
* shallowEqual([1, 2, 3], [1, 2, 3]) // true
|
|
914
|
+
* shallowEqual([1, 2, 3], [1, 2, 4]) // false
|
|
915
|
+
* shallowEqual([1, 2], [1, 2, 3]) // false
|
|
916
|
+
*/
|
|
917
|
+
function shallowEqual(arr1, arr2) {
|
|
918
|
+
if (arr1.length !== arr2.length) return false;
|
|
919
|
+
for (let i = 0; i < arr1.length; i++) if (!Object.is(arr1[i], arr2[i])) return false;
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
//#endregion
|
|
924
|
+
//#region src/tracking/dependency-tracker.ts
|
|
925
|
+
/**
|
|
926
|
+
* How often to clean up unused paths from the cache
|
|
927
|
+
*/
|
|
928
|
+
const CLEANUP_INTERVAL = 10;
|
|
929
|
+
/**
|
|
930
|
+
* Create a new tracker state
|
|
931
|
+
*/
|
|
932
|
+
function createTrackerState() {
|
|
933
|
+
return {
|
|
934
|
+
proxyTrackerState: createProxyTrackerState(),
|
|
935
|
+
previousRenderPaths: /* @__PURE__ */ new Set(),
|
|
936
|
+
currentRenderPaths: /* @__PURE__ */ new Set(),
|
|
937
|
+
pathCache: /* @__PURE__ */ new Map(),
|
|
938
|
+
lastCheckedState: null,
|
|
939
|
+
lastCheckedValues: /* @__PURE__ */ new Map(),
|
|
940
|
+
cleanupCounter: 0
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Start tracking property accesses
|
|
945
|
+
*/
|
|
946
|
+
function startTracking(tracker) {
|
|
947
|
+
startProxyTracking(tracker.proxyTrackerState);
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Create a proxy for the given state
|
|
951
|
+
*/
|
|
952
|
+
function createProxy(tracker, state) {
|
|
953
|
+
return createProxyForTarget(tracker.proxyTrackerState, state);
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Capture the paths that were tracked during a render
|
|
957
|
+
*
|
|
958
|
+
* This should be called after each render to record which paths were accessed.
|
|
959
|
+
* It also performs periodic cleanup of unused paths to prevent memory leaks.
|
|
960
|
+
*/
|
|
961
|
+
function captureTrackedPaths(tracker, state) {
|
|
962
|
+
tracker.previousRenderPaths = tracker.currentRenderPaths;
|
|
963
|
+
tracker.currentRenderPaths = stopProxyTracking(tracker.proxyTrackerState);
|
|
964
|
+
if (tracker.previousRenderPaths.size === 0 && tracker.currentRenderPaths.size === 0) return;
|
|
965
|
+
const trackedPathsUnion = new Set(tracker.previousRenderPaths);
|
|
966
|
+
for (const path of tracker.currentRenderPaths) trackedPathsUnion.add(path);
|
|
967
|
+
const canReuseCache = tracker.lastCheckedState === state;
|
|
968
|
+
for (const path of trackedPathsUnion) if (!tracker.pathCache.has(path)) {
|
|
969
|
+
const segments = parsePath(path);
|
|
970
|
+
const value = canReuseCache && tracker.lastCheckedValues.has(path) ? tracker.lastCheckedValues.get(path) : getValueAtPath(state, segments);
|
|
971
|
+
tracker.pathCache.set(path, {
|
|
972
|
+
segments,
|
|
973
|
+
value
|
|
974
|
+
});
|
|
975
|
+
} else {
|
|
976
|
+
const info$1 = tracker.pathCache.get(path);
|
|
977
|
+
info$1.value = canReuseCache && tracker.lastCheckedValues.has(path) ? tracker.lastCheckedValues.get(path) : getValueAtPath(state, info$1.segments);
|
|
978
|
+
}
|
|
979
|
+
tracker.cleanupCounter++;
|
|
980
|
+
if (tracker.cleanupCounter >= CLEANUP_INTERVAL) {
|
|
981
|
+
tracker.cleanupCounter = 0;
|
|
982
|
+
for (const path of tracker.pathCache.keys()) if (!trackedPathsUnion.has(path)) tracker.pathCache.delete(path);
|
|
983
|
+
}
|
|
984
|
+
tracker.lastCheckedValues.clear();
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Check if any tracked paths have changed
|
|
988
|
+
*
|
|
989
|
+
* This is called when state changes to determine if a re-render is needed.
|
|
990
|
+
* Returns true if any tracked path has a different value than before.
|
|
991
|
+
*/
|
|
992
|
+
function hasChanges(tracker, state) {
|
|
993
|
+
if (tracker.pathCache.size === 0) return true;
|
|
994
|
+
tracker.lastCheckedValues.clear();
|
|
995
|
+
for (const [path, info$1] of tracker.pathCache.entries()) {
|
|
996
|
+
const currentValue = getValueAtPath(state, info$1.segments);
|
|
997
|
+
tracker.lastCheckedValues.set(path, currentValue);
|
|
998
|
+
if (!Object.is(currentValue, info$1.value)) {
|
|
999
|
+
tracker.lastCheckedState = state;
|
|
1000
|
+
return true;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
tracker.lastCheckedState = state;
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Check if tracker has any tracked data
|
|
1008
|
+
*
|
|
1009
|
+
* Returns true if there are any tracked paths or cached paths.
|
|
1010
|
+
*/
|
|
1011
|
+
function hasTrackedData(tracker) {
|
|
1012
|
+
return tracker.proxyTrackerState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
//#endregion
|
|
1016
|
+
//#region src/logging/Logger.ts
|
|
1017
|
+
let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
|
|
1018
|
+
LogLevel$1[LogLevel$1["ERROR"] = 0] = "ERROR";
|
|
1019
|
+
LogLevel$1[LogLevel$1["WARN"] = 1] = "WARN";
|
|
1020
|
+
LogLevel$1[LogLevel$1["INFO"] = 2] = "INFO";
|
|
1021
|
+
LogLevel$1[LogLevel$1["DEBUG"] = 3] = "DEBUG";
|
|
1022
|
+
return LogLevel$1;
|
|
1023
|
+
}({});
|
|
1024
|
+
/**
|
|
1025
|
+
* Creates a logger instance with given configuration
|
|
1026
|
+
*
|
|
1027
|
+
* @param config - Logger configuration
|
|
1028
|
+
* @returns Logger instance with debug, info, warn, error, and configure methods
|
|
1029
|
+
*
|
|
1030
|
+
* @example
|
|
1031
|
+
* ```ts
|
|
1032
|
+
* const logger = createLogger({
|
|
1033
|
+
* enabled: true,
|
|
1034
|
+
* level: LogLevel.DEBUG,
|
|
1035
|
+
* output: (entry) => console.log(JSON.stringify(entry))
|
|
1036
|
+
* });
|
|
1037
|
+
* logger.debug('MyComponent', 'Rendering', { props: { foo: 'bar' } });
|
|
1038
|
+
* ```
|
|
1039
|
+
*/
|
|
1040
|
+
function createLogger(config) {
|
|
1041
|
+
const shouldLog = (level) => {
|
|
1042
|
+
return config.enabled && config.level >= level;
|
|
1043
|
+
};
|
|
1044
|
+
const log = (level, context, message, data) => {
|
|
1045
|
+
try {
|
|
1046
|
+
const entry = {
|
|
1047
|
+
level,
|
|
1048
|
+
context,
|
|
1049
|
+
message,
|
|
1050
|
+
timestamp: Date.now(),
|
|
1051
|
+
...data !== void 0 && { data: serialize(data) }
|
|
1052
|
+
};
|
|
1053
|
+
config.output(entry);
|
|
1054
|
+
} catch (e) {
|
|
1055
|
+
console.error("[BlacLogger] Error logging:", e);
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
const serialize = (data) => {
|
|
1059
|
+
try {
|
|
1060
|
+
return JSON.parse(JSON.stringify(data));
|
|
1061
|
+
} catch {
|
|
1062
|
+
return String(data);
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
return {
|
|
1066
|
+
debug: (context, message, data) => {
|
|
1067
|
+
if (shouldLog(LogLevel.DEBUG)) log("DEBUG", context, message, data);
|
|
1068
|
+
},
|
|
1069
|
+
info: (context, message, data) => {
|
|
1070
|
+
if (shouldLog(LogLevel.INFO)) log("INFO", context, message, data);
|
|
1071
|
+
},
|
|
1072
|
+
warn: (context, message, data) => {
|
|
1073
|
+
if (shouldLog(LogLevel.WARN)) log("WARN", context, message, data);
|
|
1074
|
+
},
|
|
1075
|
+
error: (context, message, data) => {
|
|
1076
|
+
if (shouldLog(LogLevel.ERROR)) log("ERROR", context, message, data);
|
|
1077
|
+
},
|
|
1078
|
+
configure: (opts) => {
|
|
1079
|
+
Object.assign(config, opts);
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
let currentConfig = {
|
|
1084
|
+
enabled: false,
|
|
1085
|
+
level: LogLevel.INFO,
|
|
1086
|
+
output: (entry) => console.log(JSON.stringify(entry))
|
|
1087
|
+
};
|
|
1088
|
+
let defaultLogger = createLogger(currentConfig);
|
|
1089
|
+
const debug = (context, message, data) => defaultLogger.debug(context, message, data);
|
|
1090
|
+
const info = (context, message, data) => defaultLogger.info(context, message, data);
|
|
1091
|
+
const warn = (context, message, data) => defaultLogger.warn(context, message, data);
|
|
1092
|
+
const error = (context, message, data) => defaultLogger.error(context, message, data);
|
|
1093
|
+
/**
|
|
1094
|
+
* Configuration function that recreates the default logger
|
|
1095
|
+
*
|
|
1096
|
+
* @param opts - Partial logger configuration
|
|
1097
|
+
*
|
|
1098
|
+
* @example
|
|
1099
|
+
* ```ts
|
|
1100
|
+
* configureLogger({ enabled: true, level: LogLevel.DEBUG });
|
|
1101
|
+
* ```
|
|
1102
|
+
*/
|
|
1103
|
+
function configureLogger(opts) {
|
|
1104
|
+
currentConfig = {
|
|
1105
|
+
...currentConfig,
|
|
1106
|
+
...opts
|
|
1107
|
+
};
|
|
1108
|
+
defaultLogger = createLogger(currentConfig);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
//#endregion
|
|
1112
|
+
//#region src/proxy/ProxyTracker.ts
|
|
1113
|
+
/**
|
|
1114
|
+
* Check if a value is an object that can be proxied
|
|
1115
|
+
*/
|
|
1116
|
+
function isProxyable$1(value) {
|
|
1117
|
+
return value !== null && typeof value === "object" && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof Map) && !(value instanceof Set) && !(value instanceof WeakMap) && !(value instanceof WeakSet) && !(value instanceof Promise);
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Tracks property access on state objects
|
|
1121
|
+
*/
|
|
1122
|
+
var ProxyTracker = class {
|
|
1123
|
+
trackedPaths = /* @__PURE__ */ new Set();
|
|
1124
|
+
isTracking = false;
|
|
1125
|
+
proxyCache = /* @__PURE__ */ new WeakMap();
|
|
1126
|
+
maxDepth = 10;
|
|
1127
|
+
/**
|
|
1128
|
+
* Create a proxy that tracks property access
|
|
1129
|
+
*/
|
|
1130
|
+
createProxy(target, path = "", depth = 0) {
|
|
1131
|
+
if (!this.isTracking || !isProxyable$1(target)) return target;
|
|
1132
|
+
if (depth >= this.maxDepth) return target;
|
|
1133
|
+
if (this.proxyCache.has(target)) return this.proxyCache.get(target);
|
|
1134
|
+
if (Array.isArray(target)) return this.createArrayProxy(target, path, depth);
|
|
1135
|
+
const proxy = new Proxy(target, {
|
|
1136
|
+
get: (obj, prop) => {
|
|
1137
|
+
const value = Reflect.get(obj, prop);
|
|
1138
|
+
if (typeof value === "function") return value.bind(obj);
|
|
1139
|
+
const fullPath = path ? `${path}.${String(prop)}` : String(prop);
|
|
1140
|
+
if (isProxyable$1(value)) return this.createProxy(value, fullPath, depth + 1);
|
|
1141
|
+
if (typeof prop === "string" && this.isTracking) {
|
|
1142
|
+
if (!prop.startsWith("_") && !prop.startsWith("$$")) {
|
|
1143
|
+
this.trackedPaths.add(fullPath);
|
|
1144
|
+
debug("ProxyTracker", "Tracked property access", {
|
|
1145
|
+
path: fullPath,
|
|
1146
|
+
valueType: typeof value
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
return value;
|
|
1151
|
+
},
|
|
1152
|
+
has: (obj, prop) => {
|
|
1153
|
+
if (typeof prop === "string" && this.isTracking) {
|
|
1154
|
+
const fullPath = path ? `${path}.${prop}` : prop;
|
|
1155
|
+
this.trackedPaths.add(fullPath);
|
|
1156
|
+
debug("ProxyTracker", "Tracked \"in\" operator access", { path: fullPath });
|
|
1157
|
+
}
|
|
1158
|
+
return Reflect.has(obj, prop);
|
|
1159
|
+
},
|
|
1160
|
+
ownKeys: (obj) => {
|
|
1161
|
+
if (this.isTracking && path) {
|
|
1162
|
+
this.trackedPaths.add(path);
|
|
1163
|
+
debug("ProxyTracker", "Tracked object keys iteration", { path });
|
|
1164
|
+
}
|
|
1165
|
+
return Reflect.ownKeys(obj);
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
this.proxyCache.set(target, proxy);
|
|
1169
|
+
return proxy;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Create a proxy for arrays with special handling
|
|
1173
|
+
*/
|
|
1174
|
+
createArrayProxy(target, path, depth = 0) {
|
|
1175
|
+
const proxy = new Proxy(target, { get: (arr, prop) => {
|
|
1176
|
+
const value = Reflect.get(arr, prop);
|
|
1177
|
+
if (typeof value === "function") {
|
|
1178
|
+
if ([
|
|
1179
|
+
"map",
|
|
1180
|
+
"filter",
|
|
1181
|
+
"forEach",
|
|
1182
|
+
"find",
|
|
1183
|
+
"some",
|
|
1184
|
+
"every",
|
|
1185
|
+
"reduce"
|
|
1186
|
+
].includes(String(prop))) {
|
|
1187
|
+
if (this.isTracking && path) {
|
|
1188
|
+
this.trackedPaths.add(path);
|
|
1189
|
+
debug("ProxyTracker", "Tracked array method access", {
|
|
1190
|
+
path,
|
|
1191
|
+
method: String(prop)
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return value.bind(arr);
|
|
1196
|
+
}
|
|
1197
|
+
let fullPath;
|
|
1198
|
+
if (prop === "length") fullPath = path ? `${path}.length` : "length";
|
|
1199
|
+
else if (typeof prop === "string") {
|
|
1200
|
+
const index = Number(prop);
|
|
1201
|
+
if (!isNaN(index) && index >= 0) fullPath = path ? `${path}[${index}]` : `[${index}]`;
|
|
1202
|
+
else fullPath = path ? `${path}.${prop}` : prop;
|
|
1203
|
+
} else return value;
|
|
1204
|
+
if (isProxyable$1(value)) return this.createProxy(value, fullPath, depth + 1);
|
|
1205
|
+
if (this.isTracking) {
|
|
1206
|
+
this.trackedPaths.add(fullPath);
|
|
1207
|
+
debug("ProxyTracker", "Tracked array property access", {
|
|
1208
|
+
path: fullPath,
|
|
1209
|
+
valueType: typeof value
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
return value;
|
|
1213
|
+
} });
|
|
1214
|
+
this.proxyCache.set(target, proxy);
|
|
1215
|
+
return proxy;
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Start tracking property access
|
|
1219
|
+
*/
|
|
1220
|
+
startTracking() {
|
|
1221
|
+
this.isTracking = true;
|
|
1222
|
+
this.trackedPaths.clear();
|
|
1223
|
+
debug("ProxyTracker", "Started tracking");
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Stop tracking and return tracked paths
|
|
1227
|
+
*/
|
|
1228
|
+
stopTracking() {
|
|
1229
|
+
this.isTracking = false;
|
|
1230
|
+
debug("ProxyTracker", "Stopped tracking", {
|
|
1231
|
+
pathCount: this.trackedPaths.size,
|
|
1232
|
+
paths: Array.from(this.trackedPaths)
|
|
1233
|
+
});
|
|
1234
|
+
return new Set(this.trackedPaths);
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Get currently tracked paths
|
|
1238
|
+
*/
|
|
1239
|
+
getTrackedPaths() {
|
|
1240
|
+
return new Set(this.trackedPaths);
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Check if currently tracking
|
|
1244
|
+
*/
|
|
1245
|
+
isCurrentlyTracking() {
|
|
1246
|
+
return this.isTracking;
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Clear proxy cache (useful for memory management)
|
|
1250
|
+
*/
|
|
1251
|
+
clearCache() {
|
|
1252
|
+
this.proxyCache = /* @__PURE__ */ new WeakMap();
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Set maximum tracking depth
|
|
1256
|
+
*/
|
|
1257
|
+
setMaxDepth(depth) {
|
|
1258
|
+
this.maxDepth = Math.max(1, depth);
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Add a path manually (useful for forcing dependencies)
|
|
1262
|
+
*/
|
|
1263
|
+
addPath(path) {
|
|
1264
|
+
this.trackedPaths.add(path);
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Remove a path manually
|
|
1268
|
+
*/
|
|
1269
|
+
removePath(path) {
|
|
1270
|
+
this.trackedPaths.delete(path);
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Clear all tracked paths
|
|
1274
|
+
*/
|
|
1275
|
+
clearPaths() {
|
|
1276
|
+
this.trackedPaths.clear();
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
/**
|
|
1280
|
+
* Global proxy tracker instance for convenience
|
|
1281
|
+
*/
|
|
1282
|
+
const globalProxyTracker = new ProxyTracker();
|
|
1283
|
+
/**
|
|
1284
|
+
* Utility function to track property access in a callback
|
|
1285
|
+
*/
|
|
1286
|
+
function trackAccess(state, callback) {
|
|
1287
|
+
const tracker = new ProxyTracker();
|
|
1288
|
+
tracker.startTracking();
|
|
1289
|
+
return {
|
|
1290
|
+
result: callback(tracker.createProxy(state)),
|
|
1291
|
+
trackedPaths: tracker.stopTracking()
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
//#endregion
|
|
1296
|
+
//#region src/constants.ts
|
|
1297
|
+
/**
|
|
1298
|
+
* Default configuration constants for BlaC
|
|
1299
|
+
*
|
|
1300
|
+
* Centralized location for all magic numbers and default values.
|
|
1301
|
+
*/
|
|
1302
|
+
/**
|
|
1303
|
+
* Default configuration constants for BlaC
|
|
1304
|
+
*/
|
|
1305
|
+
const BLAC_DEFAULTS = {
|
|
1306
|
+
CLEANUP_INTERVAL_MS: 3e4,
|
|
1307
|
+
WEAKREF_CLEANUP_INTERVAL_MS: 1e4,
|
|
1308
|
+
MAX_SUBSCRIPTIONS: 1e3,
|
|
1309
|
+
MAX_SUBSCRIPTIONS_HIGH_PERF: 1e4,
|
|
1310
|
+
PIPELINE_TIMEOUT_MS: 5e3,
|
|
1311
|
+
CLEANUP_INTERVAL_HIGH_PERF_MS: 5e3,
|
|
1312
|
+
MAX_PIPELINE_STAGES: 30
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
//#endregion
|
|
1316
|
+
exports.AuthVertex = AuthVertex;
|
|
1317
|
+
exports.BLAC_DEFAULTS = BLAC_DEFAULTS;
|
|
1318
|
+
exports.CounterCubit = CounterCubit;
|
|
1319
|
+
exports.CounterVertex = CounterVertex;
|
|
1320
|
+
exports.Cubit = Cubit;
|
|
1321
|
+
exports.DecrementEvent = DecrementEvent;
|
|
1322
|
+
exports.IncrementEvent = IncrementEvent;
|
|
1323
|
+
exports.LogLevel = LogLevel;
|
|
1324
|
+
exports.LoginEvent = LoginEvent;
|
|
1325
|
+
exports.LogoutEvent = LogoutEvent;
|
|
1326
|
+
exports.ProxyTracker = ProxyTracker;
|
|
1327
|
+
exports.ResetEvent = ResetEvent;
|
|
1328
|
+
exports.StateContainer = StateContainer;
|
|
1329
|
+
exports.StateContainerRegistry = StateContainerRegistry;
|
|
1330
|
+
exports.TodoCubit = TodoCubit;
|
|
1331
|
+
exports.Vertex = Vertex;
|
|
1332
|
+
exports.__resetIdCounters = __resetIdCounters;
|
|
1333
|
+
exports.captureTrackedPaths = captureTrackedPaths;
|
|
1334
|
+
exports.configureLogger = configureLogger;
|
|
1335
|
+
exports.createArrayProxy = createArrayProxy;
|
|
1336
|
+
exports.createIdGenerator = createIdGenerator;
|
|
1337
|
+
exports.createLogger = createLogger;
|
|
1338
|
+
exports.createProxy = createProxy;
|
|
1339
|
+
exports.createProxyForTarget = createProxyForTarget;
|
|
1340
|
+
exports.createProxyInternal = createProxyInternal;
|
|
1341
|
+
exports.createProxyTrackerState = createProxyTrackerState;
|
|
1342
|
+
exports.createTrackerState = createTrackerState;
|
|
1343
|
+
exports.debug = debug;
|
|
1344
|
+
exports.error = error;
|
|
1345
|
+
exports.generateId = generateId;
|
|
1346
|
+
exports.generateSimpleId = generateSimpleId;
|
|
1347
|
+
exports.getValueAtPath = getValueAtPath;
|
|
1348
|
+
exports.globalProxyTracker = globalProxyTracker;
|
|
1349
|
+
exports.globalRegistry = globalRegistry;
|
|
1350
|
+
exports.hasChanges = hasChanges;
|
|
1351
|
+
exports.hasTrackedData = hasTrackedData;
|
|
1352
|
+
exports.info = info;
|
|
1353
|
+
exports.isProxyable = isProxyable;
|
|
1354
|
+
exports.parsePath = parsePath;
|
|
1355
|
+
exports.shallowEqual = shallowEqual;
|
|
1356
|
+
exports.startProxyTracking = startProxyTracking;
|
|
1357
|
+
exports.startTracking = startTracking;
|
|
1358
|
+
exports.stopProxyTracking = stopProxyTracking;
|
|
1359
|
+
exports.trackAccess = trackAccess;
|
|
1360
|
+
exports.warn = warn;
|
|
1361
|
+
//# sourceMappingURL=index.cjs.map
|