@blac/core 2.0.0-rc-11 → 2.0.0-rc-14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/index.cjs.js +2 -2
  2. package/dist/index.cjs.js.map +1 -1
  3. package/dist/index.d.ts +739 -260
  4. package/dist/index.es.js +1924 -1237
  5. package/dist/index.es.js.map +1 -1
  6. package/package.json +6 -7
  7. package/src/Blac.ts +82 -69
  8. package/src/Bloc.ts +45 -3
  9. package/src/BlocBase.ts +263 -454
  10. package/src/Cubit.ts +1 -16
  11. package/src/__tests__/Blac.config.test.ts +10 -17
  12. package/src/__tests__/Bloc.event.test.ts +27 -52
  13. package/src/__tests__/BlocBase.subscription.test.ts +349 -0
  14. package/src/__tests__/Cubit.test.ts +39 -50
  15. package/src/__tests__/memory-leaks.test.ts +383 -0
  16. package/src/__tests__/plugins.test.ts +464 -0
  17. package/src/adapter/BlacAdapter.ts +347 -207
  18. package/src/adapter/ProxyFactory.ts +196 -255
  19. package/src/adapter/__tests__/BlacAdapter.test.ts +71 -77
  20. package/src/adapter/__tests__/ProxyFactory.test.ts +1 -1
  21. package/src/adapter/index.ts +0 -1
  22. package/src/errors/BlacError.ts +69 -0
  23. package/src/errors/ErrorManager.ts +101 -0
  24. package/src/errors/handleError.ts +114 -0
  25. package/src/errors/index.ts +13 -0
  26. package/src/events.ts +7 -1
  27. package/src/index.ts +10 -1
  28. package/src/lifecycle/BlocLifecycle.ts +156 -0
  29. package/src/lifecycle/index.ts +1 -0
  30. package/src/plugins/BlocPluginRegistry.ts +240 -0
  31. package/src/plugins/SystemPluginRegistry.ts +242 -0
  32. package/src/plugins/__tests__/BlocPluginRegistry.test.ts +450 -0
  33. package/src/plugins/__tests__/SystemPluginRegistry.test.ts +404 -0
  34. package/src/plugins/index.ts +8 -0
  35. package/src/plugins/types.ts +129 -0
  36. package/src/subscription/README.md +132 -0
  37. package/src/subscription/SubscriptionManager.ts +395 -0
  38. package/src/subscription/__tests__/SubscriptionManager.test.ts +355 -0
  39. package/src/subscription/index.ts +2 -0
  40. package/src/subscription/types.ts +90 -0
  41. package/src/testing.ts +31 -37
  42. package/src/types.ts +4 -21
  43. package/src/utils/BatchingManager.ts +59 -0
  44. package/src/utils/RerenderLogger.ts +265 -0
  45. package/src/utils/__tests__/generateInstanceId.test.ts +104 -0
  46. package/src/utils/__tests__/shallowEqual.test.ts +171 -0
  47. package/src/utils/__tests__/uuid.test.ts +144 -0
  48. package/src/utils/generateInstanceId.ts +54 -0
  49. package/src/utils/shallowEqual.ts +1 -1
  50. package/README.md +0 -329
  51. package/src/BlacObserver.ts +0 -186
  52. package/src/__tests__/BlocBase.lifecycle.test.ts +0 -441
  53. package/src/__tests__/props.test.ts +0 -256
  54. package/src/adapter/ConsumerTracker.ts +0 -241
  55. package/src/adapter/__tests__/ConsumerTracker.test.ts +0 -562
