@blac/core 2.0.0-rc-8 → 2.0.0-rc-10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +2 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +185 -4
- package/dist/index.es.js +1099 -601
- package/dist/index.es.js.map +1 -1
- package/package.json +5 -4
- package/src/Blac.ts +63 -40
- package/src/BlacObserver.ts +58 -24
- package/src/Bloc.ts +166 -157
- package/src/BlocBase.ts +266 -90
- package/src/Cubit.ts +1 -1
- package/src/__tests__/Bloc.event.test.ts +419 -0
- package/src/__tests__/BlocBase.lifecycle.test.ts +441 -0
- package/src/__tests__/Cubit.test.ts +473 -0
- package/src/adapter/BlacAdapter.ts +262 -0
- package/src/adapter/ConsumerTracker.ts +241 -0
- package/src/adapter/ProxyFactory.ts +308 -0
- package/src/adapter/__tests__/BlacAdapter.test.ts +561 -0
- package/src/adapter/__tests__/ConsumerTracker.test.ts +562 -0
- package/src/adapter/__tests__/ProxyFactory.test.ts +655 -0
- package/src/adapter/index.ts +3 -0
- package/src/index.ts +2 -1
- package/src/testing.ts +60 -47
- package/src/types.ts +11 -3
- package/src/utils/uuid.ts +4 -4
- package/src/BlacEvent.ts +0 -5
package/dist/index.es.js
CHANGED
|
@@ -1,393 +1,15 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
getInstance() {
|
|
6
|
-
return u._instance || (u._instance = new l({
|
|
7
|
-
__unsafe_ignore_singleton: !0
|
|
8
|
-
})), u._instance;
|
|
9
|
-
}
|
|
10
|
-
setInstance(e) {
|
|
11
|
-
u._instance = e;
|
|
12
|
-
}
|
|
13
|
-
resetInstance() {
|
|
14
|
-
const e = u._instance;
|
|
15
|
-
if (u._instance = new l({
|
|
16
|
-
__unsafe_ignore_singleton: !0
|
|
17
|
-
}), e)
|
|
18
|
-
for (const t of e.keepAliveBlocs)
|
|
19
|
-
u._instance.keepAliveBlocs.add(t), u._instance.uidRegistry.set(t.uid, t);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
i(u, "_instance");
|
|
23
|
-
let B = u, g = new B();
|
|
24
|
-
function A(d) {
|
|
25
|
-
g = d;
|
|
26
|
-
}
|
|
27
|
-
const r = class r {
|
|
28
|
-
/**
|
|
29
|
-
* Creates a new Blac instance.
|
|
30
|
-
* @param options - Configuration options including singleton control
|
|
31
|
-
*/
|
|
32
|
-
constructor(e = {}) {
|
|
33
|
-
/** Timestamp when the instance was created */
|
|
34
|
-
i(this, "createdAt", Date.now());
|
|
35
|
-
/** Map storing all registered bloc instances by their class name and ID */
|
|
36
|
-
i(this, "blocInstanceMap", /* @__PURE__ */ new Map());
|
|
37
|
-
/** Map storing isolated bloc instances grouped by their constructor */
|
|
38
|
-
// TODO: BlocConstructor<any> is required here for type inference to work correctly.
|
|
39
|
-
// Using BlocConstructor<BlocBase<unknown>> would break type inference when storing
|
|
40
|
-
// different bloc types in the same map. The 'any' allows proper polymorphic storage
|
|
41
|
-
// while maintaining type safety at usage sites through the BlocConstructor constraint.
|
|
42
|
-
i(this, "isolatedBlocMap", /* @__PURE__ */ new Map());
|
|
43
|
-
/** Map for O(1) lookup of isolated blocs by UID */
|
|
44
|
-
i(this, "isolatedBlocIndex", /* @__PURE__ */ new Map());
|
|
45
|
-
/** Map tracking UIDs to prevent memory leaks */
|
|
46
|
-
i(this, "uidRegistry", /* @__PURE__ */ new Map());
|
|
47
|
-
/** Set of keep-alive blocs for controlled cleanup */
|
|
48
|
-
i(this, "keepAliveBlocs", /* @__PURE__ */ new Set());
|
|
49
|
-
/** Flag to control whether changes should be posted to document */
|
|
50
|
-
i(this, "postChangesToDocument", !1);
|
|
51
|
-
/**
|
|
52
|
-
* Logs messages to console when logging is enabled
|
|
53
|
-
* @param args - Arguments to log
|
|
54
|
-
*/
|
|
55
|
-
i(this, "log", (...e) => {
|
|
56
|
-
r.enableLog && r.logLevel === "warn" && console.warn(`☢️ [Blac ${this.createdAt.toString()}]`, ...e), r.enableLog && r.logLevel === "log" && console.log(`☢️ [Blac ${this.createdAt.toString()}]`, ...e);
|
|
57
|
-
});
|
|
58
|
-
/**
|
|
59
|
-
* Logs a warning message
|
|
60
|
-
* @param message - Warning message
|
|
61
|
-
* @param args - Additional arguments
|
|
62
|
-
*/
|
|
63
|
-
i(this, "warn", (e, ...t) => {
|
|
64
|
-
r.enableLog && console.warn(
|
|
65
|
-
`🚨 [Blac ${String(r.instance.createdAt)}]`,
|
|
66
|
-
e,
|
|
67
|
-
...t
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
/**
|
|
71
|
-
* Logs an error message
|
|
72
|
-
* @param message - Error message
|
|
73
|
-
* @param args - Additional arguments
|
|
74
|
-
*/
|
|
75
|
-
i(this, "error", (e, ...t) => {
|
|
76
|
-
r.enableLog && console.error(
|
|
77
|
-
`🚨 [Blac ${String(r.instance.createdAt)}]`,
|
|
78
|
-
e,
|
|
79
|
-
...t
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
/**
|
|
83
|
-
* Resets the Blac instance to a new one, disposing non-keepAlive blocs
|
|
84
|
-
* from the old instance.
|
|
85
|
-
*/
|
|
86
|
-
i(this, "resetInstance", () => {
|
|
87
|
-
this.log("Reset Blac instance");
|
|
88
|
-
const e = new Map(this.blocInstanceMap), t = new Map(this.isolatedBlocMap);
|
|
89
|
-
e.forEach((s) => {
|
|
90
|
-
!s._keepAlive && s._disposalState === "active" && this.disposeBloc(s);
|
|
91
|
-
}), t.forEach((s) => {
|
|
92
|
-
s.forEach((n) => {
|
|
93
|
-
!n._keepAlive && n._disposalState === "active" && this.disposeBloc(n);
|
|
94
|
-
});
|
|
95
|
-
}), this.blocInstanceMap.clear(), this.isolatedBlocMap.clear(), this.isolatedBlocIndex.clear(), g.resetInstance();
|
|
96
|
-
});
|
|
97
|
-
/**
|
|
98
|
-
* Disposes of a bloc instance by removing it from the appropriate registry
|
|
99
|
-
* @param bloc - The bloc instance to dispose
|
|
100
|
-
*/
|
|
101
|
-
i(this, "disposeBloc", (e) => {
|
|
102
|
-
if (e._disposalState !== "active") {
|
|
103
|
-
this.log(
|
|
104
|
-
`[${e._name}:${String(e._id)}] disposeBloc called on already disposed bloc`
|
|
105
|
-
);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
const t = e.constructor, s = this.createBlocInstanceMapKey(e._name, e._id);
|
|
109
|
-
this.log(
|
|
110
|
-
`[${e._name}:${String(e._id)}] disposeBloc called. Isolated: ${String(t.isolated)}`
|
|
111
|
-
), e._dispose(), t.isolated ? (this.unregisterIsolatedBlocInstance(e), this.blocInstanceMap.delete(s)) : this.unregisterBlocInstance(e), this.log("dispatched bloc", e);
|
|
112
|
-
});
|
|
113
|
-
i(this, "activateBloc", (e) => {
|
|
114
|
-
if (e._disposalState !== "active") {
|
|
115
|
-
this.log(
|
|
116
|
-
`[${e._name}:${String(e._id)}] activateBloc called on disposed bloc. Ignoring.`
|
|
117
|
-
);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const t = e.constructor;
|
|
121
|
-
(e.isIsolated ? this.findIsolatedBlocInstance(t, e._id) : this.findRegisteredBlocInstance(t, e._id)) || (this.log(
|
|
122
|
-
`[${e._name}:${String(e._id)}] activateBloc called. Isolated: ${String(e.isIsolated)}`
|
|
123
|
-
), e.isIsolated ? this.registerIsolatedBlocInstance(e) : this.registerBlocInstance(e));
|
|
124
|
-
});
|
|
125
|
-
/**
|
|
126
|
-
* Gets or creates a bloc instance based on the provided class and options.
|
|
127
|
-
* If a bloc with the given ID exists, it will be returned. Otherwise, a new instance will be created.
|
|
128
|
-
*
|
|
129
|
-
* @param blocClass - The bloc class to get or create
|
|
130
|
-
* @param options - Options including:
|
|
131
|
-
* - id: The instance ID (defaults to class name if not provided)
|
|
132
|
-
* - props: Properties to pass to the bloc constructor
|
|
133
|
-
* - instanceRef: Optional reference string for the instance
|
|
134
|
-
* @returns The bloc instance
|
|
135
|
-
*/
|
|
136
|
-
i(this, "getBloc", (e, t = {}) => {
|
|
137
|
-
const { id: s } = t, n = e, o = s ?? e.name;
|
|
138
|
-
if (n.isolated) {
|
|
139
|
-
const c = this.findIsolatedBlocInstance(e, o);
|
|
140
|
-
if (c)
|
|
141
|
-
return c;
|
|
142
|
-
if (t.throwIfNotFound)
|
|
143
|
-
throw new Error(`Isolated bloc ${e.name} not found`);
|
|
144
|
-
} else {
|
|
145
|
-
const c = this.findRegisteredBlocInstance(e, o);
|
|
146
|
-
if (c)
|
|
147
|
-
return c;
|
|
148
|
-
if (t.throwIfNotFound)
|
|
149
|
-
throw new Error(`Registered bloc ${e.name} not found`);
|
|
150
|
-
}
|
|
151
|
-
const a = this.createNewBlocInstance(e, o, t);
|
|
152
|
-
if (this.log(
|
|
153
|
-
`[${e.name}:${String(o)}] (getBloc) No existing instance found. Creating new one.`,
|
|
154
|
-
t,
|
|
155
|
-
a
|
|
156
|
-
), !a)
|
|
157
|
-
throw new Error(
|
|
158
|
-
`[getBloc] Failed to create bloc instance for ${e.name}. This should never happen.`
|
|
159
|
-
);
|
|
160
|
-
return a;
|
|
161
|
-
});
|
|
162
|
-
/**
|
|
163
|
-
* Gets a bloc instance or throws an error if it doesn't exist
|
|
164
|
-
* @param blocClass - The bloc class to get
|
|
165
|
-
* @param options - Options including:
|
|
166
|
-
* - id: The instance ID (defaults to class name if not provided)
|
|
167
|
-
* - props: Properties to pass to the bloc constructor
|
|
168
|
-
* - instanceRef: Optional reference string for the instance
|
|
169
|
-
*/
|
|
170
|
-
i(this, "getBlocOrThrow", (e, t = {}) => {
|
|
171
|
-
const s = e.isolated, n = t.id || e.name, o = s ? this.findIsolatedBlocInstance(e, n) : this.findRegisteredBlocInstance(e, n);
|
|
172
|
-
if (o)
|
|
173
|
-
return o;
|
|
174
|
-
throw new Error(`Bloc ${e.name} not found`);
|
|
175
|
-
});
|
|
176
|
-
/**
|
|
177
|
-
* Gets all instances of a specific bloc class
|
|
178
|
-
* @param blocClass - The bloc class to search for
|
|
179
|
-
* @param options - Options including:
|
|
180
|
-
* - searchIsolated: Whether to search in isolated blocs (defaults to bloc's isolated property)
|
|
181
|
-
* @returns Array of matching bloc instances
|
|
182
|
-
*/
|
|
183
|
-
i(this, "getAllBlocs", (e, t = {}) => {
|
|
184
|
-
const s = [];
|
|
185
|
-
if (this.blocInstanceMap.forEach((n) => {
|
|
186
|
-
n.constructor === e && s.push(n);
|
|
187
|
-
}), t.searchIsolated !== !1) {
|
|
188
|
-
const n = this.isolatedBlocMap.get(e);
|
|
189
|
-
n && s.push(...n.map((o) => o));
|
|
190
|
-
}
|
|
191
|
-
return s;
|
|
192
|
-
});
|
|
193
|
-
/**
|
|
194
|
-
* Disposes all keep-alive blocs of a specific type
|
|
195
|
-
* @param blocClass - The bloc class to dispose
|
|
196
|
-
*/
|
|
197
|
-
i(this, "disposeKeepAliveBlocs", (e) => {
|
|
198
|
-
const t = [];
|
|
199
|
-
for (const s of this.keepAliveBlocs)
|
|
200
|
-
(!e || s.constructor === e) && t.push(s);
|
|
201
|
-
t.forEach((s) => s._dispose());
|
|
202
|
-
});
|
|
203
|
-
/**
|
|
204
|
-
* Disposes all blocs matching a pattern
|
|
205
|
-
* @param predicate - Function to test each bloc for disposal
|
|
206
|
-
*/
|
|
207
|
-
i(this, "disposeBlocs", (e) => {
|
|
208
|
-
const t = [];
|
|
209
|
-
for (const s of this.blocInstanceMap.values())
|
|
210
|
-
e(s) && t.push(s);
|
|
211
|
-
for (const s of this.isolatedBlocMap.values())
|
|
212
|
-
for (const n of s)
|
|
213
|
-
e(n) && t.push(n);
|
|
214
|
-
t.forEach((s) => s._dispose());
|
|
215
|
-
});
|
|
216
|
-
/**
|
|
217
|
-
* Gets memory usage statistics for debugging
|
|
218
|
-
*/
|
|
219
|
-
i(this, "getMemoryStats", () => ({
|
|
220
|
-
totalBlocs: this.uidRegistry.size,
|
|
221
|
-
registeredBlocs: this.blocInstanceMap.size,
|
|
222
|
-
isolatedBlocs: Array.from(this.isolatedBlocMap.values()).reduce(
|
|
223
|
-
(e, t) => e + t.length,
|
|
224
|
-
0
|
|
225
|
-
),
|
|
226
|
-
keepAliveBlocs: this.keepAliveBlocs.size,
|
|
227
|
-
isolatedBlocTypes: this.isolatedBlocMap.size
|
|
228
|
-
}));
|
|
229
|
-
/**
|
|
230
|
-
* Validates consumer references and cleans up orphaned consumers
|
|
231
|
-
*/
|
|
232
|
-
i(this, "validateConsumers", () => {
|
|
233
|
-
for (const e of this.uidRegistry.values())
|
|
234
|
-
e._validateConsumers(), e._consumers.size === 0 && !e._keepAlive && e._disposalState === "active" && setTimeout(() => {
|
|
235
|
-
e._consumers.size === 0 && !e._keepAlive && e._disposalState === "active" && this.disposeBloc(e);
|
|
236
|
-
}, 1e3);
|
|
237
|
-
});
|
|
238
|
-
const { __unsafe_ignore_singleton: t = !1 } = e;
|
|
239
|
-
if (!t)
|
|
240
|
-
return r.instance;
|
|
241
|
-
g.setInstance(this);
|
|
242
|
-
}
|
|
243
|
-
/** @deprecated Use getInstance() instead */
|
|
244
|
-
static get instance() {
|
|
245
|
-
return g.getInstance();
|
|
246
|
-
}
|
|
247
|
-
static get getAllBlocs() {
|
|
248
|
-
return r.instance.getAllBlocs;
|
|
249
|
-
}
|
|
250
|
-
static get log() {
|
|
251
|
-
return r.instance.log;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Gets the current Blac instance
|
|
255
|
-
* @returns The Blac instance
|
|
256
|
-
*/
|
|
257
|
-
static getInstance() {
|
|
258
|
-
return g.getInstance();
|
|
259
|
-
}
|
|
260
|
-
static get warn() {
|
|
261
|
-
return r.instance.warn;
|
|
262
|
-
}
|
|
263
|
-
static get error() {
|
|
264
|
-
return r.instance.error;
|
|
265
|
-
}
|
|
266
|
-
static get disposeBloc() {
|
|
267
|
-
return r.instance.disposeBloc;
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Creates a unique key for a bloc instance in the map based on the bloc class name and instance ID
|
|
271
|
-
* @param blocClassName - The name of the bloc class
|
|
272
|
-
* @param id - The instance ID
|
|
273
|
-
* @returns A unique key string in the format "className:id"
|
|
274
|
-
*/
|
|
275
|
-
createBlocInstanceMapKey(e, t) {
|
|
276
|
-
return `${e}:${String(t)}`;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Unregister a bloc instance from the main registry
|
|
280
|
-
* @param bloc - The bloc instance to unregister
|
|
281
|
-
*/
|
|
282
|
-
unregisterBlocInstance(e) {
|
|
283
|
-
const t = this.createBlocInstanceMapKey(e._name, e._id);
|
|
284
|
-
this.blocInstanceMap.delete(t), this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e);
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Registers a bloc instance in the main registry
|
|
288
|
-
* @param bloc - The bloc instance to register
|
|
289
|
-
*/
|
|
290
|
-
registerBlocInstance(e) {
|
|
291
|
-
const t = this.createBlocInstanceMapKey(e._name, e._id);
|
|
292
|
-
this.blocInstanceMap.set(t, e), this.uidRegistry.set(e.uid, e), e._keepAlive && this.keepAliveBlocs.add(e);
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Finds a registered bloc instance by its class and ID
|
|
296
|
-
* @param blocClass - The bloc class to search for
|
|
297
|
-
* @param id - The instance ID
|
|
298
|
-
* @returns The found bloc instance or undefined if not found
|
|
299
|
-
*/
|
|
300
|
-
findRegisteredBlocInstance(e, t) {
|
|
301
|
-
if (e.isolated) return;
|
|
302
|
-
const n = this.createBlocInstanceMapKey(e.name, t);
|
|
303
|
-
return this.blocInstanceMap.get(n);
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Registers an isolated bloc instance in the isolated registry
|
|
307
|
-
* @param bloc - The isolated bloc instance to register
|
|
308
|
-
*/
|
|
309
|
-
registerIsolatedBlocInstance(e) {
|
|
310
|
-
const t = e.constructor, s = this.isolatedBlocMap.get(t);
|
|
311
|
-
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);
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Unregister an isolated bloc instance from the isolated registry
|
|
315
|
-
* @param bloc - The isolated bloc instance to unregister
|
|
316
|
-
*/
|
|
317
|
-
unregisterIsolatedBlocInstance(e) {
|
|
318
|
-
const t = e.constructor, s = this.isolatedBlocMap.get(t);
|
|
319
|
-
let n = !1;
|
|
320
|
-
if (s) {
|
|
321
|
-
const a = s.findIndex((c) => c.uid === e.uid);
|
|
322
|
-
a !== -1 && (s.splice(a, 1), n = !0), s.length === 0 && this.isolatedBlocMap.delete(t);
|
|
323
|
-
}
|
|
324
|
-
const o = this.isolatedBlocIndex.delete(e.uid);
|
|
325
|
-
this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e), n !== o && this.warn(
|
|
326
|
-
`[Blac] Inconsistent state detected during isolated bloc cleanup for ${e._name}:${e.uid}. Map removal: ${n}, Index removal: ${o}`
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Finds an isolated bloc instance by its class and ID (O(n) lookup)
|
|
331
|
-
*/
|
|
332
|
-
findIsolatedBlocInstance(e, t) {
|
|
333
|
-
if (!e.isolated) return;
|
|
334
|
-
const n = this.isolatedBlocMap.get(e);
|
|
335
|
-
return n ? n.find((a) => a._id === t) : void 0;
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Finds an isolated bloc instance by UID (O(1) lookup)
|
|
339
|
-
*/
|
|
340
|
-
findIsolatedBlocInstanceByUid(e) {
|
|
341
|
-
return this.isolatedBlocIndex.get(e);
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Creates a new bloc instance and registers it in the appropriate registry
|
|
345
|
-
* @param blocClass - The bloc class to instantiate
|
|
346
|
-
* @param id - The instance ID
|
|
347
|
-
* @param props - Properties to pass to the bloc constructor
|
|
348
|
-
* @param instanceRef - Optional reference string for the instance
|
|
349
|
-
* @returns The newly created bloc instance
|
|
350
|
-
*/
|
|
351
|
-
createNewBlocInstance(e, t, s = {}) {
|
|
352
|
-
const { props: n, instanceRef: o } = s, a = new e(n);
|
|
353
|
-
return a._instanceRef = o, a.props = n || null, a._updateId(t), a._setDisposalHandler((c) => this.disposeBloc(c)), a.isIsolated ? (this.registerIsolatedBlocInstance(a), a) : (this.registerBlocInstance(a), a);
|
|
354
|
-
}
|
|
355
|
-
static get activateBloc() {
|
|
356
|
-
return r.instance.activateBloc;
|
|
357
|
-
}
|
|
358
|
-
static get getBloc() {
|
|
359
|
-
return r.instance.getBloc;
|
|
360
|
-
}
|
|
361
|
-
static get getBlocOrThrow() {
|
|
362
|
-
return r.instance.getBlocOrThrow;
|
|
363
|
-
}
|
|
364
|
-
static get disposeKeepAliveBlocs() {
|
|
365
|
-
return r.instance.disposeKeepAliveBlocs;
|
|
366
|
-
}
|
|
367
|
-
static get disposeBlocs() {
|
|
368
|
-
return r.instance.disposeBlocs;
|
|
369
|
-
}
|
|
370
|
-
static get getMemoryStats() {
|
|
371
|
-
return r.instance.getMemoryStats;
|
|
372
|
-
}
|
|
373
|
-
static get validateConsumers() {
|
|
374
|
-
return r.instance.validateConsumers;
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
/** Flag to enable/disable logging */
|
|
378
|
-
i(r, "enableLog", !1), i(r, "logLevel", "warn"), i(r, "resetInstance", () => {
|
|
379
|
-
g.resetInstance();
|
|
380
|
-
});
|
|
381
|
-
let l = r;
|
|
382
|
-
class w {
|
|
1
|
+
var M = Object.defineProperty;
|
|
2
|
+
var P = (u, e, t) => e in u ? M(u, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : u[e] = t;
|
|
3
|
+
var n = (u, e, t) => P(u, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
class E {
|
|
383
5
|
/**
|
|
384
6
|
* Creates a new BlacObservable instance
|
|
385
7
|
* @param bloc - The Bloc instance to observe
|
|
386
8
|
*/
|
|
387
9
|
constructor(e) {
|
|
388
10
|
/** The Bloc instance this observable is associated with */
|
|
389
|
-
|
|
390
|
-
|
|
11
|
+
n(this, "bloc");
|
|
12
|
+
n(this, "_observers", /* @__PURE__ */ new Set());
|
|
391
13
|
this.bloc = e;
|
|
392
14
|
}
|
|
393
15
|
/**
|
|
@@ -410,16 +32,38 @@ class w {
|
|
|
410
32
|
* @returns A function that can be called to unsubscribe the observer
|
|
411
33
|
*/
|
|
412
34
|
subscribe(e) {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
35
|
+
const t = this.bloc._disposalState;
|
|
36
|
+
return t === _.DISPOSED || t === _.DISPOSING ? (f.log(
|
|
37
|
+
"BlacObservable.subscribe: Cannot subscribe to disposed/disposing bloc.",
|
|
38
|
+
this.bloc,
|
|
39
|
+
e
|
|
40
|
+
), () => {
|
|
41
|
+
}) : (f.log(
|
|
42
|
+
"BlacObservable.subscribe: Subscribing observer.",
|
|
43
|
+
this.bloc,
|
|
44
|
+
e
|
|
45
|
+
), this._observers.add(e), t === _.DISPOSAL_REQUESTED && (f.log(
|
|
46
|
+
"BlacObservable.subscribe: Cancelling disposal due to new subscription.",
|
|
47
|
+
this.bloc
|
|
48
|
+
), this.bloc._atomicStateTransition(
|
|
49
|
+
_.DISPOSAL_REQUESTED,
|
|
50
|
+
_.ACTIVE
|
|
51
|
+
)), () => {
|
|
52
|
+
f.log(
|
|
53
|
+
"BlacObservable.subscribe: Unsubscribing observer.",
|
|
54
|
+
this.bloc,
|
|
55
|
+
e
|
|
56
|
+
), this.unsubscribe(e);
|
|
57
|
+
});
|
|
416
58
|
}
|
|
417
59
|
/**
|
|
418
60
|
* Unsubscribes an observer from state changes
|
|
419
61
|
* @param observer - The observer to unsubscribe
|
|
420
62
|
*/
|
|
421
63
|
unsubscribe(e) {
|
|
422
|
-
this._observers.delete(e), this.size === 0 && (
|
|
64
|
+
this._observers.delete(e), this.size === 0 && (f.log("BlacObservable.unsubscribe: No observers left.", this.bloc), this.bloc._consumers.size === 0 && !this.bloc._keepAlive && this.bloc._disposalState === _.ACTIVE && (f.log(
|
|
65
|
+
`[${this.bloc._name}:${this.bloc._id}] No observers or consumers left. Scheduling disposal.`
|
|
66
|
+
), this.bloc._scheduleDisposal()));
|
|
423
67
|
}
|
|
424
68
|
/**
|
|
425
69
|
* Notifies all observers of a state change
|
|
@@ -428,32 +72,28 @@ class w {
|
|
|
428
72
|
* @param action - Optional action that triggered the state change
|
|
429
73
|
*/
|
|
430
74
|
notify(e, t, s) {
|
|
431
|
-
this._observers.forEach((
|
|
432
|
-
let
|
|
433
|
-
if (
|
|
434
|
-
const a =
|
|
75
|
+
this._observers.forEach((i) => {
|
|
76
|
+
let r = !1;
|
|
77
|
+
if (i.dependencyArray) {
|
|
78
|
+
const a = i.lastState, o = i.dependencyArray(
|
|
79
|
+
e,
|
|
80
|
+
t,
|
|
81
|
+
this.bloc
|
|
82
|
+
);
|
|
435
83
|
if (!a)
|
|
436
|
-
|
|
437
|
-
else if (a.length !==
|
|
438
|
-
|
|
84
|
+
r = !0;
|
|
85
|
+
else if (a.length !== o.length)
|
|
86
|
+
r = !0;
|
|
439
87
|
else
|
|
440
|
-
for (let
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
o = !0;
|
|
88
|
+
for (let l = 0; l < o.length; l++)
|
|
89
|
+
if (!Object.is(a[l], o[l])) {
|
|
90
|
+
r = !0;
|
|
444
91
|
break;
|
|
445
92
|
}
|
|
446
|
-
|
|
447
|
-
if (!Object.is(_[f], p[f])) {
|
|
448
|
-
o = !0;
|
|
449
|
-
break;
|
|
450
|
-
}
|
|
451
|
-
if (o) break;
|
|
452
|
-
}
|
|
453
|
-
n.lastState = c;
|
|
93
|
+
i.lastState = o;
|
|
454
94
|
} else
|
|
455
|
-
|
|
456
|
-
|
|
95
|
+
r = !0;
|
|
96
|
+
r && i.fn(e, t, s);
|
|
457
97
|
});
|
|
458
98
|
}
|
|
459
99
|
/**
|
|
@@ -463,97 +103,103 @@ class w {
|
|
|
463
103
|
this._observers.clear();
|
|
464
104
|
}
|
|
465
105
|
}
|
|
466
|
-
function
|
|
467
|
-
return typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(
|
|
106
|
+
function R() {
|
|
107
|
+
return typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(u) {
|
|
468
108
|
const e = Math.random() * 16 | 0;
|
|
469
|
-
return (
|
|
109
|
+
return (u === "x" ? e : e & 3 | 8).toString(16);
|
|
470
110
|
});
|
|
471
111
|
}
|
|
472
|
-
|
|
112
|
+
var _ = /* @__PURE__ */ ((u) => (u.ACTIVE = "active", u.DISPOSAL_REQUESTED = "disposal_requested", u.DISPOSING = "disposing", u.DISPOSED = "disposed", u))(_ || {});
|
|
113
|
+
class k {
|
|
473
114
|
/**
|
|
474
115
|
* Creates a new BlocBase instance with the given initial state.
|
|
475
116
|
* Sets up the observer, registers with the Blac manager, and initializes addons.
|
|
476
|
-
*
|
|
117
|
+
*
|
|
477
118
|
* @param initialState The initial state value for this Bloc
|
|
478
119
|
*/
|
|
479
120
|
constructor(e) {
|
|
480
|
-
|
|
121
|
+
n(this, "uid", R());
|
|
481
122
|
/**
|
|
482
123
|
* Defines how dependencies are selected from the state for efficient updates.
|
|
483
124
|
* When provided, observers will only be notified when selected dependencies change.
|
|
484
125
|
*/
|
|
485
|
-
|
|
126
|
+
n(this, "defaultDependencySelector");
|
|
486
127
|
/**
|
|
487
128
|
* @internal
|
|
488
129
|
* Indicates if this specific Bloc instance is isolated from others of the same type.
|
|
489
130
|
*/
|
|
490
|
-
|
|
131
|
+
n(this, "_isolated", !1);
|
|
491
132
|
/**
|
|
492
133
|
* @internal
|
|
493
134
|
* Observable responsible for managing state listeners and notifying consumers.
|
|
494
135
|
*/
|
|
495
|
-
|
|
136
|
+
n(this, "_observer");
|
|
496
137
|
/**
|
|
497
138
|
* The unique identifier for this Bloc instance.
|
|
498
139
|
* Defaults to the class name, but can be customized.
|
|
499
140
|
*/
|
|
500
|
-
|
|
141
|
+
n(this, "_id");
|
|
501
142
|
/**
|
|
502
143
|
* @internal
|
|
503
144
|
* Reference string used internally for tracking and debugging.
|
|
504
145
|
*/
|
|
505
|
-
|
|
146
|
+
n(this, "_instanceRef");
|
|
506
147
|
/**
|
|
507
148
|
* @internal
|
|
508
149
|
* Indicates if this specific Bloc instance should be kept alive when no consumers are present.
|
|
509
150
|
*/
|
|
510
|
-
|
|
151
|
+
n(this, "_keepAlive", !1);
|
|
511
152
|
/**
|
|
512
153
|
* @readonly
|
|
513
154
|
* Timestamp when this Bloc instance was created, useful for debugging and performance tracking.
|
|
514
155
|
*/
|
|
515
|
-
|
|
156
|
+
n(this, "_createdAt", Date.now());
|
|
516
157
|
/**
|
|
517
158
|
* @internal
|
|
518
|
-
*
|
|
159
|
+
* Atomic disposal state to prevent race conditions
|
|
519
160
|
*/
|
|
520
|
-
|
|
161
|
+
n(this, "_disposalState", "active");
|
|
162
|
+
/**
|
|
163
|
+
* @internal
|
|
164
|
+
* Timestamp when disposal was requested (for React Strict Mode grace period)
|
|
165
|
+
*/
|
|
166
|
+
n(this, "_disposalRequestTime", 0);
|
|
521
167
|
/**
|
|
522
168
|
* @internal
|
|
523
169
|
* The current state of the Bloc.
|
|
524
170
|
*/
|
|
525
|
-
|
|
171
|
+
n(this, "_state");
|
|
526
172
|
/**
|
|
527
173
|
* @internal
|
|
528
174
|
* The previous state of the Bloc, maintained for comparison and history.
|
|
529
175
|
*/
|
|
530
|
-
|
|
176
|
+
n(this, "_oldState");
|
|
531
177
|
/**
|
|
532
178
|
* Props passed during Bloc instance creation.
|
|
533
179
|
* Can be used to configure or parameterize the Bloc's behavior.
|
|
534
180
|
*/
|
|
535
|
-
|
|
181
|
+
n(this, "props", null);
|
|
536
182
|
/**
|
|
537
183
|
* @internal
|
|
538
184
|
* Flag to prevent batching race conditions
|
|
539
185
|
*/
|
|
540
|
-
|
|
186
|
+
n(this, "_batchingLock", !1);
|
|
541
187
|
/**
|
|
542
188
|
* @internal
|
|
543
189
|
* Pending batched updates
|
|
544
190
|
*/
|
|
545
|
-
|
|
191
|
+
n(this, "_pendingUpdates", []);
|
|
546
192
|
/**
|
|
547
193
|
* @internal
|
|
548
194
|
* Map of consumer IDs to their WeakRef objects for proper cleanup
|
|
549
195
|
*/
|
|
550
|
-
|
|
196
|
+
n(this, "_consumerRefs", /* @__PURE__ */ new Map());
|
|
551
197
|
/**
|
|
552
198
|
* @internal
|
|
553
199
|
* Validates that all consumer references are still alive
|
|
554
200
|
* Removes dead consumers automatically
|
|
555
201
|
*/
|
|
556
|
-
|
|
202
|
+
n(this, "_validateConsumers", () => {
|
|
557
203
|
const e = [];
|
|
558
204
|
for (const [t, s] of this._consumerRefs)
|
|
559
205
|
s.deref() === void 0 && e.push(t);
|
|
@@ -565,10 +211,10 @@ class v {
|
|
|
565
211
|
* @internal
|
|
566
212
|
* Updates the Bloc instance's ID to a new value.
|
|
567
213
|
* Only updates if the new ID is defined and different from the current one.
|
|
568
|
-
*
|
|
214
|
+
*
|
|
569
215
|
* @param id The new ID to assign to this Bloc instance
|
|
570
216
|
*/
|
|
571
|
-
|
|
217
|
+
n(this, "_updateId", (e) => {
|
|
572
218
|
const t = this._id;
|
|
573
219
|
!e || e === t || (this._id = e);
|
|
574
220
|
});
|
|
@@ -576,170 +222,631 @@ class v {
|
|
|
576
222
|
* @internal
|
|
577
223
|
* Optional function to be called when the Bloc is disposed.
|
|
578
224
|
*/
|
|
579
|
-
|
|
225
|
+
n(this, "onDispose");
|
|
580
226
|
/**
|
|
581
227
|
* @internal
|
|
582
228
|
* Set of consumer IDs currently listening to this Bloc's state changes.
|
|
583
229
|
*/
|
|
584
|
-
|
|
230
|
+
n(this, "_consumers", /* @__PURE__ */ new Set());
|
|
585
231
|
/**
|
|
586
232
|
* @internal
|
|
587
233
|
* Registers a new consumer to this Bloc instance.
|
|
588
234
|
* Notifies the Blac manager that a consumer has been added.
|
|
589
|
-
*
|
|
235
|
+
*
|
|
590
236
|
* @param consumerId The unique ID of the consumer being added
|
|
591
237
|
* @param consumerRef Optional reference to the consumer object for cleanup validation
|
|
592
238
|
*/
|
|
593
|
-
|
|
239
|
+
n(this, "_addConsumer", (e, t) => {
|
|
594
240
|
var s;
|
|
595
|
-
this._disposalState
|
|
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);
|
|
596
244
|
});
|
|
597
245
|
/**
|
|
598
246
|
* @internal
|
|
599
247
|
* Unregisters a consumer from this Bloc instance.
|
|
600
248
|
* Notifies the Blac manager that a consumer has been removed.
|
|
601
|
-
*
|
|
249
|
+
*
|
|
602
250
|
* @param consumerId The unique ID of the consumer being removed
|
|
603
251
|
*/
|
|
604
|
-
|
|
252
|
+
n(this, "_removeConsumer", (e) => {
|
|
605
253
|
var t, s;
|
|
606
|
-
this._consumers.has(e) && (this._consumers.delete(e), this._consumerRefs.delete(e), (t = globalThis.Blac) == null || t.log(
|
|
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
|
+
n(this, "_disposalHandler");
|
|
265
|
+
n(this, "lastUpdate", Date.now());
|
|
266
|
+
/**
|
|
267
|
+
* @internal
|
|
268
|
+
* Flag to indicate if batching is enabled for this bloc
|
|
269
|
+
*/
|
|
270
|
+
n(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
|
+
n(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
|
+
n(this, "batch", (e) => {
|
|
293
|
+
if (this._batchingLock)
|
|
294
|
+
return e();
|
|
295
|
+
this._batchingLock = !0, this._batchingEnabled = !0, this._pendingUpdates = [];
|
|
296
|
+
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 = [];
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
this._state = e, this._observer = new E(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;
|
|
314
|
+
}
|
|
315
|
+
get isIsolated() {
|
|
316
|
+
return this._isolated;
|
|
317
|
+
}
|
|
318
|
+
get isKeepAlive() {
|
|
319
|
+
return this._keepAlive;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
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.
|
|
325
|
+
*/
|
|
326
|
+
get state() {
|
|
327
|
+
return this._disposalState === "disposed" ? this._state : this._state;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Returns whether this Bloc instance has been disposed.
|
|
331
|
+
* @returns true if the bloc is in DISPOSED state
|
|
332
|
+
*/
|
|
333
|
+
get isDisposed() {
|
|
334
|
+
return this._disposalState === "disposed";
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* @internal
|
|
338
|
+
* Returns the name of the Bloc class for identification and debugging.
|
|
339
|
+
*/
|
|
340
|
+
get _name() {
|
|
341
|
+
return this.constructor.name;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
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
|
|
349
|
+
*/
|
|
350
|
+
_atomicStateTransition(e, t) {
|
|
351
|
+
var s, i, r, a;
|
|
352
|
+
if (this._disposalState === e) {
|
|
353
|
+
const o = this._disposalState;
|
|
354
|
+
return this._disposalState = t, (s = globalThis.Blac) != null && s.enableLog && ((i = globalThis.Blac) == null || i.log(
|
|
355
|
+
`[${this._name}:${this._id}] State transition: ${o} -> ${t} (SUCCESS)`
|
|
356
|
+
)), {
|
|
357
|
+
success: !0,
|
|
358
|
+
currentState: t,
|
|
359
|
+
previousState: o
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
return (r = globalThis.Blac) != null && r.enableLog && ((a = globalThis.Blac) == null || a.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
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* @internal
|
|
372
|
+
* Cleans up resources and removes this Bloc from the system.
|
|
373
|
+
* Notifies the Blac manager and clears all observers.
|
|
374
|
+
*/
|
|
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
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* @internal
|
|
400
|
+
* Sets the disposal handler for this bloc
|
|
401
|
+
*/
|
|
402
|
+
_setDisposalHandler(e) {
|
|
403
|
+
this._disposalHandler = e;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* @internal
|
|
407
|
+
* Schedules disposal of this bloc instance if it has no consumers
|
|
408
|
+
* Uses atomic state transitions to prevent race conditions
|
|
409
|
+
*/
|
|
410
|
+
_scheduleDisposal() {
|
|
411
|
+
if (!this._atomicStateTransition(
|
|
412
|
+
"active",
|
|
413
|
+
"disposal_requested"
|
|
414
|
+
/* DISPOSAL_REQUESTED */
|
|
415
|
+
).success)
|
|
416
|
+
return;
|
|
417
|
+
if (!(this._consumers.size === 0 && !this._keepAlive)) {
|
|
418
|
+
this._atomicStateTransition(
|
|
419
|
+
"disposal_requested",
|
|
420
|
+
"active"
|
|
421
|
+
/* ACTIVE */
|
|
422
|
+
);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
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
|
+
}
|
|
433
|
+
}
|
|
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
|
+
n(k, "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
|
+
n(k, "keepAlive", !1);
|
|
445
|
+
const I = class I {
|
|
446
|
+
getInstance() {
|
|
447
|
+
return I._instance || (I._instance = new f({
|
|
448
|
+
__unsafe_ignore_singleton: !0
|
|
449
|
+
})), I._instance;
|
|
450
|
+
}
|
|
451
|
+
setInstance(e) {
|
|
452
|
+
I._instance = e;
|
|
453
|
+
}
|
|
454
|
+
resetInstance() {
|
|
455
|
+
const e = I._instance;
|
|
456
|
+
if (I._instance = new f({
|
|
457
|
+
__unsafe_ignore_singleton: !0
|
|
458
|
+
}), e)
|
|
459
|
+
for (const t of e.keepAliveBlocs)
|
|
460
|
+
I._instance.keepAliveBlocs.add(t), I._instance.uidRegistry.set(t.uid, t);
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
n(I, "_instance");
|
|
464
|
+
let T = I, b = new T();
|
|
465
|
+
function L(u) {
|
|
466
|
+
b = u;
|
|
467
|
+
}
|
|
468
|
+
const c = class c {
|
|
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
|
+
n(this, "createdAt", Date.now());
|
|
476
|
+
/** Map storing all registered bloc instances by their class name and ID */
|
|
477
|
+
n(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
|
+
n(this, "isolatedBlocMap", /* @__PURE__ */ new Map());
|
|
483
|
+
/** Map for O(1) lookup of isolated blocs by UID */
|
|
484
|
+
n(this, "isolatedBlocIndex", /* @__PURE__ */ new Map());
|
|
485
|
+
/** Map tracking UIDs to prevent memory leaks */
|
|
486
|
+
n(this, "uidRegistry", /* @__PURE__ */ new Map());
|
|
487
|
+
/** Set of keep-alive blocs for controlled cleanup */
|
|
488
|
+
n(this, "keepAliveBlocs", /* @__PURE__ */ new Set());
|
|
489
|
+
/** Flag to control whether changes should be posted to document */
|
|
490
|
+
n(this, "postChangesToDocument", !1);
|
|
491
|
+
/**
|
|
492
|
+
* Logs messages to console when logging is enabled
|
|
493
|
+
* @param args - Arguments to log
|
|
494
|
+
*/
|
|
495
|
+
n(this, "log", (...e) => {
|
|
496
|
+
c.logSpy && c.logSpy(e), c.enableLog && c.logLevel, c.enableLog && c.logLevel;
|
|
497
|
+
});
|
|
498
|
+
/**
|
|
499
|
+
* Logs a warning message
|
|
500
|
+
* @param message - Warning message
|
|
501
|
+
* @param args - Additional arguments
|
|
502
|
+
*/
|
|
503
|
+
n(this, "warn", (e, ...t) => {
|
|
504
|
+
c.enableLog;
|
|
505
|
+
});
|
|
506
|
+
/**
|
|
507
|
+
* Logs an error message
|
|
508
|
+
* @param message - Error message
|
|
509
|
+
* @param args - Additional arguments
|
|
510
|
+
*/
|
|
511
|
+
n(this, "error", (e, ...t) => {
|
|
512
|
+
c.enableLog;
|
|
513
|
+
});
|
|
514
|
+
/**
|
|
515
|
+
* Resets the Blac instance to a new one, disposing non-keepAlive blocs
|
|
516
|
+
* from the old instance.
|
|
517
|
+
*/
|
|
518
|
+
n(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((i) => {
|
|
525
|
+
!i._keepAlive && i._disposalState === _.ACTIVE && this.disposeBloc(i);
|
|
526
|
+
});
|
|
527
|
+
}), this.blocInstanceMap.clear(), this.isolatedBlocMap.clear(), this.isolatedBlocIndex.clear(), b.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
|
+
n(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 i = e.constructor, r = this.createBlocInstanceMapKey(e._name, e._id);
|
|
545
|
+
this.log(
|
|
546
|
+
`[${e._name}:${String(e._id)}] disposeBloc called. Isolated: ${String(i.isolated)}`
|
|
547
|
+
), e._dispose(), i.isolated ? (this.unregisterIsolatedBlocInstance(e), this.blocInstanceMap.delete(r)) : this.unregisterBlocInstance(e), this.log("dispatched bloc", e);
|
|
548
|
+
});
|
|
549
|
+
n(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
|
+
n(this, "getBloc", (e, t = {}) => {
|
|
573
|
+
const { id: s, forceNewInstance: i } = t, r = e, a = s ?? e.name;
|
|
574
|
+
if (this.log(`[${e.name}:${String(a)}] (getBloc) Called:`, {
|
|
575
|
+
options: t,
|
|
576
|
+
base: r
|
|
577
|
+
}), !i)
|
|
578
|
+
if (r.isolated) {
|
|
579
|
+
const l = this.findIsolatedBlocInstance(
|
|
580
|
+
e,
|
|
581
|
+
t.instanceRef ?? a
|
|
582
|
+
);
|
|
583
|
+
if (l)
|
|
584
|
+
return l;
|
|
585
|
+
if (t.throwIfNotFound)
|
|
586
|
+
throw new Error(`Isolated bloc ${e.name} not found`);
|
|
587
|
+
} else {
|
|
588
|
+
const l = this.findRegisteredBlocInstance(
|
|
589
|
+
e,
|
|
590
|
+
a
|
|
591
|
+
);
|
|
592
|
+
if (l)
|
|
593
|
+
return l;
|
|
594
|
+
if (t.throwIfNotFound)
|
|
595
|
+
throw new Error(`Registered bloc ${e.name} not found`);
|
|
596
|
+
}
|
|
597
|
+
const o = this.createNewBlocInstance(e, a, t);
|
|
598
|
+
if (this.log(
|
|
599
|
+
`[${e.name}:${String(a)}] (getBloc) No existing instance found. Creating new one.`,
|
|
600
|
+
t,
|
|
601
|
+
o
|
|
602
|
+
), !o)
|
|
603
|
+
throw new Error(
|
|
604
|
+
`[getBloc] Failed to create bloc instance for ${e.name}. This should never happen.`
|
|
605
|
+
);
|
|
606
|
+
return o;
|
|
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
|
+
n(this, "getBlocOrThrow", (e, t = {}) => {
|
|
617
|
+
const s = e.isolated, i = t.id || e.name, r = s ? this.findIsolatedBlocInstance(e, i) : this.findRegisteredBlocInstance(e, i);
|
|
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
|
+
n(this, "getAllBlocs", (e, t = {}) => {
|
|
630
|
+
const s = [];
|
|
631
|
+
if (this.blocInstanceMap.forEach((i) => {
|
|
632
|
+
i.constructor === e && s.push(i);
|
|
633
|
+
}), t.searchIsolated !== !1) {
|
|
634
|
+
const i = this.isolatedBlocMap.get(e);
|
|
635
|
+
i && s.push(...i.map((r) => r));
|
|
636
|
+
}
|
|
637
|
+
return s;
|
|
607
638
|
});
|
|
608
639
|
/**
|
|
609
|
-
*
|
|
610
|
-
*
|
|
640
|
+
* Disposes all keep-alive blocs of a specific type
|
|
641
|
+
* @param blocClass - The bloc class to dispose
|
|
611
642
|
*/
|
|
612
|
-
|
|
613
|
-
|
|
643
|
+
n(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
|
+
});
|
|
614
649
|
/**
|
|
615
|
-
*
|
|
616
|
-
*
|
|
650
|
+
* Disposes all blocs matching a pattern
|
|
651
|
+
* @param predicate - Function to test each bloc for disposal
|
|
617
652
|
*/
|
|
618
|
-
|
|
653
|
+
n(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 i of s)
|
|
659
|
+
e(i) && t.push(i);
|
|
660
|
+
t.forEach((s) => s._dispose());
|
|
661
|
+
});
|
|
619
662
|
/**
|
|
620
|
-
*
|
|
621
|
-
* Updates the state and notifies all observers of the change.
|
|
622
|
-
*
|
|
623
|
-
* @param newState The new state to be set
|
|
624
|
-
* @param oldState The previous state for comparison
|
|
625
|
-
* @param action Optional metadata about what caused the state change
|
|
663
|
+
* Gets memory usage statistics for debugging
|
|
626
664
|
*/
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
this._pendingUpdates.push({ newState: e, oldState: t, action: s }), this._oldState = t, this._state = e;
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
this._oldState = t, this._state = e, this._observer.notify(e, t, s), this.lastUpdate = Date.now();
|
|
641
|
-
});
|
|
665
|
+
n(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
|
+
}));
|
|
642
675
|
/**
|
|
643
|
-
*
|
|
644
|
-
* @param batchFn Function to execute with batching enabled
|
|
676
|
+
* Validates consumer references and cleans up orphaned consumers
|
|
645
677
|
*/
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
const t = e();
|
|
652
|
-
if (this._pendingUpdates.length > 0) {
|
|
653
|
-
const s = this._pendingUpdates[this._pendingUpdates.length - 1];
|
|
654
|
-
this._observer.notify(s.newState, s.oldState, s.action), this.lastUpdate = Date.now();
|
|
655
|
-
}
|
|
656
|
-
return t;
|
|
657
|
-
} finally {
|
|
658
|
-
this._batchingEnabled = !1, this._batchingLock = !1, this._pendingUpdates = [];
|
|
659
|
-
}
|
|
678
|
+
n(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);
|
|
660
683
|
});
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
684
|
+
const { __unsafe_ignore_singleton: t = !1 } = e;
|
|
685
|
+
if (!t)
|
|
686
|
+
return c.instance;
|
|
687
|
+
b.setInstance(this);
|
|
664
688
|
}
|
|
665
|
-
get
|
|
666
|
-
return
|
|
689
|
+
static get instance() {
|
|
690
|
+
return b.getInstance();
|
|
667
691
|
}
|
|
668
|
-
get
|
|
669
|
-
return
|
|
692
|
+
static get getAllBlocs() {
|
|
693
|
+
return c.instance.getAllBlocs;
|
|
694
|
+
}
|
|
695
|
+
static get log() {
|
|
696
|
+
return c.instance.log;
|
|
670
697
|
}
|
|
671
698
|
/**
|
|
672
|
-
*
|
|
673
|
-
*
|
|
699
|
+
* Gets the current Blac instance
|
|
700
|
+
* @returns The Blac instance
|
|
674
701
|
*/
|
|
675
|
-
|
|
676
|
-
return
|
|
702
|
+
static getInstance() {
|
|
703
|
+
return b.getInstance();
|
|
704
|
+
}
|
|
705
|
+
static get warn() {
|
|
706
|
+
return c.instance.warn;
|
|
707
|
+
}
|
|
708
|
+
static get error() {
|
|
709
|
+
return c.instance.error;
|
|
710
|
+
}
|
|
711
|
+
static get disposeBloc() {
|
|
712
|
+
return c.instance.disposeBloc;
|
|
677
713
|
}
|
|
678
714
|
/**
|
|
679
|
-
*
|
|
680
|
-
*
|
|
715
|
+
* Creates a unique key for a bloc instance in the map based on the bloc class name and instance ID
|
|
716
|
+
* @param blocClassName - The name of the bloc class
|
|
717
|
+
* @param id - The instance ID
|
|
718
|
+
* @returns A unique key string in the format "className:id"
|
|
681
719
|
*/
|
|
682
|
-
|
|
683
|
-
return
|
|
720
|
+
createBlocInstanceMapKey(e, t) {
|
|
721
|
+
return `${e}:${String(t)}`;
|
|
684
722
|
}
|
|
685
723
|
/**
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
* Notifies the Blac manager and clears all observers.
|
|
724
|
+
* Unregister a bloc instance from the main registry
|
|
725
|
+
* @param bloc - The bloc instance to unregister
|
|
689
726
|
*/
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
this.
|
|
727
|
+
unregisterBlocInstance(e) {
|
|
728
|
+
const t = this.createBlocInstanceMapKey(e._name, e._id);
|
|
729
|
+
this.blocInstanceMap.delete(t), this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e);
|
|
693
730
|
}
|
|
694
731
|
/**
|
|
695
|
-
*
|
|
696
|
-
*
|
|
732
|
+
* Registers a bloc instance in the main registry
|
|
733
|
+
* @param bloc - The bloc instance to register
|
|
697
734
|
*/
|
|
698
|
-
|
|
699
|
-
|
|
735
|
+
registerBlocInstance(e) {
|
|
736
|
+
const t = this.createBlocInstanceMapKey(e._name, e._id);
|
|
737
|
+
this.blocInstanceMap.set(t, e), this.uidRegistry.set(e.uid, e), e._keepAlive && this.keepAliveBlocs.add(e);
|
|
700
738
|
}
|
|
701
739
|
/**
|
|
702
|
-
*
|
|
703
|
-
*
|
|
740
|
+
* Finds a registered bloc instance by its class and ID
|
|
741
|
+
* @param blocClass - The bloc class to search for
|
|
742
|
+
* @param id - The instance ID
|
|
743
|
+
* @returns The found bloc instance or undefined if not found
|
|
704
744
|
*/
|
|
705
|
-
|
|
706
|
-
|
|
745
|
+
findRegisteredBlocInstance(e, t) {
|
|
746
|
+
if (e.isolated) return;
|
|
747
|
+
const i = this.createBlocInstanceMapKey(e.name, t);
|
|
748
|
+
return this.blocInstanceMap.get(i);
|
|
707
749
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
750
|
+
/**
|
|
751
|
+
* Registers an isolated bloc instance in the isolated registry
|
|
752
|
+
* @param bloc - The isolated bloc instance to register
|
|
753
|
+
*/
|
|
754
|
+
registerIsolatedBlocInstance(e) {
|
|
755
|
+
const t = e.constructor, s = this.isolatedBlocMap.get(t);
|
|
756
|
+
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);
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Unregister an isolated bloc instance from the isolated registry
|
|
760
|
+
* @param bloc - The isolated bloc instance to unregister
|
|
761
|
+
*/
|
|
762
|
+
unregisterIsolatedBlocInstance(e) {
|
|
763
|
+
const t = e.constructor, s = this.isolatedBlocMap.get(t);
|
|
764
|
+
let i = !1;
|
|
765
|
+
if (s) {
|
|
766
|
+
const a = s.findIndex((o) => o.uid === e.uid);
|
|
767
|
+
a !== -1 && (s.splice(a, 1), i = !0), s.length === 0 && this.isolatedBlocMap.delete(t);
|
|
768
|
+
}
|
|
769
|
+
const r = this.isolatedBlocIndex.delete(e.uid);
|
|
770
|
+
this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e), i !== r && this.warn(
|
|
771
|
+
`[Blac] Inconsistent state detected during isolated bloc cleanup for ${e._name}:${e.uid}. Map removal: ${i}, Index removal: ${r}`
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Finds an isolated bloc instance by its class and ID (O(n) lookup)
|
|
776
|
+
*/
|
|
777
|
+
findIsolatedBlocInstance(e, t) {
|
|
778
|
+
if (!e.isolated) return;
|
|
779
|
+
const i = this.isolatedBlocMap.get(e);
|
|
780
|
+
return i ? i.find((a) => a._id === t) : void 0;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Finds an isolated bloc instance by UID (O(1) lookup)
|
|
784
|
+
*/
|
|
785
|
+
findIsolatedBlocInstanceByUid(e) {
|
|
786
|
+
return this.isolatedBlocIndex.get(e);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Creates a new bloc instance and registers it in the appropriate registry
|
|
790
|
+
* @param blocClass - The bloc class to instantiate
|
|
791
|
+
* @param id - The instance ID
|
|
792
|
+
* @param props - Properties to pass to the bloc constructor
|
|
793
|
+
* @param instanceRef - Optional reference string for the instance
|
|
794
|
+
* @returns The newly created bloc instance
|
|
795
|
+
*/
|
|
796
|
+
createNewBlocInstance(e, t, s = {}) {
|
|
797
|
+
const { props: i, instanceRef: r } = s, a = new e(i);
|
|
798
|
+
return a._instanceRef = r, a.props = i || null, a._updateId(t), a._setDisposalHandler((o) => this.disposeBloc(o)), a.isIsolated ? (this.registerIsolatedBlocInstance(a), a) : (this.registerBlocInstance(a), a);
|
|
799
|
+
}
|
|
800
|
+
static get activateBloc() {
|
|
801
|
+
return c.instance.activateBloc;
|
|
802
|
+
}
|
|
803
|
+
static get getBloc() {
|
|
804
|
+
return c.instance.getBloc;
|
|
805
|
+
}
|
|
806
|
+
static get getBlocOrThrow() {
|
|
807
|
+
return c.instance.getBlocOrThrow;
|
|
808
|
+
}
|
|
809
|
+
static get disposeKeepAliveBlocs() {
|
|
810
|
+
return c.instance.disposeKeepAliveBlocs;
|
|
811
|
+
}
|
|
812
|
+
static get disposeBlocs() {
|
|
813
|
+
return c.instance.disposeBlocs;
|
|
814
|
+
}
|
|
815
|
+
static get getMemoryStats() {
|
|
816
|
+
return c.instance.getMemoryStats;
|
|
817
|
+
}
|
|
818
|
+
static get validateConsumers() {
|
|
819
|
+
return c.instance.validateConsumers;
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
/** Flag to enable/disable logging */
|
|
823
|
+
n(c, "enableLog", !1), n(c, "logLevel", "warn"), n(c, "logSpy", null), n(c, "resetInstance", () => {
|
|
824
|
+
b.resetInstance();
|
|
825
|
+
});
|
|
826
|
+
let f = c;
|
|
827
|
+
class O extends k {
|
|
721
828
|
constructor() {
|
|
722
829
|
super(...arguments);
|
|
723
830
|
// Stores handlers: Map<EventConstructor (subtype of A), HandlerFunction>
|
|
724
831
|
// The handler's event parameter will be correctly typed to the specific EventConstructor
|
|
725
832
|
// by the 'on' method's signature.
|
|
726
|
-
|
|
833
|
+
n(this, "eventHandlers", /* @__PURE__ */ new Map());
|
|
727
834
|
/**
|
|
728
835
|
* @internal
|
|
729
836
|
* Event queue to ensure sequential processing of async events
|
|
730
837
|
*/
|
|
731
|
-
|
|
838
|
+
n(this, "_eventQueue", []);
|
|
732
839
|
/**
|
|
733
840
|
* @internal
|
|
734
841
|
* Flag indicating if an event is currently being processed
|
|
735
842
|
*/
|
|
736
|
-
|
|
843
|
+
n(this, "_isProcessingEvent", !1);
|
|
737
844
|
/**
|
|
738
845
|
* Dispatches an action/event to the Bloc.
|
|
739
846
|
* Events are queued and processed sequentially to prevent race conditions.
|
|
740
847
|
* @param action The action/event instance to be processed.
|
|
741
848
|
*/
|
|
742
|
-
|
|
849
|
+
n(this, "add", async (t) => {
|
|
743
850
|
this._eventQueue.push(t), this._isProcessingEvent || await this._processEventQueue();
|
|
744
851
|
});
|
|
745
852
|
}
|
|
@@ -751,7 +858,7 @@ class S extends v {
|
|
|
751
858
|
* The 'event' parameter in the handler will be typed to the specific eventConstructor.
|
|
752
859
|
*/
|
|
753
860
|
on(t, s) {
|
|
754
|
-
this.eventHandlers.has(t) &&
|
|
861
|
+
this.eventHandlers.has(t) && f.warn(
|
|
755
862
|
`[Bloc ${this._name}:${String(this._id)}] Handler for event '${t.name}' already registered. It will be overwritten.`
|
|
756
863
|
), this.eventHandlers.set(
|
|
757
864
|
t,
|
|
@@ -780,35 +887,35 @@ class S extends v {
|
|
|
780
887
|
* Processes a single event
|
|
781
888
|
*/
|
|
782
889
|
async _processEvent(t) {
|
|
783
|
-
const s = t.constructor,
|
|
784
|
-
if (
|
|
785
|
-
const
|
|
786
|
-
const
|
|
787
|
-
this._pushState(a,
|
|
890
|
+
const s = t.constructor, i = this.eventHandlers.get(s);
|
|
891
|
+
if (i) {
|
|
892
|
+
const r = (a) => {
|
|
893
|
+
const o = this.state;
|
|
894
|
+
this._pushState(a, o, t);
|
|
788
895
|
};
|
|
789
896
|
try {
|
|
790
|
-
await
|
|
897
|
+
await i(t, r);
|
|
791
898
|
} catch (a) {
|
|
792
|
-
const
|
|
899
|
+
const o = t.constructor.name || "UnnamedConstructor", l = {
|
|
793
900
|
blocName: this._name,
|
|
794
901
|
blocId: String(this._id),
|
|
795
|
-
eventType:
|
|
902
|
+
eventType: o,
|
|
796
903
|
currentState: this.state,
|
|
797
904
|
action: t,
|
|
798
905
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
799
906
|
};
|
|
800
|
-
if (
|
|
801
|
-
`[Bloc ${this._name}:${String(this._id)}] Error in event handler for '${
|
|
907
|
+
if (f.error(
|
|
908
|
+
`[Bloc ${this._name}:${String(this._id)}] Error in event handler for '${o}':`,
|
|
802
909
|
a,
|
|
803
910
|
"Context:",
|
|
804
|
-
|
|
911
|
+
l
|
|
805
912
|
), a instanceof Error && a.name === "CriticalError")
|
|
806
913
|
throw a;
|
|
807
914
|
}
|
|
808
915
|
} else {
|
|
809
|
-
const
|
|
810
|
-
|
|
811
|
-
`[Bloc ${this._name}:${String(this._id)}] No handler registered for action type: '${
|
|
916
|
+
const r = t.constructor.name || "UnnamedConstructor";
|
|
917
|
+
f.warn(
|
|
918
|
+
`[Bloc ${this._name}:${String(this._id)}] No handler registered for action type: '${r}'.`,
|
|
812
919
|
"Registered handlers:",
|
|
813
920
|
Array.from(this.eventHandlers.keys()).map((a) => a.name),
|
|
814
921
|
"Action was:",
|
|
@@ -817,7 +924,7 @@ class S extends v {
|
|
|
817
924
|
}
|
|
818
925
|
}
|
|
819
926
|
}
|
|
820
|
-
class
|
|
927
|
+
class V extends k {
|
|
821
928
|
/**
|
|
822
929
|
* Updates the current state and notifies all observers of the change.
|
|
823
930
|
* If the new state is identical to the current state (using Object.is),
|
|
@@ -833,14 +940,14 @@ class k extends v {
|
|
|
833
940
|
/**
|
|
834
941
|
* Partially updates the current state by merging it with the provided state patch.
|
|
835
942
|
* This method is only applicable when the state is an object type.
|
|
836
|
-
*
|
|
943
|
+
*
|
|
837
944
|
* @param statePatch - A partial state object containing only the properties to update
|
|
838
945
|
* @param ignoreChangeCheck - If true, skips checking if the state has actually changed
|
|
839
946
|
* @throws {TypeError} If the state is not an object type
|
|
840
947
|
*/
|
|
841
948
|
patch(e, t = !1) {
|
|
842
949
|
if (typeof this.state != "object" || this.state === null) {
|
|
843
|
-
|
|
950
|
+
f.warn(
|
|
844
951
|
"Cubit.patch: was called on a cubit where the state is not an object. This is a no-op."
|
|
845
952
|
);
|
|
846
953
|
return;
|
|
@@ -849,10 +956,10 @@ class k extends v {
|
|
|
849
956
|
if (t)
|
|
850
957
|
s = !0;
|
|
851
958
|
else
|
|
852
|
-
for (const
|
|
853
|
-
if (Object.prototype.hasOwnProperty.call(e,
|
|
854
|
-
const a = this.state[
|
|
855
|
-
if (!Object.is(e[
|
|
959
|
+
for (const i in e)
|
|
960
|
+
if (Object.prototype.hasOwnProperty.call(e, i)) {
|
|
961
|
+
const a = this.state[i];
|
|
962
|
+
if (!Object.is(e[i], a)) {
|
|
856
963
|
s = !0;
|
|
857
964
|
break;
|
|
858
965
|
}
|
|
@@ -863,78 +970,86 @@ class k extends v {
|
|
|
863
970
|
});
|
|
864
971
|
}
|
|
865
972
|
}
|
|
866
|
-
class
|
|
973
|
+
class U {
|
|
867
974
|
/**
|
|
868
975
|
* Sets up a clean test environment
|
|
869
976
|
*/
|
|
870
977
|
static setUp() {
|
|
871
|
-
this.originalInstance =
|
|
978
|
+
this.originalInstance = f.instance, f.resetInstance(), f.enableLog = !1;
|
|
872
979
|
}
|
|
873
980
|
/**
|
|
874
981
|
* Tears down the test environment and restores original state
|
|
875
982
|
*/
|
|
876
983
|
static tearDown() {
|
|
877
|
-
|
|
984
|
+
f.resetInstance();
|
|
878
985
|
}
|
|
879
986
|
/**
|
|
880
987
|
* Creates a test bloc with automatic cleanup
|
|
881
988
|
*/
|
|
882
989
|
static createBloc(e, ...t) {
|
|
883
990
|
const s = new e(...t);
|
|
884
|
-
return
|
|
991
|
+
return f.activateBloc(s), s;
|
|
885
992
|
}
|
|
886
993
|
/**
|
|
887
994
|
* Waits for a bloc to emit a specific state
|
|
888
995
|
*/
|
|
889
996
|
static async waitForState(e, t, s = 5e3) {
|
|
890
|
-
return new Promise((
|
|
997
|
+
return new Promise((i, r) => {
|
|
891
998
|
const a = setTimeout(() => {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
999
|
+
r(
|
|
1000
|
+
new Error(
|
|
1001
|
+
`Timeout waiting for state matching predicate after ${s}ms`
|
|
1002
|
+
)
|
|
1003
|
+
);
|
|
1004
|
+
}, s), o = e._observer.subscribe({
|
|
1005
|
+
id: `test-waiter-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
1006
|
+
fn: (l) => {
|
|
1007
|
+
t(l) && (clearTimeout(a), o(), i(l));
|
|
897
1008
|
}
|
|
898
1009
|
});
|
|
899
|
-
t(e.state) && (clearTimeout(a),
|
|
1010
|
+
t(e.state) && (clearTimeout(a), o(), i(e.state));
|
|
900
1011
|
});
|
|
901
1012
|
}
|
|
902
1013
|
/**
|
|
903
1014
|
* Expects a bloc to emit specific states in order
|
|
904
1015
|
*/
|
|
905
1016
|
static async expectStates(e, t, s = 5e3) {
|
|
906
|
-
const
|
|
907
|
-
return new Promise((
|
|
908
|
-
const
|
|
909
|
-
a(
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1017
|
+
const i = [];
|
|
1018
|
+
return new Promise((r, a) => {
|
|
1019
|
+
const o = setTimeout(() => {
|
|
1020
|
+
a(
|
|
1021
|
+
new Error(
|
|
1022
|
+
`Timeout waiting for states. Expected: ${JSON.stringify(t)}, Received: ${JSON.stringify(i)}`
|
|
1023
|
+
)
|
|
1024
|
+
);
|
|
1025
|
+
}, s), l = e._observer.subscribe({
|
|
913
1026
|
id: `test-expecter-${crypto.randomUUID()}`,
|
|
914
|
-
fn: (
|
|
915
|
-
if (
|
|
916
|
-
clearTimeout(
|
|
917
|
-
for (let
|
|
918
|
-
const
|
|
919
|
-
if (JSON.stringify(
|
|
920
|
-
a(
|
|
921
|
-
|
|
922
|
-
|
|
1027
|
+
fn: (p) => {
|
|
1028
|
+
if (i.push(p), i.length === t.length) {
|
|
1029
|
+
clearTimeout(o), l();
|
|
1030
|
+
for (let d = 0; d < t.length; d++) {
|
|
1031
|
+
const m = t[d], v = i[d];
|
|
1032
|
+
if (JSON.stringify(m) !== JSON.stringify(v)) {
|
|
1033
|
+
a(
|
|
1034
|
+
new Error(
|
|
1035
|
+
`State mismatch at index ${d}. Expected: ${JSON.stringify(m)}, Received: ${JSON.stringify(v)}`
|
|
1036
|
+
)
|
|
1037
|
+
);
|
|
923
1038
|
return;
|
|
924
1039
|
}
|
|
925
1040
|
}
|
|
926
|
-
|
|
1041
|
+
r();
|
|
927
1042
|
}
|
|
928
1043
|
}
|
|
929
1044
|
});
|
|
930
1045
|
});
|
|
931
1046
|
}
|
|
932
1047
|
}
|
|
933
|
-
|
|
934
|
-
class
|
|
1048
|
+
n(U, "originalInstance");
|
|
1049
|
+
class z extends O {
|
|
935
1050
|
constructor(t) {
|
|
936
1051
|
super(t);
|
|
937
|
-
|
|
1052
|
+
n(this, "mockHandlers", /* @__PURE__ */ new Map());
|
|
938
1053
|
}
|
|
939
1054
|
/**
|
|
940
1055
|
* Mock an event handler for testing
|
|
@@ -955,10 +1070,10 @@ class M extends S {
|
|
|
955
1070
|
return this.eventHandlers.has(t);
|
|
956
1071
|
}
|
|
957
1072
|
}
|
|
958
|
-
class
|
|
1073
|
+
class j extends V {
|
|
959
1074
|
constructor(t) {
|
|
960
1075
|
super(t);
|
|
961
|
-
|
|
1076
|
+
n(this, "stateHistory", []);
|
|
962
1077
|
this.stateHistory.push(t);
|
|
963
1078
|
}
|
|
964
1079
|
/**
|
|
@@ -980,16 +1095,16 @@ class E extends k {
|
|
|
980
1095
|
this.stateHistory = [this.state];
|
|
981
1096
|
}
|
|
982
1097
|
}
|
|
983
|
-
class
|
|
1098
|
+
class K {
|
|
984
1099
|
constructor() {
|
|
985
|
-
|
|
986
|
-
this.initialStats =
|
|
1100
|
+
n(this, "initialStats");
|
|
1101
|
+
this.initialStats = f.getMemoryStats();
|
|
987
1102
|
}
|
|
988
1103
|
/**
|
|
989
1104
|
* Check for memory leaks and return a report
|
|
990
1105
|
*/
|
|
991
1106
|
checkForLeaks() {
|
|
992
|
-
const e =
|
|
1107
|
+
const e = f.getMemoryStats(), t = e.registeredBlocs > this.initialStats.registeredBlocs || e.isolatedBlocs > this.initialStats.isolatedBlocs || e.keepAliveBlocs > this.initialStats.keepAliveBlocs, s = `
|
|
993
1108
|
Memory Leak Detection Report:
|
|
994
1109
|
- Initial registered blocs: ${this.initialStats.registeredBlocs}
|
|
995
1110
|
- Current registered blocs: ${e.registeredBlocs}
|
|
@@ -1006,17 +1121,400 @@ Memory Leak Detection Report:
|
|
|
1006
1121
|
};
|
|
1007
1122
|
}
|
|
1008
1123
|
}
|
|
1124
|
+
class H {
|
|
1125
|
+
constructor() {
|
|
1126
|
+
n(this, "consumers", /* @__PURE__ */ new WeakMap());
|
|
1127
|
+
n(this, "registrationCount", 0);
|
|
1128
|
+
n(this, "activeConsumers", 0);
|
|
1129
|
+
}
|
|
1130
|
+
register(e, t) {
|
|
1131
|
+
this.registrationCount++, this.consumers.get(e) || this.activeConsumers++, this.consumers.set(e, {
|
|
1132
|
+
id: t,
|
|
1133
|
+
lastNotified: Date.now(),
|
|
1134
|
+
hasRendered: !1,
|
|
1135
|
+
stateAccesses: /* @__PURE__ */ new Set(),
|
|
1136
|
+
classAccesses: /* @__PURE__ */ new Set(),
|
|
1137
|
+
stateValues: /* @__PURE__ */ new Map(),
|
|
1138
|
+
classValues: /* @__PURE__ */ new Map(),
|
|
1139
|
+
accessCount: 0,
|
|
1140
|
+
lastAccessTime: 0,
|
|
1141
|
+
firstAccessTime: 0
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
unregister(e) {
|
|
1145
|
+
e && this.consumers.get(e) && (this.consumers.delete(e), this.activeConsumers = Math.max(0, this.activeConsumers - 1));
|
|
1146
|
+
}
|
|
1147
|
+
trackAccess(e, t, s, i) {
|
|
1148
|
+
const r = this.consumers.get(e);
|
|
1149
|
+
if (!r) return;
|
|
1150
|
+
const a = Date.now();
|
|
1151
|
+
r.firstAccessTime || (r.firstAccessTime = a), r.accessCount++, r.lastAccessTime = a, t === "state" ? (r.stateAccesses.add(s), i !== void 0 && r.stateValues.set(s, { value: i, lastAccessTime: a })) : (r.classAccesses.add(s), i !== void 0 && r.classValues.set(s, { value: i, lastAccessTime: a }));
|
|
1152
|
+
}
|
|
1153
|
+
resetTracking(e) {
|
|
1154
|
+
const t = this.consumers.get(e);
|
|
1155
|
+
t && (t.stateAccesses.clear(), t.classAccesses.clear(), t.stateValues.clear(), t.classValues.clear(), t.accessCount = 0, t.firstAccessTime = 0);
|
|
1156
|
+
}
|
|
1157
|
+
getDependencies(e) {
|
|
1158
|
+
const t = this.consumers.get(e);
|
|
1159
|
+
return t ? {
|
|
1160
|
+
statePaths: Array.from(t.stateAccesses),
|
|
1161
|
+
classPaths: Array.from(t.classAccesses)
|
|
1162
|
+
} : null;
|
|
1163
|
+
}
|
|
1164
|
+
hasValuesChanged(e, t, s) {
|
|
1165
|
+
const i = this.consumers.get(e);
|
|
1166
|
+
if (!i) return !0;
|
|
1167
|
+
let r = !1;
|
|
1168
|
+
const a = Date.now();
|
|
1169
|
+
if (i.stateValues.size === 0 && i.classValues.size === 0 && (i.stateAccesses.size > 0 || i.classAccesses.size > 0))
|
|
1170
|
+
return !0;
|
|
1171
|
+
for (const [o, l] of i.stateValues)
|
|
1172
|
+
try {
|
|
1173
|
+
const p = this.getValueAtPath(t, o);
|
|
1174
|
+
p !== l.value && (i.stateValues.set(o, {
|
|
1175
|
+
value: p,
|
|
1176
|
+
lastAccessTime: a
|
|
1177
|
+
}), r = !0);
|
|
1178
|
+
} catch {
|
|
1179
|
+
r = !0;
|
|
1180
|
+
}
|
|
1181
|
+
for (const [o, l] of i.classValues)
|
|
1182
|
+
try {
|
|
1183
|
+
const p = this.getValueAtPath(s, o);
|
|
1184
|
+
p !== l.value && (i.classValues.set(o, {
|
|
1185
|
+
value: p,
|
|
1186
|
+
lastAccessTime: a
|
|
1187
|
+
}), r = !0);
|
|
1188
|
+
} catch {
|
|
1189
|
+
r = !0;
|
|
1190
|
+
}
|
|
1191
|
+
return r;
|
|
1192
|
+
}
|
|
1193
|
+
shouldNotifyConsumer(e, t) {
|
|
1194
|
+
const s = this.consumers.get(e);
|
|
1195
|
+
if (!s) return !1;
|
|
1196
|
+
for (const i of t) {
|
|
1197
|
+
if (s.stateAccesses.has(i) || s.classAccesses.has(i)) return !0;
|
|
1198
|
+
for (const r of s.stateAccesses)
|
|
1199
|
+
if (i.startsWith(r + ".") || r.startsWith(i + "."))
|
|
1200
|
+
return !0;
|
|
1201
|
+
}
|
|
1202
|
+
return !1;
|
|
1203
|
+
}
|
|
1204
|
+
updateLastNotified(e) {
|
|
1205
|
+
const t = this.consumers.get(e);
|
|
1206
|
+
t && (t.lastNotified = Date.now());
|
|
1207
|
+
}
|
|
1208
|
+
getConsumerInfo(e) {
|
|
1209
|
+
return this.consumers.get(e);
|
|
1210
|
+
}
|
|
1211
|
+
setHasRendered(e, t) {
|
|
1212
|
+
const s = this.consumers.get(e);
|
|
1213
|
+
s && (s.hasRendered = t);
|
|
1214
|
+
}
|
|
1215
|
+
hasConsumer(e) {
|
|
1216
|
+
return this.consumers.has(e);
|
|
1217
|
+
}
|
|
1218
|
+
getStats() {
|
|
1219
|
+
return {
|
|
1220
|
+
totalRegistrations: this.registrationCount,
|
|
1221
|
+
activeConsumers: this.activeConsumers
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
getValueAtPath(e, t) {
|
|
1225
|
+
const s = t.split(".");
|
|
1226
|
+
let i = e;
|
|
1227
|
+
for (const r of s) {
|
|
1228
|
+
if (i == null) return;
|
|
1229
|
+
i = i[r];
|
|
1230
|
+
}
|
|
1231
|
+
return i;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
const w = /* @__PURE__ */ new WeakMap();
|
|
1235
|
+
let h = {
|
|
1236
|
+
stateProxiesCreated: 0,
|
|
1237
|
+
classProxiesCreated: 0,
|
|
1238
|
+
cacheHits: 0,
|
|
1239
|
+
cacheMisses: 0,
|
|
1240
|
+
propertyAccesses: 0,
|
|
1241
|
+
nestedProxiesCreated: 0,
|
|
1242
|
+
totalProxiesCreated: 0,
|
|
1243
|
+
createdAt: Date.now()
|
|
1244
|
+
};
|
|
1245
|
+
class y {
|
|
1246
|
+
static createStateProxy(e) {
|
|
1247
|
+
const { target: t, consumerRef: s, consumerTracker: i, path: r = "" } = e;
|
|
1248
|
+
if (!s || !i || typeof t != "object" || t === null)
|
|
1249
|
+
return t;
|
|
1250
|
+
let a = w.get(t);
|
|
1251
|
+
a || (a = /* @__PURE__ */ new WeakMap(), w.set(t, a));
|
|
1252
|
+
const o = a.get(s);
|
|
1253
|
+
if (o)
|
|
1254
|
+
return h.cacheHits++, o;
|
|
1255
|
+
h.cacheMisses++;
|
|
1256
|
+
const l = {
|
|
1257
|
+
get(d, m) {
|
|
1258
|
+
if (typeof m == "symbol" || m === "constructor")
|
|
1259
|
+
return Reflect.get(d, m);
|
|
1260
|
+
const v = r ? `${r}.${m}` : m;
|
|
1261
|
+
h.propertyAccesses++;
|
|
1262
|
+
const g = Reflect.get(d, m), S = g && typeof g === "object" && g !== null ? void 0 : g;
|
|
1263
|
+
if (i.trackAccess(s, "state", v, S), g && typeof g == "object" && g !== null) {
|
|
1264
|
+
const B = Object.getPrototypeOf(g) === Object.prototype, D = Array.isArray(g);
|
|
1265
|
+
if (B || D)
|
|
1266
|
+
return h.nestedProxiesCreated++, y.createStateProxy({
|
|
1267
|
+
target: g,
|
|
1268
|
+
consumerRef: s,
|
|
1269
|
+
consumerTracker: i,
|
|
1270
|
+
path: v
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
return g;
|
|
1274
|
+
},
|
|
1275
|
+
has(d, m) {
|
|
1276
|
+
return m in d;
|
|
1277
|
+
},
|
|
1278
|
+
ownKeys(d) {
|
|
1279
|
+
return Reflect.ownKeys(d);
|
|
1280
|
+
},
|
|
1281
|
+
getOwnPropertyDescriptor(d, m) {
|
|
1282
|
+
return Reflect.getOwnPropertyDescriptor(d, m);
|
|
1283
|
+
},
|
|
1284
|
+
set() {
|
|
1285
|
+
return !1;
|
|
1286
|
+
},
|
|
1287
|
+
deleteProperty() {
|
|
1288
|
+
return !1;
|
|
1289
|
+
}
|
|
1290
|
+
}, p = new Proxy(t, l);
|
|
1291
|
+
return a.set(s, p), h.stateProxiesCreated++, h.totalProxiesCreated++, p;
|
|
1292
|
+
}
|
|
1293
|
+
static createClassProxy(e) {
|
|
1294
|
+
const { target: t, consumerRef: s, consumerTracker: i } = e;
|
|
1295
|
+
if (!s || !i)
|
|
1296
|
+
return t;
|
|
1297
|
+
let r = w.get(t);
|
|
1298
|
+
r || (r = /* @__PURE__ */ new WeakMap(), w.set(t, r));
|
|
1299
|
+
const a = r.get(s);
|
|
1300
|
+
if (a)
|
|
1301
|
+
return h.cacheHits++, a;
|
|
1302
|
+
h.cacheMisses++;
|
|
1303
|
+
const o = {
|
|
1304
|
+
get(p, d) {
|
|
1305
|
+
const m = Reflect.get(p, d);
|
|
1306
|
+
let v = !1, g = p;
|
|
1307
|
+
const A = /* @__PURE__ */ new WeakSet(), C = 10;
|
|
1308
|
+
let S = 0;
|
|
1309
|
+
for (; g && !v && S < C && !A.has(g); ) {
|
|
1310
|
+
A.add(g);
|
|
1311
|
+
try {
|
|
1312
|
+
const x = Object.getOwnPropertyDescriptor(
|
|
1313
|
+
g,
|
|
1314
|
+
d
|
|
1315
|
+
);
|
|
1316
|
+
if (x && x.get) {
|
|
1317
|
+
v = !0;
|
|
1318
|
+
break;
|
|
1319
|
+
}
|
|
1320
|
+
g = Object.getPrototypeOf(g), S++;
|
|
1321
|
+
} catch {
|
|
1322
|
+
break;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
if (!v)
|
|
1326
|
+
return m;
|
|
1327
|
+
h.propertyAccesses++;
|
|
1328
|
+
const B = m, $ = B !== null && typeof B != "object" ? B : void 0;
|
|
1329
|
+
return i.trackAccess(
|
|
1330
|
+
s,
|
|
1331
|
+
"class",
|
|
1332
|
+
String(d),
|
|
1333
|
+
$
|
|
1334
|
+
), m;
|
|
1335
|
+
},
|
|
1336
|
+
has(p, d) {
|
|
1337
|
+
return d in p;
|
|
1338
|
+
},
|
|
1339
|
+
ownKeys(p) {
|
|
1340
|
+
return Reflect.ownKeys(p);
|
|
1341
|
+
},
|
|
1342
|
+
getOwnPropertyDescriptor(p, d) {
|
|
1343
|
+
return Reflect.getOwnPropertyDescriptor(p, d);
|
|
1344
|
+
}
|
|
1345
|
+
}, l = new Proxy(t, o);
|
|
1346
|
+
return r.set(s, l), h.classProxiesCreated++, h.totalProxiesCreated++, l;
|
|
1347
|
+
}
|
|
1348
|
+
static getProxyState(e) {
|
|
1349
|
+
return y.createStateProxy({
|
|
1350
|
+
target: e.state,
|
|
1351
|
+
consumerRef: e.consumerRef,
|
|
1352
|
+
consumerTracker: e.consumerTracker
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
static getProxyBlocInstance(e) {
|
|
1356
|
+
return y.createClassProxy({
|
|
1357
|
+
target: e.blocInstance,
|
|
1358
|
+
consumerRef: e.consumerRef,
|
|
1359
|
+
consumerTracker: e.consumerTracker
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
static getStats() {
|
|
1363
|
+
const e = Date.now() - h.createdAt;
|
|
1364
|
+
return {
|
|
1365
|
+
...h,
|
|
1366
|
+
totalProxies: h.stateProxiesCreated + h.classProxiesCreated,
|
|
1367
|
+
cacheEfficiency: h.cacheHits + h.cacheMisses > 0 ? `${(h.cacheHits / (h.cacheHits + h.cacheMisses) * 100).toFixed(1)}%` : "N/A",
|
|
1368
|
+
lifetime: `${e}ms`,
|
|
1369
|
+
proxiesPerSecond: e > 0 ? (h.totalProxiesCreated / (e / 1e3)).toFixed(2) : "N/A"
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
static resetStats() {
|
|
1373
|
+
h = {
|
|
1374
|
+
stateProxiesCreated: 0,
|
|
1375
|
+
classProxiesCreated: 0,
|
|
1376
|
+
cacheHits: 0,
|
|
1377
|
+
cacheMisses: 0,
|
|
1378
|
+
propertyAccesses: 0,
|
|
1379
|
+
nestedProxiesCreated: 0,
|
|
1380
|
+
totalProxiesCreated: 0,
|
|
1381
|
+
createdAt: Date.now()
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
class q {
|
|
1386
|
+
constructor(e, t) {
|
|
1387
|
+
n(this, "id", `consumer-${R()}`);
|
|
1388
|
+
n(this, "blocConstructor");
|
|
1389
|
+
n(this, "componentRef", { current: {} });
|
|
1390
|
+
n(this, "blocInstance");
|
|
1391
|
+
// Core components
|
|
1392
|
+
n(this, "consumerTracker");
|
|
1393
|
+
n(this, "unmountTime", 0);
|
|
1394
|
+
n(this, "mountTime", 0);
|
|
1395
|
+
// Dependency tracking
|
|
1396
|
+
n(this, "dependencyValues");
|
|
1397
|
+
n(this, "isUsingDependencies", !1);
|
|
1398
|
+
// Lifecycle state
|
|
1399
|
+
n(this, "hasMounted", !1);
|
|
1400
|
+
n(this, "mountCount", 0);
|
|
1401
|
+
n(this, "options");
|
|
1402
|
+
n(this, "createStateProxy", (e) => y.createStateProxy({
|
|
1403
|
+
target: e.target,
|
|
1404
|
+
consumerRef: this.componentRef.current,
|
|
1405
|
+
consumerTracker: this
|
|
1406
|
+
}));
|
|
1407
|
+
n(this, "createClassProxy", (e) => y.createClassProxy({
|
|
1408
|
+
target: e.target,
|
|
1409
|
+
consumerRef: this.componentRef.current,
|
|
1410
|
+
consumerTracker: this
|
|
1411
|
+
}));
|
|
1412
|
+
n(this, "createSubscription", (e) => this.blocInstance._observer.subscribe({
|
|
1413
|
+
id: this.id,
|
|
1414
|
+
fn: (s, i) => {
|
|
1415
|
+
var r;
|
|
1416
|
+
if (this.isUsingDependencies && ((r = this.options) != null && r.dependencies)) {
|
|
1417
|
+
const a = this.options.dependencies(this.blocInstance);
|
|
1418
|
+
if (!this.hasDependencyValuesChanged(
|
|
1419
|
+
this.dependencyValues,
|
|
1420
|
+
a
|
|
1421
|
+
))
|
|
1422
|
+
return;
|
|
1423
|
+
this.dependencyValues = a;
|
|
1424
|
+
} else {
|
|
1425
|
+
const a = this.consumerTracker.getConsumerInfo(
|
|
1426
|
+
this.componentRef.current
|
|
1427
|
+
);
|
|
1428
|
+
if (a && a.hasRendered && !this.consumerTracker.hasValuesChanged(
|
|
1429
|
+
this.componentRef.current,
|
|
1430
|
+
s,
|
|
1431
|
+
this.blocInstance
|
|
1432
|
+
))
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
e.onChange();
|
|
1436
|
+
}
|
|
1437
|
+
}));
|
|
1438
|
+
n(this, "mount", () => {
|
|
1439
|
+
var e, t;
|
|
1440
|
+
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))
|
|
1441
|
+
try {
|
|
1442
|
+
this.options.onMount(this.blocInstance);
|
|
1443
|
+
} catch (s) {
|
|
1444
|
+
throw s;
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
n(this, "unmount", () => {
|
|
1448
|
+
var e;
|
|
1449
|
+
if (this.unmountTime = Date.now(), this.consumerTracker.unregister(this.componentRef.current), this.blocInstance._removeConsumer(this.id), (e = this.options) != null && e.onUnmount)
|
|
1450
|
+
try {
|
|
1451
|
+
this.options.onUnmount(this.blocInstance);
|
|
1452
|
+
} catch {
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
n(this, "getProxyState", (e) => this.isUsingDependencies ? e : y.getProxyState({
|
|
1456
|
+
state: e,
|
|
1457
|
+
consumerRef: this.componentRef.current,
|
|
1458
|
+
consumerTracker: this
|
|
1459
|
+
}));
|
|
1460
|
+
n(this, "getProxyBlocInstance", () => this.isUsingDependencies ? this.blocInstance : y.getProxyBlocInstance({
|
|
1461
|
+
blocInstance: this.blocInstance,
|
|
1462
|
+
consumerRef: this.componentRef.current,
|
|
1463
|
+
consumerTracker: this
|
|
1464
|
+
}));
|
|
1465
|
+
this.options = t, this.blocConstructor = e.blocConstructor, this.componentRef = e.componentRef, this.isUsingDependencies = !!(t != null && t.dependencies), this.consumerTracker = new H(), this.blocInstance = this.updateBlocInstance(), this.consumerTracker.register(e.componentRef.current, this.id), this.isUsingDependencies && (t != null && t.dependencies) && (this.dependencyValues = t.dependencies(this.blocInstance));
|
|
1466
|
+
}
|
|
1467
|
+
trackAccess(e, t, s, i) {
|
|
1468
|
+
this.consumerTracker.trackAccess(e, t, s, i);
|
|
1469
|
+
}
|
|
1470
|
+
getConsumerDependencies(e) {
|
|
1471
|
+
return this.consumerTracker.getDependencies(e);
|
|
1472
|
+
}
|
|
1473
|
+
shouldNotifyConsumer(e, t) {
|
|
1474
|
+
const s = this.consumerTracker.getConsumerInfo(e);
|
|
1475
|
+
return !s || !s.hasRendered ? !0 : this.consumerTracker.shouldNotifyConsumer(e, t);
|
|
1476
|
+
}
|
|
1477
|
+
updateLastNotified(e) {
|
|
1478
|
+
this.consumerTracker.updateLastNotified(e), this.consumerTracker.setHasRendered(e, !0);
|
|
1479
|
+
}
|
|
1480
|
+
resetConsumerTracking() {
|
|
1481
|
+
this.consumerTracker.resetTracking(this.componentRef.current);
|
|
1482
|
+
}
|
|
1483
|
+
updateBlocInstance() {
|
|
1484
|
+
var e, t;
|
|
1485
|
+
return this.blocInstance = f.instance.getBloc(this.blocConstructor, {
|
|
1486
|
+
props: (e = this.options) == null ? void 0 : e.props,
|
|
1487
|
+
id: (t = this.options) == null ? void 0 : t.id,
|
|
1488
|
+
instanceRef: this.id
|
|
1489
|
+
}), this.blocInstance;
|
|
1490
|
+
}
|
|
1491
|
+
// Expose calledOnMount for backward compatibility
|
|
1492
|
+
get calledOnMount() {
|
|
1493
|
+
return this.hasMounted;
|
|
1494
|
+
}
|
|
1495
|
+
hasDependencyValuesChanged(e, t) {
|
|
1496
|
+
if (!e || e.length !== t.length) return !0;
|
|
1497
|
+
for (let s = 0; s < e.length; s++)
|
|
1498
|
+
if (!Object.is(e[s], t[s]))
|
|
1499
|
+
return !0;
|
|
1500
|
+
return !1;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1009
1503
|
export {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1504
|
+
f as Blac,
|
|
1505
|
+
q as BlacAdapter,
|
|
1506
|
+
E as BlacObservable,
|
|
1507
|
+
O as Bloc,
|
|
1508
|
+
k as BlocBase,
|
|
1509
|
+
_ as BlocLifecycleState,
|
|
1510
|
+
U as BlocTest,
|
|
1511
|
+
H as ConsumerTracker,
|
|
1512
|
+
V as Cubit,
|
|
1513
|
+
K as MemoryLeakDetector,
|
|
1514
|
+
z as MockBloc,
|
|
1515
|
+
j as MockCubit,
|
|
1516
|
+
y as ProxyFactory,
|
|
1517
|
+
R as generateUUID,
|
|
1518
|
+
L as setBlacInstanceManager
|
|
1021
1519
|
};
|
|
1022
1520
|
//# sourceMappingURL=index.es.js.map
|