package/dist/index.es.js CHANGED
@@ -1,697 +1,361 @@
1
- var E = Object.defineProperty;
2
- var O = (c, e, t) => e in c ? E(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
3
- var i = (c, e, t) => O(c, typeof e != "symbol" ? e + "" : e, t);
4
- class V {
1
+ var u = /* @__PURE__ */ ((r) => (r.ACTIVE = "active", r.DISPOSAL_REQUESTED = "disposal_requested", r.DISPOSING = "disposing", r.DISPOSED = "disposed", r))(u || {});
2
+ class B {
3
+ disposalState = "active";
4
+ disposalLock = !1;
5
+ disposalTimer;
6
+ disposalHandler;
7
+ get currentState() {
8
+ return this.disposalState;
9
+ }
10
+ get isDisposed() {
11
+ return this.disposalState === "disposed";
12
+ }
5
13
  /**
6
- * Creates a new BlacObservable instance
7
- * @param bloc - The Bloc instance to observe
14
+ * Atomic state transition for disposal
8
15
  */
9
- constructor(e) {
10
- /** The Bloc instance this observable is associated with */
11
- i(this, "bloc");
12
- i(this, "_observers", /* @__PURE__ */ new Set());
13
- this.bloc = e;
16
+ atomicStateTransition(e, t) {
17
+ if (this.disposalLock)
18
+ return {
19
+ success: !1,
20
+ currentState: this.disposalState,
21
+ previousState: this.disposalState
22
+ };
23
+ this.disposalLock = !0;
24
+ try {
25
+ if (this.disposalState !== e)
26
+ return {
27
+ success: !1,
28
+ currentState: this.disposalState,
29
+ previousState: this.disposalState
30
+ };
31
+ const s = this.disposalState;
32
+ return this.disposalState = t, {
33
+ success: !0,
34
+ currentState: t,
35
+ previousState: s
36
+ };
37
+ } finally {
38
+ this.disposalLock = !1;
39
+ }
14
40
  }
15
41
  /**
16
- * Gets the number of active observers
17
- * @returns The number of observers currently subscribed
42
+ * Schedule disposal after a delay
18
43
  */
19
- get size() {
20
- return this._observers.size;
44
+ scheduleDisposal(e, t, s) {
45
+ this.disposalTimer && (clearTimeout(this.disposalTimer), this.disposalTimer = void 0), this.atomicStateTransition(
46
+ "active",
47
+ "disposal_requested"
48
+ /* DISPOSAL_REQUESTED */
49
+ ).success && (this.disposalTimer = setTimeout(() => {
50
+ t() && this.disposalState === "disposal_requested" ? s() : this.atomicStateTransition(
51
+ "disposal_requested",
52
+ "active"
53
+ /* ACTIVE */
54
+ );
55
+ }, e));
21
56
  }
22
57
  /**
23
- * Gets the set of all observers
24
- * @returns The Set of all BlacObserver instances
58
+ * Cancel disposal if in disposal requested state
25
59
  */
26
- get observers() {
27
- return this._observers;
60
+ cancelDisposal() {
61
+ return this.disposalState === "disposal_requested" ? (this.disposalTimer && (clearTimeout(this.disposalTimer), this.disposalTimer = void 0), this.atomicStateTransition(
62
+ "disposal_requested",
63
+ "active"
64
+ /* ACTIVE */
65
+ ).success) : !1;
28
66
  }
29
67
  /**
30
- * Subscribes an observer to state changes
31
- * @param observer - The observer to subscribe
32
- * @returns A function that can be called to unsubscribe the observer
68
+ * Set disposal handler
33
69
  */
34
- subscribe(e) {
35
- const t = this.bloc._disposalState;
36
- return t === _.DISPOSED || t === _.DISPOSING ? (d.log(
37
- "BlacObservable.subscribe: Cannot subscribe to disposed/disposing bloc.",
38
- this.bloc,
39
- e
40
- ), () => {
41
- }) : (d.log(
42
- "BlacObservable.subscribe: Subscribing observer.",
43
- this.bloc,
44
- e
45
- ), this._observers.add(e), t === _.DISPOSAL_REQUESTED && (d.log(
46
- "BlacObservable.subscribe: Cancelling disposal due to new subscription.",
47
- this.bloc
48
- ), this.bloc._atomicStateTransition(
49
- _.DISPOSAL_REQUESTED,
50
- _.ACTIVE
51
- )), () => {
52
- d.log(
53
- "BlacObservable.subscribe: Unsubscribing observer.",
54
- this.bloc,
55
- e
56
- ), this.unsubscribe(e);
57
- });
70
+ setDisposalHandler(e) {
71
+ this.disposalHandler = e;
58
72
  }
59
73
  /**
60
- * Unsubscribes an observer from state changes
61
- * @param observer - The observer to unsubscribe
74
+ * Get disposal handler
62
75
  */
63
- unsubscribe(e) {
64
- this._observers.delete(e), this.size === 0 && (d.log("BlacObservable.unsubscribe: No observers left.", this.bloc), this.bloc._consumers.size === 0 && !this.bloc._keepAlive && this.bloc._disposalState === _.ACTIVE && (d.log(
65
- `[${this.bloc._name}:${this.bloc._id}] No observers or consumers left. Scheduling disposal.`
66
- ), this.bloc._scheduleDisposal()));
76
+ getDisposalHandler() {
77
+ return this.disposalHandler;
67
78
  }
68
79
  /**
69
- * Notifies all observers of a state change
70
- * @param newState - The new state value
71
- * @param oldState - The previous state value
72
- * @param action - Optional action that triggered the state change
80
+ * Clear disposal timer
73
81
  */
74
- notify(e, t, s) {
75
- this._observers.forEach((n) => {
76
- let r = !1;
77
- if (n.dependencyArray) {
78
- const o = n.lastState, a = n.dependencyArray(
79
- e,
80
- t,
81
- this.bloc
82
- );
83
- if (!o)
84
- r = !0;
85
- else if (o.length !== a.length)
86
- r = !0;
87
- else
88
- for (let u = 0; u < a.length; u++)
89
- if (!Object.is(o[u], a[u])) {
90
- r = !0;
91
- break;
92
- }
93
- n.lastState = a;
94
- } else
95
- r = !0;
96
- r && n.fn(e, t, s);
97
- });
82
+ clearDisposalTimer() {
83
+ this.disposalTimer && (clearTimeout(this.disposalTimer), this.disposalTimer = void 0);
84
+ }
85
+ }
86
+ class T {
87
+ plugins = /* @__PURE__ */ new Map();
88
+ metrics = /* @__PURE__ */ new Map();
89
+ executionOrder = [];
90
+ /**
91
+ * Add a system plugin
92
+ */
93
+ add(e) {
94
+ if (this.plugins.has(e.name))
95
+ throw new Error(`Plugin '${e.name}' is already registered`);
96
+ this.plugins.set(e.name, e), this.executionOrder.push(e.name), this.initializeMetrics(e.name);
97
+ }
98
+ /**
99
+ * Remove a system plugin
100
+ */
101
+ remove(e) {
102
+ return this.plugins.get(e) ? (this.plugins.delete(e), this.metrics.delete(e), this.executionOrder = this.executionOrder.filter(
103
+ (s) => s !== e
104
+ ), !0) : !1;
98
105
  }
99
106
  /**
100
- * Clears the observer set
107
+ * Get a plugin by name
108
+ */
109
+ get(e) {
110
+ return this.plugins.get(e);
111
+ }
112
+ /**
113
+ * Get all plugins in execution order
114
+ */
115
+ getAll() {
116
+ return this.executionOrder.map((e) => this.plugins.get(e));
117
+ }
118
+ /**
119
+ * Clear all plugins
101
120
  */
102
121
  clear() {
103
- this._observers.clear();
122
+ this.plugins.clear(), this.metrics.clear(), this.executionOrder = [];
104
123
  }
105
- }
106
- function $() {
107
- return typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
108
- const e = Math.random() * 16 | 0;
109
- return (c === "x" ? e : e & 3 | 8).toString(16);
110
- });
111
- }
112
- var _ = /* @__PURE__ */ ((c) => (c.ACTIVE = "active", c.DISPOSAL_REQUESTED = "disposal_requested", c.DISPOSING = "disposing", c.DISPOSED = "disposed", c))(_ || {});
113
- class x {
114
124
  /**
115
- * Creates a new BlocBase instance with the given initial state.
116
- * Sets up the observer, registers with the Blac manager, and initializes addons.
117
- *
118
- * @param initialState The initial state value for this Bloc
125
+ * Execute a hook on all plugins
119
126
  */
120
- constructor(e) {
121
- i(this, "uid", $());
122
- /**
123
- * Defines how dependencies are selected from the state for efficient updates.
124
- * When provided, observers will only be notified when selected dependencies change.
125
- */
126
- i(this, "defaultDependencySelector");
127
- /**
128
- * @internal
129
- * Indicates if this specific Bloc instance is isolated from others of the same type.
130
- */
131
- i(this, "_isolated", !1);
132
- /**
133
- * @internal
134
- * Observable responsible for managing state listeners and notifying consumers.
135
- */
136
- i(this, "_observer");
137
- /**
138
- * The unique identifier for this Bloc instance.
139
- * Defaults to the class name, but can be customized.
140
- */
141
- i(this, "_id");
142
- /**
143
- * @internal
144
- * Reference string used internally for tracking and debugging.
145
- */
146
- i(this, "_instanceRef");
147
- /**
148
- * @internal
149
- * Indicates if this specific Bloc instance should be kept alive when no consumers are present.
150
- */
151
- i(this, "_keepAlive", !1);
152
- /**
153
- * @readonly
154
- * Timestamp when this Bloc instance was created, useful for debugging and performance tracking.
155
- */
156
- i(this, "_createdAt", Date.now());
157
- /**
158
- * @internal
159
- * Atomic disposal state to prevent race conditions
160
- */
161
- i(this, "_disposalState", "active");
162
- /**
163
- * @internal
164
- * Timestamp when disposal was requested (for React Strict Mode grace period)
165
- */
166
- i(this, "_disposalRequestTime", 0);
167
- /**
168
- * @internal
169
- * The current state of the Bloc.
170
- */
171
- i(this, "_state");
172
- /**
173
- * @internal
174
- * The previous state of the Bloc, maintained for comparison and history.
175
- */
176
- i(this, "_oldState");
177
- /**
178
- * Props passed during Bloc instance creation.
179
- * Can be used to configure or parameterize the Bloc's behavior.
180
- */
181
- i(this, "props", null);
182
- /**
183
- * @internal
184
- * Flag to prevent batching race conditions
185
- */
186
- i(this, "_batchingLock", !1);
187
- /**
188
- * @internal
189
- * Pending batched updates
190
- */
191
- i(this, "_pendingUpdates", []);
192
- /**
193
- * @internal
194
- * Map of consumer IDs to their WeakRef objects for proper cleanup
195
- */
196
- i(this, "_consumerRefs", /* @__PURE__ */ new Map());
197
- /**
198
- * @internal
199
- * Validates that all consumer references are still alive
200
- * Removes dead consumers automatically
201
- */
202
- i(this, "_validateConsumers", () => {
203
- const e = [];
204
- for (const [t, s] of this._consumerRefs)
205
- s.deref() === void 0 && e.push(t);
206
- for (const t of e)
207
- this._consumers.delete(t), this._consumerRefs.delete(t);
208
- this._consumers.size === 0 && !this._keepAlive && this._disposalState === "active" && this._scheduleDisposal();
209
- });
210
- /**
211
- * @internal
212
- * Updates the Bloc instance's ID to a new value.
213
- * Only updates if the new ID is defined and different from the current one.
214
- *
215
- * @param id The new ID to assign to this Bloc instance
216
- */
217
- i(this, "_updateId", (e) => {
218
- const t = this._id;
219
- !e || e === t || (this._id = e);
220
- });
221
- /**
222
- * @internal
223
- * Optional function to be called when the Bloc is disposed.
224
- */
225
- i(this, "onDispose");
226
- /**
227
- * @internal
228
- * Set of consumer IDs currently listening to this Bloc's state changes.
229
- */
230
- i(this, "_consumers", /* @__PURE__ */ new Set());
231
- /**
232
- * @internal
233
- * Registers a new consumer to this Bloc instance.
234
- * Notifies the Blac manager that a consumer has been added.
235
- *
236
- * @param consumerId The unique ID of the consumer being added
237
- * @param consumerRef Optional reference to the consumer object for cleanup validation
238
- */
239
- i(this, "_addConsumer", (e, t) => {
240
- var s;
241
- return this._disposalState !== "active" ? !1 : (this._consumers.has(e) || (this._consumers.add(e), t && this._consumerRefs.set(e, new WeakRef(t)), (s = globalThis.Blac) == null || s.log(
242
- `[${this._name}:${this._id}] Consumer added. Total consumers: ${this._consumers.size}`
243
- )), !0);
244
- });
245
- /**
246
- * @internal
247
- * Unregisters a consumer from this Bloc instance.
248
- * Notifies the Blac manager that a consumer has been removed.
249
- *
250
- * @param consumerId The unique ID of the consumer being removed
251
- */
252
- i(this, "_removeConsumer", (e) => {
253
- var t, s;
254
- this._consumers.has(e) && (this._consumers.delete(e), this._consumerRefs.delete(e), (t = globalThis.Blac) == null || t.log(
255
- `[${this._name}:${this._id}] Consumer removed. Remaining consumers: ${this._consumers.size}, keepAlive: ${this._keepAlive}`
256
- ), this._consumers.size === 0 && !this._keepAlive && this._disposalState === "active" && ((s = globalThis.Blac) == null || s.log(
257
- `[${this._name}:${this._id}] No consumers left and not keep-alive. Scheduling disposal.`
258
- ), this._scheduleDisposal()));
259
- });
260
- /**
261
- * @internal
262
- * Handler function for disposal (can be set by Blac manager)
263
- */
264
- i(this, "_disposalHandler");
265
- i(this, "lastUpdate", Date.now());
266
- /**
267
- * @internal
268
- * Flag to indicate if batching is enabled for this bloc
269
- */
270
- i(this, "_batchingEnabled", !1);
271
- /**
272
- * @internal
273
- * Updates the state and notifies all observers of the change.
274
- *
275
- * @param newState The new state to be set
276
- * @param oldState The previous state for comparison
277
- * @param action Optional metadata about what caused the state change
278
- */
279
- i(this, "_pushState", (e, t, s) => {
280
- if (e !== void 0 && !(s !== void 0 && typeof s != "object" && typeof s != "function")) {
281
- if (this._batchingEnabled) {
282
- this._pendingUpdates.push({ newState: e, oldState: t, action: s }), this._oldState = t, this._state = e;
283
- return;
284
- }
285
- this._oldState = t, this._state = e, this._observer.notify(e, t, s), this.lastUpdate = Date.now();
286
- }
287
- });
288
- /**
289
- * Enables batching for multiple state updates
290
- * @param batchFn Function to execute with batching enabled
291
- */
292
- i(this, "batch", (e) => {
293
- if (this._batchingLock)
294
- return e();
295
- this._batchingLock = !0, this._batchingEnabled = !0, this._pendingUpdates = [];
127
+ executeHook(e, t, s) {
128
+ for (const i of this.executionOrder) {
129
+ const n = this.plugins.get(i), a = n[e];
130
+ if (typeof a != "function") continue;
131
+ const c = performance.now();
296
132
  try {
297
- const t = e();
298
- if (this._pendingUpdates.length > 0) {
299
- const s = this._pendingUpdates[this._pendingUpdates.length - 1];
300
- this._observer.notify(
301
- s.newState,
302
- s.oldState,
303
- s.action
304
- ), this.lastUpdate = Date.now();
305
- }
306
- return t;
307
- } finally {
308
- this._batchingEnabled = !1, this._batchingLock = !1, this._pendingUpdates = [];
133
+ a.apply(n, t), this.recordSuccess(i, e, c);
134
+ } catch (l) {
135
+ this.recordError(i, e, l), s ? s(l, n) : console.error(
136
+ `Plugin '${i}' error in hook '${e}':`,
137
+ l
138
+ );
309
139
  }
310
- });
311
- this._state = e, this._observer = new V(this), this._id = this.constructor.name;
312
- const t = this.constructor;
313
- this._keepAlive = typeof t.keepAlive == "boolean" ? t.keepAlive : !1, this._isolated = typeof t.isolated == "boolean" ? t.isolated : !1;
140
+ }
314
141
  }
315
- get isIsolated() {
316
- return this._isolated;
142
+ /**
143
+ * Bootstrap all plugins
144
+ */
145
+ bootstrap() {
146
+ this.executeHook("beforeBootstrap", []), this.executeHook("afterBootstrap", []);
317
147
  }
318
- get isKeepAlive() {
319
- return this._keepAlive;
148
+ /**
149
+ * Shutdown all plugins
150
+ */
151
+ shutdown() {
152
+ this.executeHook("beforeShutdown", []), this.executeHook("afterShutdown", []);
320
153
  }
321
154
  /**
322
- * Returns the current state of the Bloc.
323
- * Use this getter to access the state in a read-only manner.
324
- * Returns the state even during transitional lifecycle states for React compatibility.
155
+ * Notify plugins of bloc creation
325
156
  */
326
- get state() {
327
- return this._disposalState === "disposed" ? this._state : this._state;
157
+ notifyBlocCreated(e) {
158
+ this.executeHook("onBlocCreated", [e]);
328
159
  }
329
160
  /**
330
- * Returns whether this Bloc instance has been disposed.
331
- * @returns true if the bloc is in DISPOSED state
161
+ * Notify plugins of bloc disposal
332
162
  */
333
- get isDisposed() {
334
- return this._disposalState === "disposed";
163
+ notifyBlocDisposed(e) {
164
+ this.executeHook("onBlocDisposed", [e]);
335
165
  }
336
166
  /**
337
- * @internal
338
- * Returns the name of the Bloc class for identification and debugging.
167
+ * Notify plugins of state change
339
168
  */
340
- get _name() {
341
- return this.constructor.name;
169
+ notifyStateChanged(e, t, s) {
170
+ this.executeHook("onStateChanged", [e, t, s]);
342
171
  }
343
172
  /**
344
- * @internal
345
- * Performs atomic state transition using compare-and-swap semantics
346
- * @param expectedState The expected current state
347
- * @param newState The desired new state
348
- * @returns Result indicating success/failure and state information
173
+ * Notify plugins of event addition
349
174
  */
350
- _atomicStateTransition(e, t) {
351
- var s, n, r, o;
352
- if (this._disposalState === e) {
353
- const a = this._disposalState;
354
- return this._disposalState = t, (s = globalThis.Blac) != null && s.enableLog && ((n = globalThis.Blac) == null || n.log(
355
- `[${this._name}:${this._id}] State transition: ${a} -> ${t} (SUCCESS)`
356
- )), {
357
- success: !0,
358
- currentState: t,
359
- previousState: a
360
- };
361
- }
362
- return (r = globalThis.Blac) != null && r.enableLog && ((o = globalThis.Blac) == null || o.log(
363
- `[${this._name}:${this._id}] State transition failed: expected ${e}, current ${this._disposalState}`
364
- )), {
365
- success: !1,
366
- currentState: this._disposalState,
367
- previousState: e
175
+ notifyEventAdded(e, t) {
176
+ this.executeHook("onEventAdded", [e, t]);
177
+ }
178
+ /**
179
+ * Notify plugins of errors
180
+ */
181
+ notifyError(e, t, s) {
182
+ this.executeHook("onError", [e, t, s], (i, n) => {
183
+ console.error(`Plugin '${n.name}' error handler failed:`, i);
184
+ });
185
+ }
186
+ /**
187
+ * Notify plugins of adapter lifecycle events
188
+ */
189
+ notifyAdapterCreated(e, t) {
190
+ this.executeHook("onAdapterCreated", [e, t]);
191
+ }
192
+ notifyAdapterMount(e, t) {
193
+ this.executeHook("onAdapterMount", [e, t]);
194
+ }
195
+ notifyAdapterUnmount(e, t) {
196
+ this.executeHook("onAdapterUnmount", [e, t]);
197
+ }
198
+ notifyAdapterRender(e, t) {
199
+ this.executeHook("onAdapterRender", [e, t]);
200
+ }
201
+ notifyAdapterDisposed(e, t) {
202
+ this.executeHook("onAdapterDisposed", [e, t]);
203
+ }
204
+ /**
205
+ * Get metrics for a plugin
206
+ */
207
+ getMetrics(e) {
208
+ return this.metrics.get(e);
209
+ }
210
+ initializeMetrics(e) {
211
+ this.metrics.set(e, /* @__PURE__ */ new Map());
212
+ }
213
+ recordSuccess(e, t, s) {
214
+ const i = this.metrics.get(e), n = i.get(t) || {
215
+ executionTime: 0,
216
+ executionCount: 0,
217
+ errorCount: 0
218
+ }, a = performance.now() - s;
219
+ i.set(t, {
220
+ ...n,
221
+ executionTime: n.executionTime + a,
222
+ executionCount: n.executionCount + 1,
223
+ lastExecutionTime: a
224
+ });
225
+ }
226
+ recordError(e, t, s) {
227
+ const i = this.metrics.get(e), n = i.get(t) || {
228
+ executionTime: 0,
229
+ executionCount: 0,
230
+ errorCount: 0
368
231
  };
232
+ i.set(t, {
233
+ ...n,
234
+ errorCount: n.errorCount + 1,
235
+ lastError: s
236
+ });
237
+ }
238
+ }
239
+ var v = /* @__PURE__ */ ((r) => (r.LIFECYCLE = "LIFECYCLE", r.STATE = "STATE", r.PLUGIN = "PLUGIN", r.VALIDATION = "VALIDATION", r.DISPOSAL = "DISPOSAL", r.CONSUMER = "CONSUMER", r))(v || {}), y = /* @__PURE__ */ ((r) => (r.FATAL = "FATAL", r.ERROR = "ERROR", r.WARNING = "WARNING", r.INFO = "INFO", r))(y || {});
240
+ class m extends Error {
241
+ constructor(e, t, s, i, n) {
242
+ super(e), this.category = t, this.severity = s, this.context = i, this.cause = n, this.name = "BlacError", Object.setPrototypeOf(this, m.prototype);
243
+ }
244
+ toString() {
245
+ const e = this.context ? ` [${Object.entries(this.context).filter(([t, s]) => s !== void 0).map(([t, s]) => `${t}: ${s}`).join(", ")}]` : "";
246
+ return `${this.name} [${this.severity}/${this.category}]: ${this.message}${e}`;
247
+ }
248
+ }
249
+ const P = {
250
+ shouldPropagate: (r) => r.severity === "FATAL",
251
+ shouldLog: (r) => r.severity !== "INFO",
252
+ handle: (r) => {
253
+ P.shouldLog(r) && console.error(r.toString(), r.cause);
369
254
  }
255
+ };
256
+ class f {
257
+ static instance;
258
+ handlers = /* @__PURE__ */ new Set();
259
+ strategy = P;
370
260
  /**
371
- * @internal
372
- * Cleans up resources and removes this Bloc from the system.
373
- * Notifies the Blac manager and clears all observers.
261
+ * Get the singleton instance of ErrorManager
374
262
  */
375
- _dispose() {
376
- var t;
377
- let e = this._atomicStateTransition(
378
- "active",
379
- "disposing"
380
- /* DISPOSING */
381
- );
382
- if (e.success || (e = this._atomicStateTransition(
383
- "disposal_requested",
384
- "disposing"
385
- /* DISPOSING */
386
- )), !e.success)
387
- return !1;
388
- try {
389
- return this._consumers.clear(), this._consumerRefs.clear(), this._observer.clear(), (t = this.onDispose) == null || t.call(this), this._atomicStateTransition(
390
- "disposing",
391
- "disposed"
392
- /* DISPOSED */
393
- ).success;
394
- } catch (s) {
395
- throw this._disposalState = "active", s;
396
- }
263
+ static getInstance() {
264
+ return f.instance || (f.instance = new f()), f.instance;
397
265
  }
398
266
  /**
399
- * @internal
400
- * Sets the disposal handler for this bloc
267
+ * Set a custom error handling strategy
401
268
  */
402
- _setDisposalHandler(e) {
403
- this._disposalHandler = e;
269
+ setStrategy(e) {
270
+ this.strategy = e;
404
271
  }
405
272
  /**
406
- * @internal
407
- * Schedules disposal of this bloc instance if it has no consumers
408
- * Uses atomic state transitions to prevent race conditions
273
+ * Add a custom error handler that will be called for all errors
409
274
  */
410
- _scheduleDisposal() {
411
- if (!this._atomicStateTransition(
412
- "active",
413
- "disposal_requested"
414
- /* DISPOSAL_REQUESTED */
415
- ).success)
275
+ addHandler(e) {
276
+ this.handlers.add(e);
277
+ }
278
+ /**
279
+ * Remove a previously added error handler
280
+ */
281
+ removeHandler(e) {
282
+ this.handlers.delete(e);
283
+ }
284
+ /**
285
+ * Process an error through all handlers and apply the configured strategy
286
+ */
287
+ handle(e) {
288
+ if (this.handlers.forEach((t) => {
289
+ try {
290
+ t(e);
291
+ } catch (s) {
292
+ console.error("Error in error handler:", s);
293
+ }
294
+ }), this.strategy.handle(e), this.strategy.shouldPropagate(e))
295
+ throw e;
296
+ }
297
+ /**
298
+ * Convenience method for wrapping operations with error handling
299
+ */
300
+ wrap(e, t) {
301
+ try {
302
+ return e();
303
+ } catch (s) {
304
+ const i = t(s);
305
+ this.handle(i);
416
306
  return;
417
- if (!(this._consumers.size === 0 && !this._keepAlive)) {
418
- this._atomicStateTransition(
419
- "disposal_requested",
420
- "active"
421
- /* ACTIVE */
422
- );
307
+ }
308
+ }
309
+ /**
310
+ * Async version of wrap
311
+ */
312
+ async wrapAsync(e, t) {
313
+ try {
314
+ return await e();
315
+ } catch (s) {
316
+ const i = t(s);
317
+ this.handle(i);
423
318
  return;
424
319
  }
425
- this._disposalRequestTime = Date.now(), queueMicrotask(() => {
426
- this._consumers.size === 0 && !this._keepAlive && this._observer.size === 0 && this._disposalState === "disposal_requested" ? this._disposalHandler ? this._disposalHandler(this) : this._dispose() : this._atomicStateTransition(
427
- "disposal_requested",
428
- "active"
429
- /* ACTIVE */
430
- );
431
- });
432
320
  }
433
321
  }
434
- /**
435
- * When true, every consumer will receive its own unique instance of this Bloc.
436
- * Use this when state should not be shared between components.
437
- * @default false
438
- */
439
- i(x, "isolated", !1), /**
440
- * When true, the Bloc instance persists even when there are no active consumers.
441
- * Useful for maintaining state between component unmount/remount cycles.
442
- * @default false
443
- */
444
- i(x, "keepAlive", !1);
445
- const y = class y {
322
+ class g {
323
+ static _instance;
446
324
  getInstance() {
447
- return y._instance || (y._instance = new d({
325
+ return g._instance || (g._instance = new o({
448
326
  __unsafe_ignore_singleton: !0
449
- })), y._instance;
327
+ })), g._instance;
450
328
  }
451
329
  setInstance(e) {
452
- y._instance = e;
330
+ g._instance = e;
453
331
  }
454
332
  resetInstance() {
455
- const e = y._instance;
456
- if (y._instance = new d({
333
+ const e = g._instance;
334
+ if (g._instance = new o({
457
335
  __unsafe_ignore_singleton: !0
458
336
  }), e)
459
337
  for (const t of e.keepAliveBlocs)
460
- y._instance.keepAliveBlocs.add(t), y._instance.uidRegistry.set(t.uid, t);
338
+ g._instance.keepAliveBlocs.add(t), g._instance.uidRegistry.set(t.uid, t);
461
339
  }
462
- };
463
- i(y, "_instance");
464
- let C = y, S = new C();
465
- function q(c) {
466
- S = c;
467
340
  }
468
- const l = class l {
469
- /**
470
- * Creates a new Blac instance.
471
- * @param options - Configuration options including singleton control
472
- */
473
- constructor(e = {}) {
474
- /** Timestamp when the instance was created */
475
- i(this, "createdAt", Date.now());
476
- /** Map storing all registered bloc instances by their class name and ID */
477
- i(this, "blocInstanceMap", /* @__PURE__ */ new Map());
478
- /** Map storing isolated bloc instances grouped by their constructor */
479
- // Using BlocConstructor<BlocBase<unknown>> would break type inference when storing
480
- // different bloc types in the same map. The 'any' allows proper polymorphic storage
481
- // while maintaining type safety at usage sites through the BlocConstructor constraint.
482
- i(this, "isolatedBlocMap", /* @__PURE__ */ new Map());
483
- /** Map for O(1) lookup of isolated blocs by UID */
484
- i(this, "isolatedBlocIndex", /* @__PURE__ */ new Map());
485
- /** Map tracking UIDs to prevent memory leaks */
486
- i(this, "uidRegistry", /* @__PURE__ */ new Map());
487
- /** Set of keep-alive blocs for controlled cleanup */
488
- i(this, "keepAliveBlocs", /* @__PURE__ */ new Set());
489
- /** Flag to control whether changes should be posted to document */
490
- i(this, "postChangesToDocument", !1);
491
- /**
492
- * Logs messages to console when logging is enabled
493
- * @param args - Arguments to log
494
- */
495
- i(this, "log", (...e) => {
496
- l.logSpy && l.logSpy(e), l.enableLog && l.logLevel, l.enableLog && l.logLevel;
497
- });
498
- /**
499
- * Logs a warning message
500
- * @param message - Warning message
501
- * @param args - Additional arguments
502
- */
503
- i(this, "warn", (e, ...t) => {
504
- l.enableLog;
505
- });
506
- /**
507
- * Logs an error message
508
- * @param message - Error message
509
- * @param args - Additional arguments
510
- */
511
- i(this, "error", (e, ...t) => {
512
- l.enableLog;
513
- });
514
- /**
515
- * Resets the Blac instance to a new one, disposing non-keepAlive blocs
516
- * from the old instance.
517
- */
518
- i(this, "resetInstance", () => {
519
- this.log("Reset Blac instance");
520
- const e = new Map(this.blocInstanceMap), t = new Map(this.isolatedBlocMap);
521
- e.forEach((s) => {
522
- !s._keepAlive && s._disposalState === _.ACTIVE && this.disposeBloc(s);
523
- }), t.forEach((s) => {
524
- s.forEach((n) => {
525
- !n._keepAlive && n._disposalState === _.ACTIVE && this.disposeBloc(n);
526
- });
527
- }), this.blocInstanceMap.clear(), this.isolatedBlocMap.clear(), this.isolatedBlocIndex.clear(), S.resetInstance();
528
- });
529
- /**
530
- * Disposes of a bloc instance by removing it from the appropriate registry
531
- * @param bloc - The bloc instance to dispose
532
- */
533
- i(this, "disposeBloc", (e) => {
534
- const t = e._disposalState;
535
- if (![
536
- _.ACTIVE,
537
- _.DISPOSAL_REQUESTED
538
- ].includes(t)) {
539
- this.log(
540
- `[${e._name}:${String(e._id)}] disposeBloc called on bloc in invalid state: ${t}`
541
- );
542
- return;
543
- }
544
- const n = e.constructor, r = this.createBlocInstanceMapKey(e._name, e._id);
545
- this.log(
546
- `[${e._name}:${String(e._id)}] disposeBloc called. Isolated: ${String(n.isolated)}`
547
- ), e._dispose(), n.isolated ? (this.unregisterIsolatedBlocInstance(e), this.blocInstanceMap.delete(r)) : this.unregisterBlocInstance(e), this.log("dispatched bloc", e);
548
- });
549
- i(this, "activateBloc", (e) => {
550
- if (e._disposalState !== _.ACTIVE) {
551
- this.log(
552
- `[${e._name}:${String(e._id)}] activateBloc called on disposed bloc. Ignoring.`
553
- );
554
- return;
555
- }
556
- const t = e.constructor;
557
- (e.isIsolated ? this.findIsolatedBlocInstance(t, e._id) : this.findRegisteredBlocInstance(t, e._id)) || (this.log(
558
- `[${e._name}:${String(e._id)}] activateBloc called. Isolated: ${String(e.isIsolated)}`
559
- ), e.isIsolated ? this.registerIsolatedBlocInstance(e) : this.registerBlocInstance(e));
560
- });
561
- /**
562
- * Gets or creates a bloc instance based on the provided class and options.
563
- * If a bloc with the given ID exists, it will be returned. Otherwise, a new instance will be created.
564
- *
565
- * @param blocClass - The bloc class to get or create
566
- * @param options - Options including:
567
- * - id: The instance ID (defaults to class name if not provided)
568
- * - props: Properties to pass to the bloc constructor
569
- * - instanceRef: Optional reference string for the instance
570
- * @returns The bloc instance
571
- */
572
- i(this, "getBloc", (e, t = {}) => {
573
- const { id: s, forceNewInstance: n } = t, r = e, o = s ?? e.name;
574
- if (this.log(`[${e.name}:${String(o)}] (getBloc) Called:`, {
575
- options: t,
576
- base: r
577
- }), !n)
578
- if (r.isolated) {
579
- const u = this.findIsolatedBlocInstance(
580
- e,
581
- t.instanceRef ?? o
582
- );
583
- if (u)
584
- return u;
585
- if (t.throwIfNotFound)
586
- throw new Error(`Isolated bloc ${e.name} not found`);
587
- } else {
588
- const u = this.findRegisteredBlocInstance(
589
- e,
590
- o
591
- );
592
- if (u)
593
- return u;
594
- if (t.throwIfNotFound)
595
- throw new Error(`Registered bloc ${e.name} not found`);
596
- }
597
- const a = this.createNewBlocInstance(e, o, t);
598
- if (this.log(
599
- `[${e.name}:${String(o)}] (getBloc) No existing instance found. Creating new one.`,
600
- t,
601
- a
602
- ), !a)
603
- throw new Error(
604
- `[getBloc] Failed to create bloc instance for ${e.name}. This should never happen.`
605
- );
606
- return a;
607
- });
608
- /**
609
- * Gets a bloc instance or throws an error if it doesn't exist
610
- * @param blocClass - The bloc class to get
611
- * @param options - Options including:
612
- * - id: The instance ID (defaults to class name if not provided)
613
- * - props: Properties to pass to the bloc constructor
614
- * - instanceRef: Optional reference string for the instance
615
- */
616
- i(this, "getBlocOrThrow", (e, t = {}) => {
617
- const s = e.isolated, n = t.id || e.name, r = s ? this.findIsolatedBlocInstance(e, n) : this.findRegisteredBlocInstance(e, n);
618
- if (r)
619
- return r;
620
- throw new Error(`Bloc ${e.name} not found`);
621
- });
622
- /**
623
- * Gets all instances of a specific bloc class
624
- * @param blocClass - The bloc class to search for
625
- * @param options - Options including:
626
- * - searchIsolated: Whether to search in isolated blocs (defaults to bloc's isolated property)
627
- * @returns Array of matching bloc instances
628
- */
629
- i(this, "getAllBlocs", (e, t = {}) => {
630
- const s = [];
631
- if (this.blocInstanceMap.forEach((n) => {
632
- n.constructor === e && s.push(n);
633
- }), t.searchIsolated !== !1) {
634
- const n = this.isolatedBlocMap.get(e);
635
- n && s.push(...n.map((r) => r));
636
- }
637
- return s;
638
- });
639
- /**
640
- * Disposes all keep-alive blocs of a specific type
641
- * @param blocClass - The bloc class to dispose
642
- */
643
- i(this, "disposeKeepAliveBlocs", (e) => {
644
- const t = [];
645
- for (const s of this.keepAliveBlocs)
646
- (!e || s.constructor === e) && t.push(s);
647
- t.forEach((s) => s._dispose());
648
- });
649
- /**
650
- * Disposes all blocs matching a pattern
651
- * @param predicate - Function to test each bloc for disposal
652
- */
653
- i(this, "disposeBlocs", (e) => {
654
- const t = [];
655
- for (const s of this.blocInstanceMap.values())
656
- e(s) && t.push(s);
657
- for (const s of this.isolatedBlocMap.values())
658
- for (const n of s)
659
- e(n) && t.push(n);
660
- t.forEach((s) => s._dispose());
661
- });
662
- /**
663
- * Gets memory usage statistics for debugging
664
- */
665
- i(this, "getMemoryStats", () => ({
666
- totalBlocs: this.uidRegistry.size,
667
- registeredBlocs: this.blocInstanceMap.size,
668
- isolatedBlocs: Array.from(this.isolatedBlocMap.values()).reduce(
669
- (e, t) => e + t.length,
670
- 0
671
- ),
672
- keepAliveBlocs: this.keepAliveBlocs.size,
673
- isolatedBlocTypes: this.isolatedBlocMap.size
674
- }));
675
- /**
676
- * Validates consumer references and cleans up orphaned consumers
677
- */
678
- i(this, "validateConsumers", () => {
679
- for (const e of this.uidRegistry.values())
680
- e._validateConsumers(), e._consumers.size === 0 && !e._keepAlive && e._disposalState === _.ACTIVE && setTimeout(() => {
681
- e._consumers.size === 0 && !e._keepAlive && e._disposalState === _.ACTIVE && this.disposeBloc(e);
682
- }, 1e3);
683
- });
684
- const { __unsafe_ignore_singleton: t = !1 } = e;
685
- if (!t)
686
- return l.instance;
687
- S.setInstance(this);
688
- }
341
+ let b = new g();
342
+ function H(r) {
343
+ b = r;
344
+ }
345
+ class o {
689
346
  static get instance() {
690
- return S.getInstance();
347
+ return b.getInstance();
691
348
  }
349
+ /** Timestamp when the instance was created */
350
+ createdAt = Date.now();
351
+ errorManager = f.getInstance();
692
352
  static get getAllBlocs() {
693
- return l.instance.getAllBlocs;
353
+ return o.instance.getAllBlocs;
694
354
  }
355
+ /** Private static configuration */
356
+ static _config = {
357
+ proxyDependencyTracking: !0
358
+ };
695
359
  /** Get current configuration */
696
360
  static get config() {
697
361
  return { ...this._config };
@@ -702,174 +366,1106 @@ const l = class l {
702
366
  * @throws Error if configuration is invalid
703
367
  */
704
368
  static setConfig(e) {
705
- if (e.proxyDependencyTracking !== void 0 && typeof e.proxyDependencyTracking != "boolean")
706
- throw new Error("BlacConfig.proxyDependencyTracking must be a boolean");
707
- if (e.exposeBlacInstance !== void 0 && typeof e.exposeBlacInstance != "boolean")
708
- throw new Error("BlacConfig.exposeBlacInstance must be a boolean");
369
+ if (e.proxyDependencyTracking !== void 0 && typeof e.proxyDependencyTracking != "boolean") {
370
+ const t = new m(
371
+ "BlacConfig.proxyDependencyTracking must be a boolean",
372
+ v.VALIDATION,
373
+ y.FATAL
374
+ );
375
+ this.instance.errorManager.handle(t);
376
+ }
709
377
  this._config = {
710
378
  ...this._config,
711
379
  ...e
712
380
  }, this.enableLog && this.instance.log("Blac config updated:", this._config);
713
381
  }
382
+ /** Map storing all registered bloc instances by their class name and ID */
383
+ blocInstanceMap = /* @__PURE__ */ new Map();
384
+ /** Map storing isolated bloc instances grouped by their constructor */
385
+ // Using BlocConstructor<BlocBase<unknown>> would break type inference when storing
386
+ // different bloc types in the same map. The 'any' allows proper polymorphic storage
387
+ // while maintaining type safety at usage sites through the BlocConstructor constraint.
388
+ isolatedBlocMap = /* @__PURE__ */ new Map();
389
+ /** Map for O(1) lookup of isolated blocs by UID */
390
+ isolatedBlocIndex = /* @__PURE__ */ new Map();
391
+ /** Map tracking UIDs to prevent memory leaks */
392
+ uidRegistry = /* @__PURE__ */ new Map();
393
+ /** Set of keep-alive blocs for controlled cleanup */
394
+ keepAliveBlocs = /* @__PURE__ */ new Set();
395
+ /** Flag to control whether changes should be posted to document */
396
+ postChangesToDocument = !1;
397
+ /** System plugin registry */
398
+ plugins = new T();
399
+ /**
400
+ * Creates a new Blac instance.
401
+ * @param options - Configuration options including singleton control
402
+ */
403
+ constructor(e = {}) {
404
+ const { __unsafe_ignore_singleton: t = !1 } = e;
405
+ if (!t)
406
+ return o.instance;
407
+ b.setInstance(this), this.plugins.bootstrap();
408
+ }
409
+ /** Flag to enable/disable logging */
410
+ static enableLog = !1;
411
+ static logLevel = "warn";
412
+ static logSpy = null;
413
+ /**
414
+ * Logs messages to console when logging is enabled
415
+ * @param args - Arguments to log
416
+ */
417
+ log = (...e) => {
418
+ o.logSpy && o.logSpy(e), o.enableLog && o.logLevel, o.enableLog && o.logLevel;
419
+ };
714
420
  static get log() {
715
- return l.instance.log;
421
+ return o.instance.log;
716
422
  }
717
423
  /**
718
424
  * Gets the current Blac instance
719
425
  * @returns The Blac instance
720
426
  */
721
427
  static getInstance() {
722
- return S.getInstance();
428
+ return b.getInstance();
723
429
  }
430
+ /**
431
+ * Logs a warning message
432
+ * @param message - Warning message
433
+ * @param args - Additional arguments
434
+ */
435
+ warn = (e, ...t) => {
436
+ console.warn(e, ...t);
437
+ };
724
438
  static get warn() {
725
- return l.instance.warn;
439
+ return o.instance.warn;
726
440
  }
441
+ /**
442
+ * Logs an error message
443
+ * @param message - Error message
444
+ * @param args - Additional arguments
445
+ */
446
+ error = (e, ...t) => {
447
+ o.enableLog && console.error(e, ...t);
448
+ };
727
449
  static get error() {
728
- return l.instance.error;
450
+ return o.instance.error;
729
451
  }
452
+ /**
453
+ * Resets the Blac instance to a new one, disposing non-keepAlive blocs
454
+ * from the old instance.
455
+ */
456
+ resetInstance = () => {
457
+ this.log("Reset Blac instance");
458
+ const e = new Map(this.blocInstanceMap), t = new Map(this.isolatedBlocMap);
459
+ e.forEach((s) => {
460
+ !s._keepAlive && s._disposalState === u.ACTIVE && this.disposeBloc(s);
461
+ }), t.forEach((s) => {
462
+ s.forEach((i) => {
463
+ !i._keepAlive && i._disposalState === u.ACTIVE && this.disposeBloc(i);
464
+ });
465
+ }), this.blocInstanceMap.clear(), this.isolatedBlocMap.clear(), this.isolatedBlocIndex.clear(), b.resetInstance();
466
+ };
467
+ static resetInstance = () => {
468
+ b.resetInstance();
469
+ };
470
+ /**
471
+ * Disposes of a bloc instance by removing it from the appropriate registry
472
+ * @param bloc - The bloc instance to dispose
473
+ */
474
+ disposeBloc = (e) => {
475
+ const t = e._disposalState;
476
+ if (![
477
+ u.ACTIVE,
478
+ u.DISPOSAL_REQUESTED
479
+ ].includes(t)) {
480
+ this.log(
481
+ `[${e._name}:${String(e._id)}] disposeBloc called on bloc in invalid state: ${t}`
482
+ );
483
+ return;
484
+ }
485
+ const i = e.constructor, n = this.createBlocInstanceMapKey(e._name, e._id);
486
+ this.log(
487
+ `[${e._name}:${String(e._id)}] disposeBloc called. Isolated: ${String(i.isolated)}`
488
+ ), e.dispose(), this.plugins.notifyBlocDisposed(e), i.isolated ? (this.unregisterIsolatedBlocInstance(e), this.blocInstanceMap.delete(n)) : this.unregisterBlocInstance(e), this.log("dispatched bloc", e);
489
+ };
730
490
  static get disposeBloc() {
731
- return l.instance.disposeBloc;
491
+ return o.instance.disposeBloc;
492
+ }
493
+ /**
494
+ * Creates a unique key for a bloc instance in the map based on the bloc class name and instance ID
495
+ * @param blocClassName - The name of the bloc class
496
+ * @param id - The instance ID
497
+ * @returns A unique key string in the format "className:id"
498
+ */
499
+ createBlocInstanceMapKey(e, t) {
500
+ return `${e}:${String(t)}`;
501
+ }
502
+ /**
503
+ * Unregister a bloc instance from the main registry
504
+ * @param bloc - The bloc instance to unregister
505
+ */
506
+ unregisterBlocInstance(e) {
507
+ const t = this.createBlocInstanceMapKey(e._name, e._id);
508
+ this.blocInstanceMap.delete(t), this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e);
509
+ }
510
+ /**
511
+ * Registers a bloc instance in the main registry
512
+ * @param bloc - The bloc instance to register
513
+ */
514
+ registerBlocInstance(e) {
515
+ const t = this.createBlocInstanceMapKey(e._name, e._id);
516
+ this.blocInstanceMap.set(t, e), this.uidRegistry.set(e.uid, e), e._keepAlive && this.keepAliveBlocs.add(e);
517
+ }
518
+ /**
519
+ * Finds a registered bloc instance by its class and ID
520
+ * @param blocClass - The bloc class to search for
521
+ * @param id - The instance ID
522
+ * @returns The found bloc instance or undefined if not found
523
+ */
524
+ findRegisteredBlocInstance(e, t) {
525
+ if (e.isolated) return;
526
+ const i = this.createBlocInstanceMapKey(e.name, t), n = this.blocInstanceMap.get(i);
527
+ if (!(n && n.isDisposed))
528
+ return n;
529
+ }
530
+ /**
531
+ * Registers an isolated bloc instance in the isolated registry
532
+ * @param bloc - The isolated bloc instance to register
533
+ */
534
+ registerIsolatedBlocInstance(e) {
535
+ const t = e.constructor, s = this.isolatedBlocMap.get(t);
536
+ s ? s.push(e) : this.isolatedBlocMap.set(t, [e]), this.isolatedBlocIndex.set(e.uid, e), this.uidRegistry.set(e.uid, e), e._keepAlive && this.keepAliveBlocs.add(e);
537
+ }
538
+ /**
539
+ * Unregister an isolated bloc instance from the isolated registry
540
+ * @param bloc - The isolated bloc instance to unregister
541
+ */
542
+ unregisterIsolatedBlocInstance(e) {
543
+ const t = e.constructor, s = this.isolatedBlocMap.get(t);
544
+ let i = !1;
545
+ if (s) {
546
+ const a = s.findIndex((c) => c.uid === e.uid);
547
+ a !== -1 && (s.splice(a, 1), i = !0), s.length === 0 && this.isolatedBlocMap.delete(t);
548
+ }
549
+ const n = this.isolatedBlocIndex.delete(e.uid);
550
+ this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e), i !== n && this.warn(
551
+ `[Blac] Inconsistent state detected during isolated bloc cleanup for ${e._name}:${e.uid}. Map removal: ${i}, Index removal: ${n}`
552
+ );
553
+ }
554
+ /**
555
+ * Finds an isolated bloc instance by its class and ID (O(n) lookup)
556
+ */
557
+ findIsolatedBlocInstance(e, t) {
558
+ if (!e.isolated) return;
559
+ const i = this.isolatedBlocMap.get(e);
560
+ return i ? i.find((a) => a._id === t && !a.isDisposed) : void 0;
561
+ }
562
+ /**
563
+ * Finds an isolated bloc instance by UID (O(1) lookup)
564
+ */
565
+ findIsolatedBlocInstanceByUid(e) {
566
+ return this.isolatedBlocIndex.get(e);
567
+ }
568
+ /**
569
+ * Creates a new bloc instance and registers it in the appropriate registry
570
+ * @param blocClass - The bloc class to instantiate
571
+ * @param id - The instance ID
572
+ * @param props - Properties to pass to the bloc constructor
573
+ * @param instanceRef - Optional reference string for the instance
574
+ * @returns The newly created bloc instance
575
+ */
576
+ createNewBlocInstance(e, t, s = {}) {
577
+ const { constructorParams: i, instanceRef: n } = s, a = new e(i);
578
+ return a.blacInstance = this, a._instanceRef = n, a._id = t, a.setDisposalHandler((c) => this.disposeBloc(c)), a.isIsolated ? this.registerIsolatedBlocInstance(a) : this.registerBlocInstance(a), this.plugins.notifyBlocCreated(a), a;
579
+ }
580
+ activateBloc = (e) => {
581
+ if (e._disposalState !== u.ACTIVE) {
582
+ this.log(
583
+ `[${e._name}:${String(e._id)}] activateBloc called on disposed bloc. Ignoring.`
584
+ );
585
+ return;
586
+ }
587
+ const t = e.constructor;
588
+ (e.isIsolated ? this.findIsolatedBlocInstance(t, e._id) : this.findRegisteredBlocInstance(t, e._id)) || (this.log(
589
+ `[${e._name}:${String(e._id)}] activateBloc called. Isolated: ${String(e.isIsolated)}`
590
+ ), e.isIsolated ? this.registerIsolatedBlocInstance(e) : this.registerBlocInstance(e));
591
+ };
592
+ static get activateBloc() {
593
+ return o.instance.activateBloc;
594
+ }
595
+ /**
596
+ * Gets or creates a bloc instance based on the provided class and options.
597
+ * If a bloc with the given ID exists, it will be returned. Otherwise, a new instance will be created.
598
+ *
599
+ * @param blocClass - The bloc class to get or create
600
+ * @param options - Options including:
601
+ * - id: The instance ID (defaults to class name if not provided)
602
+ * - props: Properties to pass to the bloc constructor
603
+ * - instanceRef: Optional reference string for the instance
604
+ * @returns The bloc instance
605
+ */
606
+ getBloc = (e, t = {}) => {
607
+ const { id: s, forceNewInstance: i } = t, n = e, a = s ?? e.name;
608
+ if (this.log(`[${e.name}:${String(a)}] (getBloc) Called:`, {
609
+ options: t,
610
+ base: n
611
+ }), !i)
612
+ if (n.isolated) {
613
+ const l = this.findIsolatedBlocInstance(
614
+ e,
615
+ t.instanceRef ?? a
616
+ );
617
+ if (l)
618
+ return l;
619
+ if (t.throwIfNotFound)
620
+ throw new Error(`Isolated bloc ${e.name} not found`);
621
+ } else {
622
+ const l = this.findRegisteredBlocInstance(
623
+ e,
624
+ a
625
+ );
626
+ if (l)
627
+ return l;
628
+ if (t.throwIfNotFound)
629
+ throw new Error(`Registered bloc ${e.name} not found`);
630
+ }
631
+ const c = this.createNewBlocInstance(e, a, t);
632
+ if (this.log(
633
+ `[${e.name}:${String(a)}] (getBloc) No existing instance found. Creating new one.`,
634
+ t,
635
+ c
636
+ ), !c)
637
+ throw new Error(
638
+ `[getBloc] Failed to create bloc instance for ${e.name}. This should never happen.`
639
+ );
640
+ return c;
641
+ };
642
+ static get getBloc() {
643
+ return o.instance.getBloc;
644
+ }
645
+ /**
646
+ * Gets all instances of a specific bloc class
647
+ * @param blocClass - The bloc class to search for
648
+ * @param options - Options including:
649
+ * - searchIsolated: Whether to search in isolated blocs (defaults to bloc's isolated property)
650
+ * @returns Array of matching bloc instances
651
+ */
652
+ getAllBlocs = (e, t = {}) => {
653
+ const s = [];
654
+ if (this.blocInstanceMap.forEach((i) => {
655
+ i.constructor === e && s.push(i);
656
+ }), t.searchIsolated !== !1) {
657
+ const i = this.isolatedBlocMap.get(e);
658
+ i && s.push(...i.map((n) => n));
659
+ }
660
+ return s;
661
+ };
662
+ /**
663
+ * Disposes all keep-alive blocs of a specific type
664
+ * @param blocClass - The bloc class to dispose
665
+ */
666
+ disposeKeepAliveBlocs = (e) => {
667
+ const t = [];
668
+ for (const s of this.keepAliveBlocs)
669
+ (!e || s.constructor === e) && t.push(s);
670
+ t.forEach((s) => s.dispose());
671
+ };
672
+ static get disposeKeepAliveBlocs() {
673
+ return o.instance.disposeKeepAliveBlocs;
674
+ }
675
+ /**
676
+ * Disposes all blocs matching a pattern
677
+ * @param predicate - Function to test each bloc for disposal
678
+ */
679
+ disposeBlocs = (e) => {
680
+ const t = [];
681
+ for (const s of this.blocInstanceMap.values())
682
+ e(s) && t.push(s);
683
+ for (const s of this.isolatedBlocMap.values())
684
+ for (const i of s)
685
+ e(i) && t.push(i);
686
+ t.forEach((s) => s.dispose());
687
+ };
688
+ static get disposeBlocs() {
689
+ return o.instance.disposeBlocs;
690
+ }
691
+ /**
692
+ * Gets memory usage statistics for debugging
693
+ */
694
+ getMemoryStats = () => ({
695
+ totalBlocs: this.uidRegistry.size,
696
+ registeredBlocs: this.blocInstanceMap.size,
697
+ isolatedBlocs: Array.from(this.isolatedBlocMap.values()).reduce(
698
+ (e, t) => e + t.length,
699
+ 0
700
+ ),
701
+ keepAliveBlocs: this.keepAliveBlocs.size,
702
+ isolatedBlocTypes: this.isolatedBlocMap.size
703
+ });
704
+ static get getMemoryStats() {
705
+ return o.instance.getMemoryStats;
706
+ }
707
+ /**
708
+ * Validates subscription references and cleans up orphaned blocs
709
+ */
710
+ validateConsumers = () => {
711
+ for (const e of this.uidRegistry.values())
712
+ e.subscriptionCount === 0 && !e._keepAlive && e._disposalState === u.ACTIVE && setTimeout(() => {
713
+ e.subscriptionCount === 0 && !e._keepAlive && e._disposalState === u.ACTIVE && this.disposeBloc(e);
714
+ }, 1e3);
715
+ };
716
+ static get validateConsumers() {
717
+ return o.instance.validateConsumers;
718
+ }
719
+ /**
720
+ * Bootstrap the Blac instance and all plugins
721
+ */
722
+ bootstrap() {
723
+ this.plugins.bootstrap();
724
+ }
725
+ /**
726
+ * Shutdown the Blac instance and all plugins
727
+ */
728
+ shutdown() {
729
+ this.plugins.shutdown();
730
+ for (const e of this.blocInstanceMap.values())
731
+ e._keepAlive || this.disposeBloc(e);
732
+ for (const e of this.isolatedBlocMap.values())
733
+ for (const t of e)
734
+ t._keepAlive || this.disposeBloc(t);
735
+ }
736
+ }
737
+ function A() {
738
+ return typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(r) {
739
+ const e = Math.random() * 16 | 0;
740
+ return (r === "x" ? e : e & 3 | 8).toString(16);
741
+ });
742
+ }
743
+ const x = {
744
+ fatal: (r, e, t, s) => {
745
+ const i = new m(
746
+ r,
747
+ e,
748
+ y.FATAL,
749
+ t,
750
+ s
751
+ );
752
+ throw f.getInstance().handle(i), i;
753
+ },
754
+ error: (r, e, t, s) => {
755
+ const i = new m(
756
+ r,
757
+ e,
758
+ y.ERROR,
759
+ t,
760
+ s
761
+ );
762
+ f.getInstance().handle(i);
763
+ },
764
+ warn: (r, e, t, s) => {
765
+ const i = new m(
766
+ r,
767
+ e,
768
+ y.WARNING,
769
+ t,
770
+ s
771
+ );
772
+ f.getInstance().handle(i);
773
+ },
774
+ info: (r, e, t) => {
775
+ const s = new m(r, e, y.INFO, t);
776
+ f.getInstance().handle(s);
777
+ },
778
+ /**
779
+ * Wraps a function to catch and handle errors
780
+ */
781
+ wrap: (r, e, t, s = y.ERROR) => {
782
+ try {
783
+ return r();
784
+ } catch (i) {
785
+ const n = i instanceof Error ? i.message : String(i), a = new m(n, e, s, t, i);
786
+ f.getInstance().handle(a);
787
+ return;
788
+ }
789
+ },
790
+ /**
791
+ * Wraps an async function to catch and handle errors
792
+ */
793
+ wrapAsync: async (r, e, t, s = y.ERROR) => {
794
+ try {
795
+ return await r();
796
+ } catch (i) {
797
+ const n = i instanceof Error ? i.message : String(i), a = new m(n, e, s, t, i);
798
+ f.getInstance().handle(a);
799
+ return;
800
+ }
801
+ }
802
+ };
803
+ class w {
804
+ plugins = /* @__PURE__ */ new Map();
805
+ executionOrder = [];
806
+ attached = !1;
807
+ /**
808
+ * Add a bloc plugin
809
+ */
810
+ add(e) {
811
+ if (this.plugins.has(e.name))
812
+ throw new Error(`Plugin '${e.name}' is already registered`);
813
+ e.capabilities && this.validateCapabilities(e), this.plugins.set(e.name, e), this.executionOrder.push(e.name);
814
+ }
815
+ /**
816
+ * Remove a bloc plugin
817
+ */
818
+ remove(e) {
819
+ const t = this.plugins.get(e);
820
+ return t ? (this.attached && t.onDetach && x.wrap(() => t.onDetach(), v.PLUGIN, {
821
+ pluginName: e,
822
+ operation: "onDetach"
823
+ }), this.plugins.delete(e), this.executionOrder = this.executionOrder.filter(
824
+ (s) => s !== e
825
+ ), !0) : !1;
826
+ }
827
+ /**
828
+ * Get a plugin by name
829
+ */
830
+ get(e) {
831
+ return this.plugins.get(e);
832
+ }
833
+ /**
834
+ * Get all plugins in execution order
835
+ */
836
+ getAll() {
837
+ return this.executionOrder.map((e) => this.plugins.get(e));
838
+ }
839
+ /**
840
+ * Clear all plugins
841
+ */
842
+ clear() {
843
+ if (this.attached)
844
+ for (const e of this.getAll())
845
+ e.onDetach && x.wrap(() => e.onDetach(), v.PLUGIN, {
846
+ pluginName: e.name,
847
+ operation: "onDetach"
848
+ });
849
+ this.plugins.clear(), this.executionOrder = [], this.attached = !1;
850
+ }
851
+ /**
852
+ * Attach all plugins to a bloc
853
+ */
854
+ attach(e) {
855
+ if (this.attached)
856
+ throw new Error("Plugins are already attached");
857
+ for (const t of this.getAll())
858
+ if (t.onAttach)
859
+ try {
860
+ t.onAttach(e);
861
+ } catch (s) {
862
+ console.error(`Plugin '${t.name}' error in onAttach:`, s), this.remove(t.name);
863
+ }
864
+ this.attached = !0;
865
+ }
866
+ /**
867
+ * Transform state through all plugins
868
+ */
869
+ transformState(e, t) {
870
+ let s = t;
871
+ for (const i of this.getAll())
872
+ if (i.transformState && this.canTransformState(i))
873
+ try {
874
+ s = i.transformState(
875
+ e,
876
+ s
877
+ );
878
+ } catch (n) {
879
+ console.error(
880
+ `Plugin '${i.name}' error in transformState:`,
881
+ n
882
+ );
883
+ }
884
+ return s;
885
+ }
886
+ /**
887
+ * Transform event through all plugins
888
+ */
889
+ transformEvent(e) {
890
+ let t = e;
891
+ for (const s of this.getAll()) {
892
+ if (t === null) break;
893
+ if (s.transformEvent && this.canInterceptEvents(s))
894
+ try {
895
+ t = s.transformEvent(t);
896
+ } catch (i) {
897
+ console.error(
898
+ `Plugin '${s.name}' error in transformEvent:`,
899
+ i
900
+ );
901
+ }
902
+ }
903
+ return t;
904
+ }
905
+ /**
906
+ * Notify plugins of state change
907
+ */
908
+ notifyStateChange(e, t) {
909
+ for (const s of this.getAll())
910
+ if (s.onStateChange && this.canReadState(s))
911
+ try {
912
+ s.onStateChange(e, t);
913
+ } catch (i) {
914
+ console.error(
915
+ `Plugin '${s.name}' error in onStateChange:`,
916
+ i
917
+ );
918
+ }
919
+ }
920
+ /**
921
+ * Notify plugins of event
922
+ */
923
+ notifyEvent(e) {
924
+ for (const t of this.getAll())
925
+ if (t.onEvent && this.canReadState(t))
926
+ try {
927
+ t.onEvent(e);
928
+ } catch (s) {
929
+ console.error(`Plugin '${t.name}' error in onEvent:`, s);
930
+ }
931
+ }
932
+ /**
933
+ * Notify plugins of error
934
+ */
935
+ notifyError(e, t) {
936
+ for (const s of this.getAll())
937
+ if (s.onError)
938
+ try {
939
+ s.onError(e, t);
940
+ } catch (i) {
941
+ console.error(`Plugin '${s.name}' error in onError:`, i);
942
+ }
943
+ }
944
+ validateCapabilities(e) {
945
+ const t = e.capabilities;
946
+ if (t.transformState && !t.readState)
947
+ throw new Error(
948
+ `Plugin '${e.name}': transformState requires readState capability`
949
+ );
950
+ if (t.interceptEvents && !t.readState)
951
+ throw new Error(
952
+ `Plugin '${e.name}': interceptEvents requires readState capability`
953
+ );
954
+ }
955
+ canReadState(e) {
956
+ return !e.capabilities || e.capabilities.readState !== !1;
957
+ }
958
+ canTransformState(e) {
959
+ return !e.capabilities || e.capabilities.transformState === !0;
960
+ }
961
+ canInterceptEvents(e) {
962
+ return !e.capabilities || e.capabilities.interceptEvents === !0;
963
+ }
964
+ }
965
+ class E {
966
+ constructor(e) {
967
+ this.bloc = e;
968
+ }
969
+ subscriptions = /* @__PURE__ */ new Map();
970
+ pathToSubscriptions = /* @__PURE__ */ new Map();
971
+ weakRefCleanupScheduled = !1;
972
+ totalNotifications = 0;
973
+ /**
974
+ * Subscribe to state changes
975
+ */
976
+ subscribe(e) {
977
+ const t = `${e.type}-${A()}`, s = {
978
+ id: t,
979
+ type: e.type,
980
+ selector: e.selector,
981
+ equalityFn: e.equalityFn || Object.is,
982
+ notify: e.notify,
983
+ priority: e.priority ?? 0,
984
+ weakRef: e.weakRef,
985
+ dependencies: /* @__PURE__ */ new Set(),
986
+ metadata: {
987
+ lastNotified: Date.now(),
988
+ hasRendered: !1,
989
+ accessCount: 0,
990
+ firstAccessTime: Date.now()
991
+ }
992
+ };
993
+ if (s.selector)
994
+ try {
995
+ s.lastValue = s.selector(
996
+ this.bloc.state,
997
+ this.bloc
998
+ );
999
+ } catch (i) {
1000
+ o.error(`SubscriptionManager: Error in selector for ${t}:`, i);
1001
+ }
1002
+ return this.subscriptions.set(t, s), o.log(
1003
+ `[${this.bloc._name}:${this.bloc._id}] Subscription added: ${t}. Total: ${this.subscriptions.size}`
1004
+ ), this.bloc._cancelDisposalIfRequested(), () => this.unsubscribe(t);
1005
+ }
1006
+ /**
1007
+ * Unsubscribe by ID
1008
+ */
1009
+ unsubscribe(e) {
1010
+ const t = this.subscriptions.get(e);
1011
+ if (t) {
1012
+ if (t.dependencies)
1013
+ for (const s of t.dependencies) {
1014
+ const i = this.pathToSubscriptions.get(s);
1015
+ i && (i.delete(e), i.size === 0 && this.pathToSubscriptions.delete(s));
1016
+ }
1017
+ this.subscriptions.delete(e), o.log(
1018
+ `[${this.bloc._name}:${this.bloc._id}] Subscription removed: ${e}. Remaining: ${this.subscriptions.size}`
1019
+ ), this.bloc.checkDisposal();
1020
+ }
1021
+ }
1022
+ /**
1023
+ * Notify all subscriptions of state change
1024
+ */
1025
+ notify(e, t, s) {
1026
+ this.cleanupDeadReferences();
1027
+ const i = Array.from(this.subscriptions.values()).sort(
1028
+ (n, a) => (a.priority ?? 0) - (n.priority ?? 0)
1029
+ );
1030
+ for (const n of i) {
1031
+ if (n.weakRef && !n.weakRef.deref()) {
1032
+ this.scheduleWeakRefCleanup();
1033
+ continue;
1034
+ }
1035
+ let a = !1, c, l;
1036
+ if (n.selector)
1037
+ try {
1038
+ c = n.selector(e, this.bloc), l = n.lastValue, a = !(n.equalityFn || Object.is)(l, c), a && (n.lastValue = c);
1039
+ } catch (h) {
1040
+ o.error(
1041
+ `SubscriptionManager: Error in selector for ${n.id}:`,
1042
+ h
1043
+ );
1044
+ continue;
1045
+ }
1046
+ else {
1047
+ if (n.dependencies && n.dependencies.size > 0) {
1048
+ const h = this.getChangedPaths(t, e);
1049
+ a = this.shouldNotifyForPaths(
1050
+ n.id,
1051
+ h
1052
+ ), o.config.logLevel === "debug" && (o.log(
1053
+ `[SubscriptionManager] Subscription ${n.id} dependencies:`,
1054
+ Array.from(n.dependencies)
1055
+ ), o.log(
1056
+ "[SubscriptionManager] Changed paths:",
1057
+ Array.from(h)
1058
+ ), o.log("[SubscriptionManager] Should notify:", a));
1059
+ } else
1060
+ a = !0;
1061
+ c = e, l = t;
1062
+ }
1063
+ if (a)
1064
+ try {
1065
+ n.notify(c, l, s), this.totalNotifications++, n.metadata && (n.metadata.lastNotified = Date.now(), n.metadata.hasRendered = !0);
1066
+ } catch (h) {
1067
+ o.error(
1068
+ `SubscriptionManager: Error in notify for ${n.id}:`,
1069
+ h
1070
+ );
1071
+ }
1072
+ }
1073
+ }
1074
+ /**
1075
+ * Track a path access for a subscription
1076
+ */
1077
+ trackAccess(e, t, s) {
1078
+ const i = this.subscriptions.get(e);
1079
+ if (!i) return;
1080
+ i.dependencies || (i.dependencies = /* @__PURE__ */ new Set()), i.dependencies.add(t);
1081
+ let n = this.pathToSubscriptions.get(t);
1082
+ n || (n = /* @__PURE__ */ new Set(), this.pathToSubscriptions.set(t, n)), n.add(e), i.metadata && (i.metadata.accessCount = (i.metadata.accessCount || 0) + 1, i.metadata.lastAccessTime = Date.now());
1083
+ }
1084
+ /**
1085
+ * Get the paths that changed between two states
1086
+ */
1087
+ getChangedPaths(e, t, s = "") {
1088
+ const i = /* @__PURE__ */ new Set();
1089
+ if (e === t) return i;
1090
+ if (typeof e != "object" || typeof t != "object" || e === null || t === null)
1091
+ return s && i.add(s), i;
1092
+ const n = /* @__PURE__ */ new Set([
1093
+ ...Object.keys(e),
1094
+ ...Object.keys(t)
1095
+ ]);
1096
+ for (const a of n) {
1097
+ const c = s ? `${s}.${a}` : a, l = e[a], h = t[a];
1098
+ l !== h && (i.add(c), typeof l == "object" && typeof h == "object" && l !== null && h !== null && this.getChangedPaths(
1099
+ l,
1100
+ h,
1101
+ c
1102
+ ).forEach((S) => i.add(S)));
1103
+ }
1104
+ return i;
1105
+ }
1106
+ /**
1107
+ * Check if a subscription should be notified based on changed paths
1108
+ */
1109
+ shouldNotifyForPaths(e, t) {
1110
+ const s = this.subscriptions.get(e);
1111
+ if (!s || !s.dependencies) return !0;
1112
+ for (const i of s.dependencies) {
1113
+ if (i.startsWith("_class.")) {
1114
+ if (t.size > 0)
1115
+ return !0;
1116
+ continue;
1117
+ }
1118
+ if (t.has(i)) return !0;
1119
+ for (const n of t)
1120
+ if (n.startsWith(i + ".") || i.startsWith(n + "."))
1121
+ return !0;
1122
+ }
1123
+ return !1;
1124
+ }
1125
+ /**
1126
+ * Get statistics about subscriptions
1127
+ */
1128
+ getStats() {
1129
+ let e = 0, t = 0;
1130
+ for (const s of this.subscriptions.values())
1131
+ s.type === "consumer" ? e++ : t++;
1132
+ return {
1133
+ activeSubscriptions: this.subscriptions.size,
1134
+ consumerCount: e,
1135
+ observerCount: t,
1136
+ totalNotifications: this.totalNotifications,
1137
+ trackedDependencies: this.pathToSubscriptions.size
1138
+ };
1139
+ }
1140
+ /**
1141
+ * Clear all subscriptions
1142
+ */
1143
+ clear() {
1144
+ this.subscriptions.clear(), this.pathToSubscriptions.clear();
1145
+ }
1146
+ /**
1147
+ * Get subscription by ID
1148
+ */
1149
+ getSubscription(e) {
1150
+ return this.subscriptions.get(e);
1151
+ }
1152
+ /**
1153
+ * Check if there are any active subscriptions
1154
+ */
1155
+ get hasSubscriptions() {
1156
+ return this.subscriptions.size > 0;
1157
+ }
1158
+ /**
1159
+ * Get count of active subscriptions
1160
+ */
1161
+ get size() {
1162
+ return this.subscriptions.size;
1163
+ }
1164
+ /**
1165
+ * Clean up subscriptions with dead weak references
1166
+ */
1167
+ cleanupDeadReferences() {
1168
+ if (!this.weakRefCleanupScheduled) return;
1169
+ const e = [];
1170
+ for (const [t, s] of this.subscriptions)
1171
+ s.weakRef && !s.weakRef.deref() && e.push(t);
1172
+ for (const t of e)
1173
+ this.unsubscribe(t);
1174
+ this.weakRefCleanupScheduled = !1;
1175
+ }
1176
+ /**
1177
+ * Schedule weak reference cleanup for next tick
1178
+ */
1179
+ scheduleWeakRefCleanup() {
1180
+ this.weakRefCleanupScheduled || (this.weakRefCleanupScheduled = !0, queueMicrotask(() => this.cleanupDeadReferences()));
1181
+ }
1182
+ }
1183
+ class D {
1184
+ pendingUpdates = [];
1185
+ isBatching = !1;
1186
+ /**
1187
+ * Execute a callback with batched updates
1188
+ */
1189
+ batchUpdates(e, t) {
1190
+ if (this.isBatching) {
1191
+ e();
1192
+ return;
1193
+ }
1194
+ this.isBatching = !0, this.pendingUpdates = [];
1195
+ try {
1196
+ if (e(), this.pendingUpdates.length > 0) {
1197
+ const s = this.pendingUpdates[this.pendingUpdates.length - 1];
1198
+ t(s);
1199
+ }
1200
+ } finally {
1201
+ this.isBatching = !1, this.pendingUpdates = [];
1202
+ }
1203
+ }
1204
+ /**
1205
+ * Add an update to the batch
1206
+ */
1207
+ addUpdate(e) {
1208
+ this.isBatching && this.pendingUpdates.push(e);
1209
+ }
1210
+ /**
1211
+ * Check if currently batching
1212
+ */
1213
+ get isCurrentlyBatching() {
1214
+ return this.isBatching;
1215
+ }
1216
+ }
1217
+ class C {
1218
+ uid = A();
1219
+ blacInstance;
1220
+ static isolated = !1;
1221
+ get isIsolated() {
1222
+ return this._isolated;
1223
+ }
1224
+ static keepAlive = !1;
1225
+ get isKeepAlive() {
1226
+ return this._keepAlive;
1227
+ }
1228
+ _isolated = !1;
1229
+ _id;
1230
+ _instanceRef;
1231
+ _name;
1232
+ /**
1233
+ * Unified subscription manager for all state notifications
1234
+ */
1235
+ _subscriptionManager;
1236
+ _state;
1237
+ _lifecycleManager = new B();
1238
+ _batchingManager = new D();
1239
+ _keepAlive = !1;
1240
+ lastUpdate;
1241
+ _plugins = new w();
1242
+ onDispose;
1243
+ /**
1244
+ * Creates a new BlocBase instance with unified subscription management
1245
+ */
1246
+ constructor(e) {
1247
+ this._state = e, this._id = this.constructor.name, this._name = this.constructor.name, this._subscriptionManager = new E(this);
1248
+ const t = this.constructor;
1249
+ if (this._keepAlive = typeof t.keepAlive == "boolean" ? t.keepAlive : !1, this._isolated = typeof t.isolated == "boolean" ? t.isolated : !1, this._plugins = new w(), t.plugins && Array.isArray(t.plugins))
1250
+ for (const s of t.plugins)
1251
+ this._plugins.add(s);
1252
+ this._plugins.attach(this);
1253
+ }
1254
+ /**
1255
+ * Returns the current state
1256
+ */
1257
+ get state() {
1258
+ return this._lifecycleManager.isDisposed ? this._state : this._state;
1259
+ }
1260
+ /**
1261
+ * Subscribe to all state changes
1262
+ */
1263
+ subscribe(e) {
1264
+ return this._subscriptionManager.subscribe({
1265
+ type: "observer",
1266
+ notify: (t) => e(t)
1267
+ });
1268
+ }
1269
+ /**
1270
+ * Subscribe with a selector for optimized updates
1271
+ */
1272
+ subscribeWithSelector(e, t, s) {
1273
+ return this._subscriptionManager.subscribe({
1274
+ type: "consumer",
1275
+ selector: e,
1276
+ equalityFn: s,
1277
+ notify: (i) => t(i)
1278
+ });
1279
+ }
1280
+ /**
1281
+ * Subscribe with React component reference for automatic cleanup
1282
+ */
1283
+ subscribeComponent(e, t) {
1284
+ return this._subscriptionManager.subscribe({
1285
+ type: "consumer",
1286
+ weakRef: e,
1287
+ notify: t
1288
+ });
1289
+ }
1290
+ /**
1291
+ * Get current subscription count
1292
+ */
1293
+ get subscriptionCount() {
1294
+ return this._subscriptionManager.size;
1295
+ }
1296
+ /**
1297
+ * Track property access for a subscription
1298
+ */
1299
+ trackAccess(e, t, s) {
1300
+ this._subscriptionManager.trackAccess(e, t, s);
1301
+ }
1302
+ /**
1303
+ * Emit a new state
1304
+ */
1305
+ emit(e, t) {
1306
+ this._pushState(e, this._state, t);
1307
+ }
1308
+ /**
1309
+ * Internal state push method used by Bloc
1310
+ */
1311
+ _pushState(e, t, s) {
1312
+ if (this._lifecycleManager.currentState !== u.ACTIVE) {
1313
+ this.blacInstance?.error(
1314
+ `[${this._name}:${this._id}] Attempted state update on ${this._lifecycleManager.currentState} bloc. Update ignored.`
1315
+ );
1316
+ return;
1317
+ }
1318
+ if (e === void 0)
1319
+ return;
1320
+ this._state = e;
1321
+ const i = this._plugins.transformState(
1322
+ t,
1323
+ e
1324
+ );
1325
+ if (this._state = i, this._plugins.notifyStateChange(t, i), this.blacInstance?.plugins.notifyStateChanged(
1326
+ this,
1327
+ t,
1328
+ i
1329
+ ), this._batchingManager.isCurrentlyBatching) {
1330
+ this._batchingManager.addUpdate({
1331
+ newState: i,
1332
+ oldState: t,
1333
+ action: s
1334
+ });
1335
+ return;
1336
+ }
1337
+ this._subscriptionManager.notify(i, t, s), this.lastUpdate = Date.now();
1338
+ }
1339
+ _batchUpdates(e) {
1340
+ this._batchingManager.batchUpdates(e, (t) => {
1341
+ this._subscriptionManager.notify(
1342
+ t.newState,
1343
+ t.oldState,
1344
+ t.action
1345
+ );
1346
+ });
732
1347
  }
733
1348
  /**
734
- * Creates a unique key for a bloc instance in the map based on the bloc class name and instance ID
735
- * @param blocClassName - The name of the bloc class
736
- * @param id - The instance ID
737
- * @returns A unique key string in the format "className:id"
1349
+ * Add a plugin
738
1350
  */
739
- createBlocInstanceMapKey(e, t) {
740
- return `${e}:${String(t)}`;
1351
+ addPlugin(e) {
1352
+ if (this._plugins.add(e), this._plugins.attached && e.onAttach)
1353
+ try {
1354
+ e.onAttach(this);
1355
+ } catch (t) {
1356
+ console.error(`Plugin '${e.name}' error in onAttach:`, t);
1357
+ }
741
1358
  }
742
1359
  /**
743
- * Unregister a bloc instance from the main registry
744
- * @param bloc - The bloc instance to unregister
1360
+ * Remove a plugin
745
1361
  */
746
- unregisterBlocInstance(e) {
747
- const t = this.createBlocInstanceMapKey(e._name, e._id);
748
- this.blocInstanceMap.delete(t), this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e);
1362
+ removePlugin(e) {
1363
+ this._plugins.remove(e.name);
749
1364
  }
750
1365
  /**
751
- * Registers a bloc instance in the main registry
752
- * @param bloc - The bloc instance to register
1366
+ * Get all plugins
753
1367
  */
754
- registerBlocInstance(e) {
755
- const t = this.createBlocInstanceMapKey(e._name, e._id);
756
- this.blocInstanceMap.set(t, e), this.uidRegistry.set(e.uid, e), e._keepAlive && this.keepAliveBlocs.add(e);
1368
+ get plugins() {
1369
+ return this._plugins.getAll();
757
1370
  }
758
1371
  /**
759
- * Finds a registered bloc instance by its class and ID
760
- * @param blocClass - The bloc class to search for
761
- * @param id - The instance ID
762
- * @returns The found bloc instance or undefined if not found
1372
+ * Disposal management
763
1373
  */
764
- findRegisteredBlocInstance(e, t) {
765
- if (e.isolated) return;
766
- const n = this.createBlocInstanceMapKey(e.name, t);
767
- return this.blocInstanceMap.get(n);
1374
+ get isDisposed() {
1375
+ return this._lifecycleManager.isDisposed;
768
1376
  }
769
1377
  /**
770
- * Registers an isolated bloc instance in the isolated registry
771
- * @param bloc - The isolated bloc instance to register
1378
+ * Atomic state transition for disposal
772
1379
  */
773
- registerIsolatedBlocInstance(e) {
774
- const t = e.constructor, s = this.isolatedBlocMap.get(t);
775
- s ? s.push(e) : this.isolatedBlocMap.set(t, [e]), this.isolatedBlocIndex.set(e.uid, e), this.uidRegistry.set(e.uid, e), e._keepAlive && this.keepAliveBlocs.add(e);
1380
+ _atomicStateTransition(e, t) {
1381
+ return this._lifecycleManager.atomicStateTransition(
1382
+ e,
1383
+ t
1384
+ );
776
1385
  }
777
1386
  /**
778
- * Unregister an isolated bloc instance from the isolated registry
779
- * @param bloc - The isolated bloc instance to unregister
1387
+ * Dispose the bloc and clean up resources
780
1388
  */
781
- unregisterIsolatedBlocInstance(e) {
782
- const t = e.constructor, s = this.isolatedBlocMap.get(t);
783
- let n = !1;
784
- if (s) {
785
- const o = s.findIndex((a) => a.uid === e.uid);
786
- o !== -1 && (s.splice(o, 1), n = !0), s.length === 0 && this.isolatedBlocMap.delete(t);
1389
+ async dispose() {
1390
+ if (!this._lifecycleManager.atomicStateTransition(
1391
+ u.ACTIVE,
1392
+ u.DISPOSING
1393
+ ).success)
1394
+ if (this._lifecycleManager.currentState === u.DISPOSAL_REQUESTED)
1395
+ this._lifecycleManager.atomicStateTransition(
1396
+ u.DISPOSAL_REQUESTED,
1397
+ u.DISPOSING
1398
+ );
1399
+ else
1400
+ return;
1401
+ try {
1402
+ this._subscriptionManager.clear(), this.onDispose && this.onDispose();
1403
+ for (const s of this._plugins.getAll())
1404
+ try {
1405
+ "onDispose" in s && typeof s.onDispose == "function" && s.onDispose(this);
1406
+ } catch (i) {
1407
+ console.error("Plugin disposal error:", i);
1408
+ }
1409
+ const t = this._lifecycleManager.getDisposalHandler();
1410
+ t && t(this);
1411
+ } finally {
1412
+ this._lifecycleManager.atomicStateTransition(
1413
+ u.DISPOSING,
1414
+ u.DISPOSED
1415
+ );
787
1416
  }
788
- const r = this.isolatedBlocIndex.delete(e.uid);
789
- this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e), n !== r && this.warn(
790
- `[Blac] Inconsistent state detected during isolated bloc cleanup for ${e._name}:${e.uid}. Map removal: ${n}, Index removal: ${r}`
791
- );
792
1417
  }
793
1418
  /**
794
- * Finds an isolated bloc instance by its class and ID (O(n) lookup)
1419
+ * Schedule disposal when no subscriptions remain
795
1420
  */
796
- findIsolatedBlocInstance(e, t) {
797
- if (!e.isolated) return;
798
- const n = this.isolatedBlocMap.get(e);
799
- return n ? n.find((o) => o._id === t) : void 0;
1421
+ _scheduleDisposal() {
1422
+ this._subscriptionManager.size === 0 && !this._keepAlive && this._lifecycleManager.scheduleDisposal(
1423
+ 16,
1424
+ () => this._subscriptionManager.size === 0 && !this._keepAlive,
1425
+ () => this.dispose()
1426
+ );
800
1427
  }
801
1428
  /**
802
- * Finds an isolated bloc instance by UID (O(1) lookup)
1429
+ * Set disposal handler
803
1430
  */
804
- findIsolatedBlocInstanceByUid(e) {
805
- return this.isolatedBlocIndex.get(e);
1431
+ setDisposalHandler(e) {
1432
+ this._lifecycleManager.setDisposalHandler(
1433
+ e
1434
+ );
806
1435
  }
807
1436
  /**
808
- * Creates a new bloc instance and registers it in the appropriate registry
809
- * @param blocClass - The bloc class to instantiate
810
- * @param id - The instance ID
811
- * @param props - Properties to pass to the bloc constructor
812
- * @param instanceRef - Optional reference string for the instance
813
- * @returns The newly created bloc instance
1437
+ * Check if disposal should be scheduled (called by subscription manager)
814
1438
  */
815
- createNewBlocInstance(e, t, s = {}) {
816
- const { props: n, instanceRef: r } = s, o = new e(n);
817
- return o._instanceRef = r, o.props = n || null, o._updateId(t), o._setDisposalHandler((a) => this.disposeBloc(a)), o.isIsolated ? (this.registerIsolatedBlocInstance(o), o) : (this.registerBlocInstance(o), o);
818
- }
819
- static get activateBloc() {
820
- return l.instance.activateBloc;
1439
+ checkDisposal() {
1440
+ this._subscriptionManager.size === 0 && !this._keepAlive && this._lifecycleManager.currentState === u.ACTIVE && this._scheduleDisposal();
821
1441
  }
822
- static get getBloc() {
823
- return l.instance.getBloc;
824
- }
825
- static get getBlocOrThrow() {
826
- return l.instance.getBlocOrThrow;
827
- }
828
- static get disposeKeepAliveBlocs() {
829
- return l.instance.disposeKeepAliveBlocs;
830
- }
831
- static get disposeBlocs() {
832
- return l.instance.disposeBlocs;
833
- }
834
- static get getMemoryStats() {
835
- return l.instance.getMemoryStats;
836
- }
837
- static get validateConsumers() {
838
- return l.instance.validateConsumers;
839
- }
840
- };
841
- /** Private static configuration */
842
- i(l, "_config", {
843
- exposeBlacInstance: !1,
844
- proxyDependencyTracking: !0
845
- }), /** Flag to enable/disable logging */
846
- i(l, "enableLog", !1), i(l, "logLevel", "warn"), i(l, "logSpy", null), i(l, "resetInstance", () => {
847
- S.resetInstance();
848
- });
849
- let d = l;
850
- class U extends x {
851
- constructor() {
852
- super(...arguments);
853
- i(this, "eventHandlers", /* @__PURE__ */ new Map());
854
- /**
855
- * @internal
856
- * Event queue to ensure sequential processing of async events
857
- */
858
- i(this, "_eventQueue", []);
859
- /**
860
- * @internal
861
- * Flag indicating if an event is currently being processed
862
- */
863
- i(this, "_isProcessingEvent", !1);
864
- /**
865
- * Dispatches an action/event to the Bloc.
866
- * Events are queued and processed sequentially to prevent race conditions.
867
- * @param action The action/event instance to be processed.
868
- */
869
- i(this, "add", async (t) => {
870
- this._eventQueue.push(t), this._isProcessingEvent || await this._processEventQueue();
871
- });
1442
+ /**
1443
+ * Cancel disposal if bloc is in disposal_requested state
1444
+ */
1445
+ _cancelDisposalIfRequested() {
1446
+ this.blacInstance?.log(
1447
+ `[${this._name}:${this._id}] _cancelDisposalIfRequested called. Current state: ${this._lifecycleManager.currentState}`
1448
+ ), this._lifecycleManager.cancelDisposal() ? this.blacInstance?.log(
1449
+ `[${this._name}:${this._id}] Disposal cancelled - new subscription added`
1450
+ ) : this._lifecycleManager.currentState === u.DISPOSAL_REQUESTED ? this.blacInstance?.warn(
1451
+ `[${this._name}:${this._id}] Failed to cancel disposal. Current state: ${this._lifecycleManager.currentState}`
1452
+ ) : this._lifecycleManager.isDisposed && this.blacInstance?.error(
1453
+ `[${this._name}:${this._id}] Cannot cancel disposal - bloc is already disposed`
1454
+ );
872
1455
  }
1456
+ }
1457
+ class R extends C {
1458
+ eventHandlers = /* @__PURE__ */ new Map();
1459
+ /**
1460
+ * @internal
1461
+ * Event queue to ensure sequential processing of async events
1462
+ */
1463
+ _eventQueue = [];
1464
+ /**
1465
+ * @internal
1466
+ * Flag indicating if an event is currently being processed
1467
+ */
1468
+ _isProcessingEvent = !1;
873
1469
  /**
874
1470
  * Registers an event handler for a specific event type.
875
1471
  * This method is typically called in the constructor of a derived Bloc class.
@@ -877,14 +1473,35 @@ class U extends x {
877
1473
  * @param handler A function that processes the event and can emit new states.
878
1474
  * The 'event' parameter in the handler will be typed to the specific eventConstructor.
879
1475
  */
880
- on(t, s) {
881
- this.eventHandlers.has(t) && d.warn(
882
- `[Bloc ${this._name}:${String(this._id)}] Handler for event '${t.name}' already registered. It will be overwritten.`
1476
+ on(e, t) {
1477
+ this.eventHandlers.has(e) && o.warn(
1478
+ `[Bloc ${this._name}:${String(this._id)}] Handler for event '${e.name}' already registered. It will be overwritten.`
883
1479
  ), this.eventHandlers.set(
884
- t,
885
- s
1480
+ e,
1481
+ t
886
1482
  );
887
1483
  }
1484
+ /**
1485
+ * Dispatches an action/event to the Bloc.
1486
+ * Events are queued and processed sequentially to prevent race conditions.
1487
+ * @param action The action/event instance to be processed.
1488
+ */
1489
+ add = async (e) => {
1490
+ let t = e;
1491
+ try {
1492
+ t = this._plugins.transformEvent(e);
1493
+ } catch (s) {
1494
+ console.error("Error transforming event:", s);
1495
+ }
1496
+ if (t !== null) {
1497
+ try {
1498
+ this._plugins.notifyEvent(t);
1499
+ } catch (s) {
1500
+ console.error("Error notifying plugins of event:", s);
1501
+ }
1502
+ o.instance.plugins.notifyEventAdded(this, t), this._eventQueue.push(t), this._isProcessingEvent || await this._processEventQueue();
1503
+ }
1504
+ };
888
1505
  /**
889
1506
  * @internal
890
1507
  * Processes events from the queue sequentially
@@ -894,8 +1511,8 @@ class U extends x {
894
1511
  this._isProcessingEvent = !0;
895
1512
  try {
896
1513
  for (; this._eventQueue.length > 0; ) {
897
- const t = this._eventQueue.shift();
898
- await this._processEvent(t);
1514
+ const e = this._eventQueue.shift();
1515
+ await this._processEvent(e);
899
1516
  }
900
1517
  } finally {
901
1518
  this._isProcessingEvent = !1;
@@ -906,54 +1523,59 @@ class U extends x {
906
1523
  * @internal
907
1524
  * Processes a single event
908
1525
  */
909
- async _processEvent(t) {
910
- const s = t.constructor, n = this.eventHandlers.get(s);
911
- if (n) {
912
- const r = (o) => {
1526
+ async _processEvent(e) {
1527
+ const t = e.constructor, s = this.eventHandlers.get(t);
1528
+ if (s) {
1529
+ const i = (n) => {
913
1530
  const a = this.state;
914
- this._pushState(o, a, t);
1531
+ this._pushState(n, a, e);
915
1532
  };
916
1533
  try {
917
- await n(t, r);
918
- } catch (o) {
919
- const a = t.constructor.name || "UnnamedConstructor", u = {
1534
+ await s(e, i);
1535
+ } catch (n) {
1536
+ const a = e.constructor.name || "UnnamedConstructor", c = {
920
1537
  blocName: this._name,
921
1538
  blocId: String(this._id),
922
1539
  eventType: a,
923
1540
  currentState: this.state,
924
- action: t,
1541
+ action: e,
925
1542
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
926
1543
  };
927
- if (d.error(
1544
+ if (o.error(
928
1545
  `[Bloc ${this._name}:${String(this._id)}] Error in event handler for '${a}':`,
929
- o,
1546
+ n,
930
1547
  "Context:",
931
- u
932
- ), o instanceof Error && o.name === "CriticalError")
933
- throw o;
1548
+ c
1549
+ ), n instanceof Error)
1550
+ try {
1551
+ this._plugins.notifyError(n, {
1552
+ phase: "event-processing",
1553
+ operation: "handler",
1554
+ metadata: { event: e }
1555
+ }), o.instance.plugins.notifyError(n, this, {
1556
+ phase: "event-processing",
1557
+ operation: "handler",
1558
+ metadata: { event: e }
1559
+ });
1560
+ } catch (l) {
1561
+ console.error("Error notifying plugins:", l);
1562
+ }
1563
+ if (n instanceof Error && n.name === "CriticalError")
1564
+ throw n;
934
1565
  }
935
1566
  } else {
936
- const r = t.constructor.name || "UnnamedConstructor";
937
- d.warn(
938
- `[Bloc ${this._name}:${String(this._id)}] No handler registered for action type: '${r}'.`,
1567
+ const i = e.constructor.name || "UnnamedConstructor";
1568
+ o.warn(
1569
+ `[Bloc ${this._name}:${String(this._id)}] No handler registered for action type: '${i}'.`,
939
1570
  "Registered handlers:",
940
- Array.from(this.eventHandlers.keys()).map((o) => o.name),
1571
+ Array.from(this.eventHandlers.keys()).map((n) => n.name),
941
1572
  "Action was:",
942
- t
1573
+ e
943
1574
  );
944
1575
  }
945
1576
  }
946
1577
  }
947
- class H extends x {
948
- /**
949
- * @internal
950
- * Protected method for useBloc to call
951
- */
952
- _updateProps(e) {
953
- var s;
954
- const t = this.props;
955
- this.props = e, (s = this.onPropsChanged) == null || s.call(this, t, e);
956
- }
1578
+ class O extends C {
957
1579
  /**
958
1580
  * Updates the current state and notifies all observers of the change.
959
1581
  * If the new state is identical to the current state (using Object.is),
@@ -976,7 +1598,7 @@ class H extends x {
976
1598
  */
977
1599
  patch(e, t = !1) {
978
1600
  if (typeof this.state != "object" || this.state === null) {
979
- d.warn(
1601
+ o.warn(
980
1602
  "Cubit.patch: was called on a cubit where the state is not an object. This is a no-op."
981
1603
  );
982
1604
  return;
@@ -985,10 +1607,10 @@ class H extends x {
985
1607
  if (t)
986
1608
  s = !0;
987
1609
  else
988
- for (const n in e)
989
- if (Object.prototype.hasOwnProperty.call(e, n)) {
990
- const o = this.state[n];
991
- if (!Object.is(e[n], o)) {
1610
+ for (const i in e)
1611
+ if (Object.prototype.hasOwnProperty.call(e, i)) {
1612
+ const a = this.state[i];
1613
+ if (!Object.is(e[i], a)) {
992
1614
  s = !0;
993
1615
  break;
994
1616
  }
@@ -999,112 +1621,237 @@ class H extends x {
999
1621
  });
1000
1622
  }
1001
1623
  }
1002
- class N {
1624
+ class L {
1003
1625
  constructor(e) {
1004
1626
  this.props = e;
1005
1627
  }
1006
1628
  }
1007
- function j(c, e) {
1008
- if (Object.is(c, e))
1629
+ function V(r, e) {
1630
+ if (Object.is(r, e))
1009
1631
  return !0;
1010
- if (typeof c != "object" || c === null || typeof e != "object" || e === null)
1632
+ if (typeof r != "object" || r === null || typeof e != "object" || e === null)
1011
1633
  return !1;
1012
- const t = Object.keys(c), s = Object.keys(e);
1634
+ const t = Object.keys(r), s = Object.keys(e);
1013
1635
  if (t.length !== s.length)
1014
1636
  return !1;
1015
- for (let n = 0; n < t.length; n++) {
1016
- const r = t[n];
1017
- if (!Object.prototype.hasOwnProperty.call(e, r) || !Object.is(c[r], e[r]))
1637
+ for (let i = 0; i < t.length; i++) {
1638
+ const n = t[i];
1639
+ if (!Object.prototype.hasOwnProperty.call(e, n) || !Object.is(r[n], e[n]))
1018
1640
  return !1;
1019
1641
  }
1020
1642
  return !0;
1021
1643
  }
1022
- class L {
1644
+ function N(r) {
1645
+ if (!r || typeof r != "object")
1646
+ return;
1647
+ const e = [];
1648
+ for (const [s, i] of Object.entries(r)) {
1649
+ const n = typeof i;
1650
+ (n === "string" || n === "number" || n === "boolean" || i === null || i === void 0) && e.push([s, i]);
1651
+ }
1652
+ if (e.length === 0)
1653
+ return;
1654
+ e.sort(([s], [i]) => s.localeCompare(i));
1655
+ const t = [];
1656
+ for (const [s, i] of e)
1657
+ i === null ? t.push(`${s}:null`) : i === void 0 ? t.push(`${s}:undefined`) : t.push(`${s}:${String(i)}`);
1658
+ return t.join("|");
1659
+ }
1660
+ class F {
1661
+ static componentRenderCounts = /* @__PURE__ */ new Map();
1662
+ static lastRenderTimestamps = /* @__PURE__ */ new Map();
1663
+ static groupedLogs = /* @__PURE__ */ new Map();
1664
+ static groupTimeouts = /* @__PURE__ */ new Map();
1665
+ /**
1666
+ * Log a component rerender with detailed information
1667
+ */
1668
+ static logRerender(e) {
1669
+ const t = o._config?.rerenderLogging;
1670
+ if (!t) return;
1671
+ const s = this.parseConfig(t);
1672
+ if (!s.enabled || s.filter && !s.filter({
1673
+ componentName: e.componentName,
1674
+ blocName: e.blocName
1675
+ }))
1676
+ return;
1677
+ const i = `${e.componentName}-${e.blocId}`, n = this.componentRenderCounts.get(i) || 0;
1678
+ this.componentRenderCounts.set(i, n + 1), e.renderCount = n + 1;
1679
+ const a = this.lastRenderTimestamps.get(i);
1680
+ a && (e.duration = e.timestamp - a), this.lastRenderTimestamps.set(i, e.timestamp), s.includeStackTrace && s.level === "detailed" && (e.stackTrace = new Error().stack), s.groupRerenders ? this.logGrouped(e, s) : this.logImmediate(e, s);
1681
+ }
1682
+ /**
1683
+ * Parse the logging configuration
1684
+ */
1685
+ static parseConfig(e) {
1686
+ return e === !0 ? { enabled: !0, level: "normal" } : typeof e == "string" ? {
1687
+ enabled: !0,
1688
+ level: e === "minimal" ? "minimal" : "detailed"
1689
+ } : {
1690
+ enabled: e.enabled,
1691
+ level: e.level || "normal",
1692
+ filter: e.filter,
1693
+ includeStackTrace: e.includeStackTrace,
1694
+ groupRerenders: e.groupRerenders
1695
+ };
1696
+ }
1697
+ /**
1698
+ * Log immediately without grouping
1699
+ */
1700
+ static logImmediate(e, t) {
1701
+ const s = this.formatMessage(e, t.level);
1702
+ t.level === "detailed" ? (console.group(s.header), s.details && console.log(s.details), s.values && console.table(s.values), e.stackTrace && console.log("Stack trace:", e.stackTrace), console.groupEnd()) : console.log(s.header, s.details || "");
1703
+ }
1704
+ /**
1705
+ * Log with grouping (batch multiple rerenders)
1706
+ */
1707
+ static logGrouped(e, t) {
1708
+ const s = `${e.componentName}-${e.blocId}`, i = this.groupTimeouts.get(s);
1709
+ i && clearTimeout(i);
1710
+ const n = this.groupedLogs.get(s) || [];
1711
+ n.push(e), this.groupedLogs.set(s, n);
1712
+ const a = setTimeout(() => {
1713
+ const c = this.groupedLogs.get(s) || [];
1714
+ this.groupedLogs.delete(s), this.groupTimeouts.delete(s), c.length === 1 ? this.logImmediate(c[0], t) : (console.group(
1715
+ `🔄 ${e.componentName} rendered ${c.length} times (${e.blocName})`
1716
+ ), c.forEach((l, h) => {
1717
+ const p = this.formatMessage(l, t.level);
1718
+ console.log(` ${h + 1}. ${p.details || p.header}`);
1719
+ }), console.groupEnd());
1720
+ }, 50);
1721
+ this.groupTimeouts.set(s, a);
1722
+ }
1723
+ /**
1724
+ * Format the log message based on level
1725
+ */
1726
+ static formatMessage(e, t) {
1727
+ const s = this.getReasonEmoji(e.reason.type);
1728
+ if (t === "minimal")
1729
+ return {
1730
+ header: `${s} ${e.componentName} #${e.renderCount}`,
1731
+ details: null,
1732
+ values: null
1733
+ };
1734
+ const i = `${s} ${e.componentName} rerender #${e.renderCount} (${e.blocName})`;
1735
+ let n = `Reason: ${e.reason.description || e.reason.type}`;
1736
+ e.duration !== void 0 && (n += ` | Time since last: ${e.duration}ms`), t === "normal" && e.reason.changedPaths && e.reason.changedPaths.length > 0 && (n += ` | Changed: ${e.reason.changedPaths.join(", ")}`);
1737
+ let a = null;
1738
+ return t === "detailed" && e.reason.changedPaths && e.reason.changedPaths.length > 0 && (a = {}, e.reason.changedPaths.forEach((c) => {
1739
+ a[c] = {
1740
+ old: e.reason.oldValues?.[c],
1741
+ new: e.reason.newValues?.[c]
1742
+ };
1743
+ }), Object.keys(a).length === 0 && (a = null)), { header: i, details: n, values: a };
1744
+ }
1745
+ /**
1746
+ * Get emoji for reason type
1747
+ */
1748
+ static getReasonEmoji(e) {
1749
+ switch (e) {
1750
+ case "state-change":
1751
+ return "📊";
1752
+ case "dependency-change":
1753
+ return "🔗";
1754
+ case "mount":
1755
+ return "🚀";
1756
+ case "props-change":
1757
+ return "📦";
1758
+ default:
1759
+ return "🔄";
1760
+ }
1761
+ }
1762
+ /**
1763
+ * Clear all tracking data
1764
+ */
1765
+ static clear() {
1766
+ this.componentRenderCounts.clear(), this.lastRenderTimestamps.clear(), this.groupedLogs.clear(), this.groupTimeouts.forEach((e) => clearTimeout(e)), this.groupTimeouts.clear();
1767
+ }
1768
+ /**
1769
+ * Get render count for a component
1770
+ */
1771
+ static getRenderCount(e, t) {
1772
+ return this.componentRenderCounts.get(`${e}-${t}`) || 0;
1773
+ }
1774
+ }
1775
+ class j {
1776
+ static originalInstance;
1023
1777
  /**
1024
1778
  * Sets up a clean test environment
1025
1779
  */
1026
1780
  static setUp() {
1027
- this.originalInstance = d.instance, d.resetInstance(), d.enableLog = !1;
1781
+ this.originalInstance = o.instance, o.resetInstance(), o.enableLog = !1;
1028
1782
  }
1029
1783
  /**
1030
1784
  * Tears down the test environment and restores original state
1031
1785
  */
1032
1786
  static tearDown() {
1033
- d.resetInstance();
1787
+ o.resetInstance();
1034
1788
  }
1035
1789
  /**
1036
1790
  * Creates a test bloc with automatic cleanup
1037
1791
  */
1038
1792
  static createBloc(e, ...t) {
1039
1793
  const s = new e(...t);
1040
- return d.activateBloc(s), s;
1794
+ return o.activateBloc(s), s;
1041
1795
  }
1042
1796
  /**
1043
1797
  * Waits for a bloc to emit a specific state
1044
1798
  */
1045
1799
  static async waitForState(e, t, s = 5e3) {
1046
- return new Promise((n, r) => {
1047
- const o = setTimeout(() => {
1048
- r(
1800
+ return new Promise((i, n) => {
1801
+ const a = setTimeout(() => {
1802
+ n(
1049
1803
  new Error(
1050
1804
  `Timeout waiting for state matching predicate after ${s}ms`
1051
1805
  )
1052
1806
  );
1053
- }, s), a = e._observer.subscribe({
1054
- id: `test-waiter-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1055
- fn: (u) => {
1056
- t(u) && (clearTimeout(o), a(), n(u));
1057
- }
1807
+ }, s), c = e.subscribe((l) => {
1808
+ t(l) && (clearTimeout(a), c(), i(l));
1058
1809
  });
1059
- t(e.state) && (clearTimeout(o), a(), n(e.state));
1810
+ t(e.state) && (clearTimeout(a), c(), i(e.state));
1060
1811
  });
1061
1812
  }
1062
1813
  /**
1063
1814
  * Expects a bloc to emit specific states in order
1064
1815
  */
1065
1816
  static async expectStates(e, t, s = 5e3) {
1066
- const n = [];
1067
- return new Promise((r, o) => {
1068
- const a = setTimeout(() => {
1069
- o(
1817
+ const i = [];
1818
+ return new Promise((n, a) => {
1819
+ const c = setTimeout(() => {
1820
+ a(
1070
1821
  new Error(
1071
- `Timeout waiting for states. Expected: ${JSON.stringify(t)}, Received: ${JSON.stringify(n)}`
1822
+ `Timeout waiting for states. Expected: ${JSON.stringify(t)}, Received: ${JSON.stringify(i)}`
1072
1823
  )
1073
1824
  );
1074
- }, s), u = e._observer.subscribe({
1075
- id: `test-expecter-${crypto.randomUUID()}`,
1076
- fn: (p) => {
1077
- if (n.push(p), n.length === t.length) {
1078
- clearTimeout(a), u();
1079
- for (let h = 0; h < t.length; h++) {
1080
- const m = t[h], I = n[h];
1081
- if (JSON.stringify(m) !== JSON.stringify(I)) {
1082
- o(
1083
- new Error(
1084
- `State mismatch at index ${h}. Expected: ${JSON.stringify(m)}, Received: ${JSON.stringify(I)}`
1085
- )
1086
- );
1087
- return;
1088
- }
1825
+ }, s), l = e.subscribe((h) => {
1826
+ if (i.push(h), i.length === t.length) {
1827
+ clearTimeout(c), l();
1828
+ for (let p = 0; p < t.length; p++) {
1829
+ const S = t[p], k = i[p];
1830
+ if (JSON.stringify(S) !== JSON.stringify(k)) {
1831
+ a(
1832
+ new Error(
1833
+ `State mismatch at index ${p}. Expected: ${JSON.stringify(S)}, Received: ${JSON.stringify(k)}`
1834
+ )
1835
+ );
1836
+ return;
1089
1837
  }
1090
- r();
1091
1838
  }
1839
+ n();
1092
1840
  }
1093
1841
  });
1094
1842
  });
1095
1843
  }
1096
1844
  }
1097
- i(L, "originalInstance");
1098
- class Q extends U {
1099
- constructor(t) {
1100
- super(t);
1101
- i(this, "mockHandlers", /* @__PURE__ */ new Map());
1845
+ class z extends R {
1846
+ mockHandlers = /* @__PURE__ */ new Map();
1847
+ constructor(e) {
1848
+ super(e);
1102
1849
  }
1103
1850
  /**
1104
1851
  * Mock an event handler for testing
1105
1852
  */
1106
- mockEventHandler(t, s) {
1107
- this.on(t, s);
1853
+ mockEventHandler(e, t) {
1854
+ this.on(e, t);
1108
1855
  }
1109
1856
  /**
1110
1857
  * Get the number of registered handlers
@@ -1115,21 +1862,20 @@ class Q extends U {
1115
1862
  /**
1116
1863
  * Check if a handler is registered for an event type
1117
1864
  */
1118
- hasHandler(t) {
1119
- return this.eventHandlers.has(t);
1865
+ hasHandler(e) {
1866
+ return this.eventHandlers.has(e);
1120
1867
  }
1121
1868
  }
1122
- class W extends H {
1123
- constructor(t) {
1124
- super(t);
1125
- i(this, "stateHistory", []);
1126
- this.stateHistory.push(t);
1869
+ class q extends O {
1870
+ stateHistory = [];
1871
+ constructor(e) {
1872
+ super(e), this.stateHistory.push(e);
1127
1873
  }
1128
1874
  /**
1129
1875
  * Override emit to track state history
1130
1876
  */
1131
- emit(t) {
1132
- this.stateHistory.push(t), super.emit(t);
1877
+ emit(e) {
1878
+ this.stateHistory.push(e), super.emit(e);
1133
1879
  }
1134
1880
  /**
1135
1881
  * Get the history of all states
@@ -1144,16 +1890,16 @@ class W extends H {
1144
1890
  this.stateHistory = [this.state];
1145
1891
  }
1146
1892
  }
1147
- class F {
1893
+ class W {
1894
+ initialStats;
1148
1895
  constructor() {
1149
- i(this, "initialStats");
1150
- this.initialStats = d.getMemoryStats();
1896
+ this.initialStats = o.getMemoryStats();
1151
1897
  }
1152
1898
  /**
1153
1899
  * Check for memory leaks and return a report
1154
1900
  */
1155
1901
  checkForLeaks() {
1156
- const e = d.getMemoryStats(), t = e.registeredBlocs > this.initialStats.registeredBlocs || e.isolatedBlocs > this.initialStats.isolatedBlocs || e.keepAliveBlocs > this.initialStats.keepAliveBlocs, s = `
1902
+ const e = o.getMemoryStats(), t = e.registeredBlocs > this.initialStats.registeredBlocs || e.isolatedBlocs > this.initialStats.isolatedBlocs || e.keepAliveBlocs > this.initialStats.keepAliveBlocs, s = `
1157
1903
  Memory Leak Detection Report:
1158
1904
  - Initial registered blocs: ${this.initialStats.registeredBlocs}
1159
1905
  - Current registered blocs: ${e.registeredBlocs}
@@ -1170,419 +1916,360 @@ Memory Leak Detection Report:
1170
1916
  };
1171
1917
  }
1172
1918
  }
1173
- class z {
1174
- constructor() {
1175
- i(this, "consumers", /* @__PURE__ */ new WeakMap());
1176
- i(this, "registrationCount", 0);
1177
- i(this, "activeConsumers", 0);
1178
- }
1179
- register(e, t) {
1180
- this.registrationCount++, this.consumers.get(e) || this.activeConsumers++, this.consumers.set(e, {
1181
- id: t,
1182
- lastNotified: Date.now(),
1183
- hasRendered: !1,
1184
- stateAccesses: /* @__PURE__ */ new Set(),
1185
- classAccesses: /* @__PURE__ */ new Set(),
1186
- stateValues: /* @__PURE__ */ new Map(),
1187
- classValues: /* @__PURE__ */ new Map(),
1188
- accessCount: 0,
1189
- lastAccessTime: 0,
1190
- firstAccessTime: 0
1191
- });
1192
- }
1193
- unregister(e) {
1194
- e && this.consumers.get(e) && (this.consumers.delete(e), this.activeConsumers = Math.max(0, this.activeConsumers - 1));
1195
- }
1196
- trackAccess(e, t, s, n) {
1197
- const r = this.consumers.get(e);
1198
- if (!r) return;
1199
- const o = Date.now();
1200
- r.firstAccessTime || (r.firstAccessTime = o), r.accessCount++, r.lastAccessTime = o, t === "state" ? (r.stateAccesses.add(s), n !== void 0 && r.stateValues.set(s, { value: n, lastAccessTime: o })) : (r.classAccesses.add(s), n !== void 0 && r.classValues.set(s, { value: n, lastAccessTime: o }));
1201
- }
1202
- resetTracking(e) {
1203
- const t = this.consumers.get(e);
1204
- t && (t.stateAccesses.clear(), t.classAccesses.clear(), t.stateValues.clear(), t.classValues.clear(), t.accessCount = 0, t.firstAccessTime = 0);
1205
- }
1206
- getDependencies(e) {
1207
- const t = this.consumers.get(e);
1208
- return t ? {
1209
- statePaths: Array.from(t.stateAccesses),
1210
- classPaths: Array.from(t.classAccesses)
1211
- } : null;
1212
- }
1213
- hasValuesChanged(e, t, s) {
1214
- const n = this.consumers.get(e);
1215
- if (!n) return !0;
1216
- let r = !1;
1217
- const o = Date.now();
1218
- if (n.stateValues.size === 0 && n.classValues.size === 0 && (n.stateAccesses.size > 0 || n.classAccesses.size > 0))
1219
- return !0;
1220
- for (const [a, u] of n.stateValues)
1221
- try {
1222
- const p = this.getValueAtPath(t, a);
1223
- p !== u.value && (n.stateValues.set(a, {
1224
- value: p,
1225
- lastAccessTime: o
1226
- }), r = !0);
1227
- } catch {
1228
- r = !0;
1229
- }
1230
- for (const [a, u] of n.classValues)
1231
- try {
1232
- const p = this.getValueAtPath(s, a);
1233
- p !== u.value && (n.classValues.set(a, {
1234
- value: p,
1235
- lastAccessTime: o
1236
- }), r = !0);
1237
- } catch {
1238
- r = !0;
1239
- }
1240
- return r;
1241
- }
1242
- shouldNotifyConsumer(e, t) {
1243
- const s = this.consumers.get(e);
1244
- if (!s) return !1;
1245
- for (const n of t) {
1246
- if (s.stateAccesses.has(n) || s.classAccesses.has(n)) return !0;
1247
- for (const r of s.stateAccesses)
1248
- if (n.startsWith(r + ".") || r.startsWith(n + "."))
1249
- return !0;
1250
- }
1251
- return !1;
1252
- }
1253
- updateLastNotified(e) {
1254
- const t = this.consumers.get(e);
1255
- t && (t.lastNotified = Date.now());
1256
- }
1257
- getConsumerInfo(e) {
1258
- return this.consumers.get(e);
1259
- }
1260
- setHasRendered(e, t) {
1261
- const s = this.consumers.get(e);
1262
- s && (s.hasRendered = t);
1263
- }
1264
- hasConsumer(e) {
1265
- return this.consumers.has(e);
1266
- }
1267
- getStats() {
1268
- return {
1269
- totalRegistrations: this.registrationCount,
1270
- activeConsumers: this.activeConsumers
1271
- };
1272
- }
1273
- getValueAtPath(e, t) {
1274
- const s = t.split(".");
1275
- let n = e;
1276
- for (const r of s) {
1277
- if (n == null) return;
1278
- n = n[r];
1279
- }
1280
- return n;
1281
- }
1282
- }
1283
- const k = /* @__PURE__ */ new WeakMap();
1284
- let f = {
1919
+ const I = /* @__PURE__ */ new WeakMap(), d = {
1285
1920
  stateProxiesCreated: 0,
1286
1921
  classProxiesCreated: 0,
1287
1922
  cacheHits: 0,
1288
1923
  cacheMisses: 0,
1289
- propertyAccesses: 0,
1290
- nestedProxiesCreated: 0,
1291
- totalProxiesCreated: 0,
1292
- createdAt: Date.now()
1293
- };
1294
- class b {
1295
- static createStateProxy(e) {
1296
- const { target: t, consumerRef: s, consumerTracker: n, path: r = "" } = e;
1297
- if (!s || !n || typeof t != "object" || t === null)
1298
- return t;
1299
- let o = k.get(t);
1300
- o || (o = /* @__PURE__ */ new WeakMap(), k.set(t, o));
1301
- const a = o.get(s);
1924
+ totalProxiesCreated: 0
1925
+ }, _ = (r, e, t, s = "") => {
1926
+ if (!e || !t || typeof r != "object" || r === null)
1927
+ return r;
1928
+ if (!s) {
1929
+ let n = I.get(r);
1930
+ n || (n = /* @__PURE__ */ new WeakMap(), I.set(r, n));
1931
+ const a = n.get(e);
1302
1932
  if (a)
1303
- return f.cacheHits++, a;
1304
- f.cacheMisses++;
1305
- const u = {
1306
- get(h, m) {
1307
- if (typeof m == "symbol" || m === "constructor")
1308
- return Reflect.get(h, m);
1309
- const I = r ? `${r}.${m}` : m;
1310
- f.propertyAccesses++;
1311
- const g = Reflect.get(h, m), w = g && typeof g === "object" && g !== null ? void 0 : g;
1312
- if (n.trackAccess(s, "state", I, w), g && typeof g == "object" && g !== null) {
1313
- const B = Object.getPrototypeOf(g) === Object.prototype, P = Array.isArray(g);
1314
- if (B || P)
1315
- return f.nestedProxiesCreated++, b.createStateProxy({
1316
- target: g,
1317
- consumerRef: s,
1318
- consumerTracker: n,
1319
- path: I
1320
- });
1321
- }
1322
- return g;
1323
- },
1324
- has(h, m) {
1325
- return m in h;
1326
- },
1327
- ownKeys(h) {
1328
- return Reflect.ownKeys(h);
1329
- },
1330
- getOwnPropertyDescriptor(h, m) {
1331
- return Reflect.getOwnPropertyDescriptor(h, m);
1332
- },
1333
- set() {
1334
- return !1;
1335
- },
1336
- deleteProperty() {
1337
- return !1;
1338
- }
1339
- }, p = new Proxy(t, u);
1340
- return o.set(s, p), f.stateProxiesCreated++, f.totalProxiesCreated++, p;
1341
- }
1342
- static createClassProxy(e) {
1343
- const { target: t, consumerRef: s, consumerTracker: n } = e;
1344
- if (!s || !n)
1345
- return t;
1346
- let r = k.get(t);
1347
- r || (r = /* @__PURE__ */ new WeakMap(), k.set(t, r));
1348
- const o = r.get(s);
1349
- if (o)
1350
- return f.cacheHits++, o;
1351
- f.cacheMisses++;
1352
- const a = {
1353
- get(p, h) {
1354
- const m = Reflect.get(p, h);
1355
- let I = !1, g = p;
1356
- const A = /* @__PURE__ */ new WeakSet(), D = 10;
1357
- let w = 0;
1358
- for (; g && !I && w < D && !A.has(g); ) {
1359
- A.add(g);
1360
- try {
1361
- const T = Object.getOwnPropertyDescriptor(
1362
- g,
1363
- h
1364
- );
1365
- if (T && T.get) {
1366
- I = !0;
1367
- break;
1368
- }
1369
- g = Object.getPrototypeOf(g), w++;
1370
- } catch {
1371
- break;
1372
- }
1373
- }
1374
- if (!I)
1375
- return m;
1376
- f.propertyAccesses++;
1377
- const B = m, M = B !== null && typeof B != "object" ? B : void 0;
1378
- return n.trackAccess(
1379
- s,
1933
+ return d.cacheHits++, a;
1934
+ d.cacheMisses++;
1935
+ }
1936
+ const i = new Proxy(r, {
1937
+ get(n, a) {
1938
+ if (typeof a == "symbol" || a === "constructor")
1939
+ return Reflect.get(n, a);
1940
+ const c = s ? `${s}.${a}` : a, l = Reflect.get(n, a), h = l && typeof l == "object";
1941
+ return t.trackAccess(
1942
+ e,
1943
+ "state",
1944
+ c,
1945
+ h ? void 0 : l
1946
+ ), h && (Array.isArray(l) || Object.getPrototypeOf(l) === Object.prototype) ? _(l, e, t, c) : l;
1947
+ },
1948
+ set: () => !1,
1949
+ // State should be immutable
1950
+ deleteProperty: () => !1
1951
+ // State properties should not be deleted
1952
+ });
1953
+ return s || (I.get(r).set(e, i), d.stateProxiesCreated++, d.totalProxiesCreated++), i;
1954
+ }, M = (r, e, t) => {
1955
+ if (!e || !t)
1956
+ return r;
1957
+ let s = I.get(r);
1958
+ s || (s = /* @__PURE__ */ new WeakMap(), I.set(r, s));
1959
+ const i = s.get(e);
1960
+ if (i)
1961
+ return d.cacheHits++, i;
1962
+ d.cacheMisses++;
1963
+ const n = new Proxy(r, {
1964
+ get(a, c) {
1965
+ const l = Reflect.get(a, c);
1966
+ if (U(a, c)?.get) {
1967
+ const p = l !== null && typeof l != "object";
1968
+ t.trackAccess(
1969
+ e,
1380
1970
  "class",
1381
- String(h),
1382
- M
1383
- ), m;
1384
- },
1385
- has(p, h) {
1386
- return h in p;
1387
- },
1388
- ownKeys(p) {
1389
- return Reflect.ownKeys(p);
1390
- },
1391
- getOwnPropertyDescriptor(p, h) {
1392
- return Reflect.getOwnPropertyDescriptor(p, h);
1971
+ String(c),
1972
+ p ? l : void 0
1973
+ );
1393
1974
  }
1394
- }, u = new Proxy(t, a);
1395
- return r.set(s, u), f.classProxiesCreated++, f.totalProxiesCreated++, u;
1396
- }
1397
- static getProxyState(e) {
1398
- return b.createStateProxy({
1399
- target: e.state,
1400
- consumerRef: e.consumerRef,
1401
- consumerTracker: e.consumerTracker
1402
- });
1403
- }
1404
- static getProxyBlocInstance(e) {
1405
- return b.createClassProxy({
1406
- target: e.blocInstance,
1407
- consumerRef: e.consumerRef,
1408
- consumerTracker: e.consumerTracker
1409
- });
1410
- }
1411
- static getStats() {
1412
- const e = Date.now() - f.createdAt;
1413
- return {
1414
- ...f,
1415
- totalProxies: f.stateProxiesCreated + f.classProxiesCreated,
1416
- cacheEfficiency: f.cacheHits + f.cacheMisses > 0 ? `${(f.cacheHits / (f.cacheHits + f.cacheMisses) * 100).toFixed(1)}%` : "N/A",
1417
- lifetime: `${e}ms`,
1418
- proxiesPerSecond: e > 0 ? (f.totalProxiesCreated / (e / 1e3)).toFixed(2) : "N/A"
1419
- };
1420
- }
1421
- static resetStats() {
1422
- f = {
1423
- stateProxiesCreated: 0,
1424
- classProxiesCreated: 0,
1425
- cacheHits: 0,
1426
- cacheMisses: 0,
1427
- propertyAccesses: 0,
1428
- nestedProxiesCreated: 0,
1429
- totalProxiesCreated: 0,
1430
- createdAt: Date.now()
1431
- };
1975
+ return l;
1976
+ }
1977
+ });
1978
+ return s.set(e, n), d.classProxiesCreated++, d.totalProxiesCreated++, n;
1979
+ }, U = (r, e, t = 10) => {
1980
+ let s = r, i = 0;
1981
+ for (; s && i < t; ) {
1982
+ const n = Object.getOwnPropertyDescriptor(s, e);
1983
+ if (n) return n;
1984
+ s = Object.getPrototypeOf(s), i++;
1985
+ }
1986
+ }, $ = {
1987
+ createStateProxy: (r) => _(
1988
+ r.target,
1989
+ r.consumerRef,
1990
+ r.consumerTracker,
1991
+ r.path
1992
+ ),
1993
+ createClassProxy: (r) => M(
1994
+ r.target,
1995
+ r.consumerRef,
1996
+ r.consumerTracker
1997
+ ),
1998
+ getProxyState: (r) => _(
1999
+ r.state,
2000
+ r.consumerRef,
2001
+ r.consumerTracker
2002
+ ),
2003
+ getProxyBlocInstance: (r) => M(
2004
+ r.blocInstance,
2005
+ r.consumerRef,
2006
+ r.consumerTracker
2007
+ ),
2008
+ // Compatibility functions that return expected structure
2009
+ getStats: () => ({
2010
+ ...d,
2011
+ propertyAccesses: 0,
2012
+ nestedProxiesCreated: 0,
2013
+ cacheEfficiency: d.cacheHits + d.cacheMisses > 0 ? `${(d.cacheHits / (d.cacheHits + d.cacheMisses) * 100).toFixed(1)}%` : "N/A",
2014
+ lifetime: "0ms",
2015
+ proxiesPerSecond: "N/A"
2016
+ }),
2017
+ resetStats: () => {
2018
+ d.stateProxiesCreated = 0, d.classProxiesCreated = 0, d.cacheHits = 0, d.cacheMisses = 0, d.totalProxiesCreated = 0;
1432
2019
  }
1433
- }
1434
- const v = class v {
2020
+ };
2021
+ class G {
2022
+ id = `adapter-${A()}`;
2023
+ blocConstructor;
2024
+ componentRef = { current: {} };
2025
+ blocInstance;
2026
+ unmountTime = 0;
2027
+ mountTime = 0;
2028
+ // Subscription management
2029
+ subscriptionId;
2030
+ unsubscribe;
2031
+ // Dependency tracking
2032
+ dependencyValues;
2033
+ isUsingDependencies = !1;
2034
+ trackedPaths = /* @__PURE__ */ new Set();
2035
+ pendingTrackedPaths = /* @__PURE__ */ new Set();
2036
+ // Paths tracked before subscription exists
2037
+ // Proxy caching
2038
+ cachedStateProxy;
2039
+ cachedBlocProxy;
2040
+ lastProxiedState;
2041
+ // Lifecycle state
2042
+ hasMounted = !1;
2043
+ mountCount = 0;
2044
+ // Rerender tracking
2045
+ lastState;
2046
+ lastDependencyValues;
2047
+ componentName;
2048
+ renderCount = 0;
2049
+ lastDependenciesFn;
2050
+ options;
1435
2051
  constructor(e, t) {
1436
- i(this, "id", `consumer-${$()}`);
1437
- i(this, "blocConstructor");
1438
- i(this, "componentRef", { current: {} });
1439
- i(this, "blocInstance");
1440
- // Core components
1441
- i(this, "consumerTracker");
1442
- i(this, "lastProps");
1443
- i(this, "unmountTime", 0);
1444
- i(this, "mountTime", 0);
1445
- // Dependency tracking
1446
- i(this, "dependencyValues");
1447
- i(this, "isUsingDependencies", !1);
1448
- // Lifecycle state
1449
- i(this, "hasMounted", !1);
1450
- i(this, "mountCount", 0);
1451
- i(this, "options");
1452
- i(this, "createStateProxy", (e) => b.createStateProxy({
1453
- target: e.target,
1454
- consumerRef: this.componentRef.current,
1455
- consumerTracker: this
1456
- }));
1457
- i(this, "createClassProxy", (e) => b.createClassProxy({
1458
- target: e.target,
1459
- consumerRef: this.componentRef.current,
1460
- consumerTracker: this
1461
- }));
1462
- i(this, "createSubscription", (e) => this.blocInstance._observer.subscribe({
1463
- id: this.id,
1464
- fn: (s, n) => {
1465
- var r;
1466
- if (this.isUsingDependencies && ((r = this.options) != null && r.dependencies)) {
1467
- const o = this.options.dependencies(this.blocInstance);
1468
- if (!this.hasDependencyValuesChanged(
1469
- this.dependencyValues,
1470
- o
1471
- ))
1472
- return;
1473
- this.dependencyValues = o;
1474
- } else if (d.config.proxyDependencyTracking) {
1475
- const o = this.consumerTracker.getConsumerInfo(
1476
- this.componentRef.current
1477
- );
1478
- if (o && o.hasRendered && !this.consumerTracker.hasValuesChanged(
1479
- this.componentRef.current,
1480
- s,
1481
- this.blocInstance
1482
- ))
1483
- return;
1484
- } else {
1485
- e.onChange();
1486
- return;
1487
- }
1488
- e.onChange();
1489
- }
1490
- }));
1491
- i(this, "mount", () => {
1492
- var e, t;
1493
- if (this.isUsingDependencies && ((e = this.options) != null && e.dependencies) && (this.dependencyValues = this.options.dependencies(this.blocInstance)), this.mountCount++, this.blocInstance._addConsumer(this.id, this.componentRef.current), !this.hasMounted && (this.hasMounted = !0, this.mountTime = Date.now(), (t = this.options) != null && t.onMount))
1494
- try {
1495
- this.options.onMount(this.blocInstance);
1496
- } catch (s) {
1497
- throw s;
1498
- }
1499
- });
1500
- i(this, "unmount", () => {
1501
- var e;
1502
- if (this.unmountTime = Date.now(), this.consumerTracker.unregister(this.componentRef.current), this.blocInstance._removeConsumer(this.id), v.propsOwners.get(this.blocInstance) === this.id && v.propsOwners.delete(this.blocInstance), (e = this.options) != null && e.onUnmount)
1503
- try {
1504
- this.options.onUnmount(this.blocInstance);
1505
- } catch {
1506
- }
1507
- });
1508
- i(this, "getProxyState", (e) => this.isUsingDependencies || !d.config.proxyDependencyTracking ? e : b.getProxyState({
1509
- state: e,
1510
- consumerRef: this.componentRef.current,
1511
- consumerTracker: this
1512
- }));
1513
- i(this, "getProxyBlocInstance", () => this.isUsingDependencies || !d.config.proxyDependencyTracking ? this.blocInstance : b.getProxyBlocInstance({
1514
- blocInstance: this.blocInstance,
1515
- consumerRef: this.componentRef.current,
1516
- consumerTracker: this
1517
- }));
1518
- this.options = t, this.blocConstructor = e.blocConstructor, this.componentRef = e.componentRef, this.isUsingDependencies = !!(t != null && t.dependencies), this.consumerTracker = new z(), this.blocInstance = this.updateBlocInstance(), this.consumerTracker.register(e.componentRef.current, this.id), this.isUsingDependencies && (t != null && t.dependencies) && (this.dependencyValues = t.dependencies(this.blocInstance)), (t == null ? void 0 : t.props) !== void 0 && this.updateProps(t.props);
1519
- }
1520
- trackAccess(e, t, s, n) {
1521
- this.consumerTracker.trackAccess(e, t, s, n);
2052
+ this.options = t, this.blocConstructor = e.blocConstructor, this.componentRef = e.componentRef, this.isUsingDependencies = !!t?.dependencies, this.updateBlocInstance(), this.isUsingDependencies && t?.dependencies && (this.dependencyValues = t.dependencies(this.blocInstance));
2053
+ const s = this.getAdapterMetadata();
2054
+ o.getInstance().plugins.notifyAdapterCreated(this, s);
1522
2055
  }
1523
- getConsumerDependencies(e) {
1524
- return this.consumerTracker.getDependencies(e);
1525
- }
1526
- shouldNotifyConsumer(e, t) {
1527
- const s = this.consumerTracker.getConsumerInfo(e);
1528
- return !s || !s.hasRendered ? !0 : this.consumerTracker.shouldNotifyConsumer(e, t);
1529
- }
1530
- updateLastNotified(e) {
1531
- this.consumerTracker.updateLastNotified(e), this.consumerTracker.setHasRendered(e, !0);
1532
- }
1533
- resetConsumerTracking() {
1534
- this.consumerTracker.resetTracking(this.componentRef.current);
2056
+ trackAccess(e, t, s, i) {
2057
+ const n = t === "class" ? `_class.${s}` : s;
2058
+ this.trackedPaths.add(n), this.subscriptionId ? this.blocInstance.trackAccess(this.subscriptionId, n, i) : (this.pendingTrackedPaths.add(n), o.config.logLevel === "debug" && o.log(`[BlacAdapter] trackAccess storing pending path: ${s}`));
1535
2059
  }
1536
2060
  updateBlocInstance() {
1537
- var e, t;
1538
- return this.blocInstance = d.instance.getBloc(this.blocConstructor, {
1539
- props: (e = this.options) == null ? void 0 : e.props,
1540
- id: (t = this.options) == null ? void 0 : t.id,
2061
+ let e = this.options?.instanceId;
2062
+ if (!e && this.options?.staticProps) {
2063
+ const t = N(this.options.staticProps);
2064
+ t && (e = t);
2065
+ }
2066
+ return this.blocInstance = o.instance.getBloc(this.blocConstructor, {
2067
+ constructorParams: this.options?.staticProps,
2068
+ id: e,
1541
2069
  instanceRef: this.id
1542
2070
  }), this.blocInstance;
1543
2071
  }
1544
- // Expose calledOnMount for backward compatibility
1545
- get calledOnMount() {
1546
- return this.hasMounted;
1547
- }
1548
- updateProps(e) {
1549
- const t = this.blocInstance;
1550
- if (v.propsOwners.has(t) || v.propsOwners.set(t, this.id), v.propsOwners.get(t) !== this.id) {
1551
- d.warn(
1552
- `[BlacAdapter] Attempted to set props on ${t.constructor.name} from non-owner adapter`
2072
+ createSubscription = (e) => {
2073
+ if (this.isUsingDependencies && this.options?.dependencies)
2074
+ this.unsubscribe = this.blocInstance.subscribeWithSelector(
2075
+ (t) => this.options.dependencies(this.blocInstance),
2076
+ (t) => {
2077
+ this.hasDependencyValuesChanged(
2078
+ this.dependencyValues,
2079
+ t
2080
+ ) && (this.dependencyValues = t, e.onChange());
2081
+ }
1553
2082
  );
1554
- return;
2083
+ else {
2084
+ const t = new WeakRef(this.componentRef.current);
2085
+ this.unsubscribe = this.blocInstance.subscribeComponent(
2086
+ t,
2087
+ e.onChange
2088
+ );
2089
+ const s = this.blocInstance._subscriptionManager.subscriptions;
2090
+ if (this.subscriptionId = Array.from(s.keys()).pop(), this.subscriptionId && this.pendingTrackedPaths.size > 0) {
2091
+ for (const i of this.pendingTrackedPaths)
2092
+ this.blocInstance.trackAccess(this.subscriptionId, i);
2093
+ this.pendingTrackedPaths.clear();
2094
+ }
1555
2095
  }
1556
- t._disposalState === _.DISPOSED || t._disposalState === _.DISPOSING || j(this.lastProps, e) || ("add" in t && typeof t.add == "function" ? t.add(new N(e)) : "_updateProps" in t && typeof t._updateProps == "function" && t._updateProps(e), this.lastProps = e);
1557
- }
1558
- hasDependencyValuesChanged(e, t) {
2096
+ return () => {
2097
+ this.unsubscribe && (this.unsubscribe(), this.unsubscribe = void 0, this.subscriptionId = void 0);
2098
+ };
2099
+ };
2100
+ hasDependencyValuesChanged = (e, t) => {
1559
2101
  if (!e || e.length !== t.length) return !0;
1560
2102
  for (let s = 0; s < e.length; s++)
1561
2103
  if (!Object.is(e[s], t[s]))
1562
2104
  return !0;
1563
2105
  return !1;
2106
+ };
2107
+ getStateProxy = () => {
2108
+ if (this.isUsingDependencies || !o.config.proxyDependencyTracking)
2109
+ return this.blocInstance.state;
2110
+ const e = this.blocInstance.state;
2111
+ return this.cachedStateProxy && this.lastProxiedState === e ? this.cachedStateProxy : (this.lastProxiedState = e, this.cachedStateProxy = this.createStateProxy({ target: e }), this.cachedStateProxy);
2112
+ };
2113
+ getBlocProxy = () => this.isUsingDependencies || !o.config.proxyDependencyTracking ? this.blocInstance : this.cachedBlocProxy ? this.cachedBlocProxy : (this.cachedBlocProxy = this.createClassProxy({ target: this.blocInstance }), this.cachedBlocProxy);
2114
+ createStateProxy = (e) => $.createStateProxy({
2115
+ target: e.target,
2116
+ consumerRef: this.componentRef.current,
2117
+ consumerTracker: this
2118
+ });
2119
+ createClassProxy = (e) => $.createClassProxy({
2120
+ target: e.target,
2121
+ consumerRef: this.componentRef.current,
2122
+ consumerTracker: this
2123
+ });
2124
+ // Lifecycle methods
2125
+ mount = () => {
2126
+ this.hasMounted = !0, this.mountCount++, this.mountTime = Date.now(), this.options?.onMount && this.options.onMount(this.blocInstance), this.isUsingDependencies && this.options?.dependencies && (this.dependencyValues = this.options.dependencies(this.blocInstance));
2127
+ const e = this.getAdapterMetadata();
2128
+ o.getInstance().plugins.notifyAdapterMount(this, e);
2129
+ };
2130
+ unmount = () => {
2131
+ if (this.unmountTime = Date.now(), this.unsubscribe && (this.unsubscribe(), this.unsubscribe = void 0, this.subscriptionId = void 0), this.options?.onUnmount)
2132
+ try {
2133
+ this.options.onUnmount(this.blocInstance);
2134
+ } catch (t) {
2135
+ console.error("Error in onUnmount hook:", t);
2136
+ }
2137
+ const e = this.getAdapterMetadata();
2138
+ o.getInstance().plugins.notifyAdapterUnmount(this, e);
2139
+ };
2140
+ // Reset tracking for next render
2141
+ resetTracking() {
2142
+ if (this.trackedPaths.clear(), this.pendingTrackedPaths.clear(), this.subscriptionId) {
2143
+ const e = this.blocInstance._subscriptionManager.subscriptions.get(this.subscriptionId);
2144
+ e && e.dependencies && e.dependencies.clear();
2145
+ }
1564
2146
  }
1565
- };
1566
- // Props ownership tracking
1567
- i(v, "propsOwners", /* @__PURE__ */ new WeakMap());
1568
- let R = v;
2147
+ // Set component name for rerender logging
2148
+ setComponentName(e) {
2149
+ this.componentName = e;
2150
+ }
2151
+ // Notify plugins about render
2152
+ notifyRender() {
2153
+ this.renderCount++, this.isUsingDependencies && this.options?.dependencies && (this.lastDependencyValues = this.dependencyValues, this.dependencyValues = this.options.dependencies(this.blocInstance));
2154
+ const e = this.getAdapterMetadata();
2155
+ o.getInstance().plugins.notifyAdapterRender(this, e);
2156
+ }
2157
+ // Get adapter metadata for plugins
2158
+ getAdapterMetadata() {
2159
+ return {
2160
+ componentName: this.componentName,
2161
+ blocInstance: this.blocInstance,
2162
+ renderCount: this.renderCount,
2163
+ trackedPaths: Array.from(this.trackedPaths),
2164
+ isUsingDependencies: this.isUsingDependencies,
2165
+ lastState: this.lastState,
2166
+ lastDependencyValues: this.lastDependencyValues,
2167
+ currentDependencyValues: this.dependencyValues
2168
+ };
2169
+ }
2170
+ // Get value at a dot-notated path
2171
+ getValueAtPath(e, t) {
2172
+ const s = t.split(".");
2173
+ let i = e;
2174
+ for (const n of s) {
2175
+ if (i == null) return;
2176
+ i = i[n];
2177
+ }
2178
+ return i;
2179
+ }
2180
+ // Get paths that changed between states
2181
+ getStateChangedPaths(e, t) {
2182
+ const s = [];
2183
+ if (this.trackedPaths.size > 0)
2184
+ for (const i of this.trackedPaths) {
2185
+ if (i.startsWith("_class.")) continue;
2186
+ const n = this.getValueAtPath(e, i), a = this.getValueAtPath(t, i);
2187
+ Object.is(n, a) || s.push(i);
2188
+ }
2189
+ else if (e !== t) {
2190
+ const i = this.getDeepChangedPaths(e, t);
2191
+ if (i.length > 0)
2192
+ return i;
2193
+ s.push("(entire state)");
2194
+ }
2195
+ return s;
2196
+ }
2197
+ // Deep comparison to find all changed paths
2198
+ getDeepChangedPaths(e, t, s = "") {
2199
+ const i = [];
2200
+ if (e === t) return i;
2201
+ if (e == null || t == null)
2202
+ return i.push(s || "(root)"), i;
2203
+ if (typeof e != "object" || typeof t != "object")
2204
+ return e !== t && i.push(s || "(root)"), i;
2205
+ if (Array.isArray(e) || Array.isArray(t)) {
2206
+ if (!Array.isArray(e) || !Array.isArray(t) || e.length !== t.length)
2207
+ return i.push(s || "(root)"), i;
2208
+ for (let a = 0; a < e.length; a++) {
2209
+ const c = s ? `${s}[${a}]` : `[${a}]`;
2210
+ i.push(
2211
+ ...this.getDeepChangedPaths(e[a], t[a], c)
2212
+ );
2213
+ }
2214
+ return i;
2215
+ }
2216
+ const n = /* @__PURE__ */ new Set([...Object.keys(e), ...Object.keys(t)]);
2217
+ for (const a of n) {
2218
+ const c = s ? `${s}.${a}` : a;
2219
+ if (!(a in e))
2220
+ i.push(`${c} (added)`);
2221
+ else if (!(a in t))
2222
+ i.push(`${c} (removed)`);
2223
+ else {
2224
+ const l = e[a], h = t[a];
2225
+ if (!Object.is(l, h))
2226
+ if (typeof l != "object" || typeof h != "object" || l === null || h === null)
2227
+ i.push(c);
2228
+ else {
2229
+ const p = this.getDeepChangedPaths(
2230
+ l,
2231
+ h,
2232
+ c
2233
+ );
2234
+ p.length > 0 ? i.push(...p) : i.push(c);
2235
+ }
2236
+ }
2237
+ }
2238
+ return i;
2239
+ }
2240
+ // Get last rerender reason
2241
+ getLastRerenderReason() {
2242
+ }
2243
+ }
1569
2244
  export {
1570
- d as Blac,
1571
- R as BlacAdapter,
1572
- V as BlacObservable,
1573
- U as Bloc,
1574
- x as BlocBase,
1575
- _ as BlocLifecycleState,
1576
- L as BlocTest,
1577
- z as ConsumerTracker,
1578
- H as Cubit,
1579
- F as MemoryLeakDetector,
1580
- Q as MockBloc,
1581
- W as MockCubit,
1582
- N as PropsUpdated,
1583
- b as ProxyFactory,
1584
- $ as generateUUID,
1585
- q as setBlacInstanceManager,
1586
- j as shallowEqual
2245
+ o as Blac,
2246
+ G as BlacAdapter,
2247
+ m as BlacError,
2248
+ R as Bloc,
2249
+ C as BlocBase,
2250
+ B as BlocLifecycleManager,
2251
+ u as BlocLifecycleState,
2252
+ w as BlocPluginRegistry,
2253
+ j as BlocTest,
2254
+ O as Cubit,
2255
+ P as DefaultErrorStrategy,
2256
+ v as ErrorCategory,
2257
+ f as ErrorManager,
2258
+ y as ErrorSeverity,
2259
+ W as MemoryLeakDetector,
2260
+ z as MockBloc,
2261
+ q as MockCubit,
2262
+ L as PropsUpdated,
2263
+ $ as ProxyFactory,
2264
+ F as RerenderLogger,
2265
+ E as SubscriptionManager,
2266
+ T as SystemPluginRegistry,
2267
+ M as createBlocProxy,
2268
+ _ as createStateProxy,
2269
+ N as generateInstanceIdFromProps,
2270
+ A as generateUUID,
2271
+ x as handleError,
2272
+ H as setBlacInstanceManager,
2273
+ V as shallowEqual
1587
2274
  };
1588
2275
  //# sourceMappingURL=index.es.js.map