@blac/core 2.0.0-rc-16 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/Blac.d.ts +246 -0
- package/dist/Blac.d.ts.map +1 -0
- package/dist/Blac.js +624 -0
- package/dist/Blac.js.map +1 -0
- package/dist/Bloc.d.ts +41 -0
- package/dist/Bloc.d.ts.map +1 -0
- package/dist/Bloc.js +140 -0
- package/dist/Bloc.js.map +1 -0
- package/dist/BlocBase.d.ts +110 -0
- package/dist/BlocBase.d.ts.map +1 -0
- package/dist/BlocBase.js +287 -0
- package/dist/BlocBase.js.map +1 -0
- package/dist/Cubit.d.ts +25 -0
- package/dist/Cubit.d.ts.map +1 -0
- package/dist/Cubit.js +64 -0
- package/dist/Cubit.js.map +1 -0
- package/dist/adapter/BlacAdapter.d.ts +67 -0
- package/dist/adapter/BlacAdapter.d.ts.map +1 -0
- package/dist/adapter/BlacAdapter.js +263 -0
- package/dist/adapter/BlacAdapter.js.map +1 -0
- package/dist/adapter/ProxyFactory.d.ts +50 -0
- package/dist/adapter/ProxyFactory.d.ts.map +1 -0
- package/dist/adapter/ProxyFactory.js +150 -0
- package/dist/adapter/ProxyFactory.js.map +1 -0
- package/{src/adapter/index.ts → dist/adapter/index.d.ts} +1 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +19 -0
- package/dist/adapter/index.js.map +1 -0
- package/dist/errors/BlacError.d.ts +38 -0
- package/dist/errors/BlacError.d.ts.map +1 -0
- package/dist/errors/BlacError.js +55 -0
- package/dist/errors/BlacError.js.map +1 -0
- package/dist/errors/ErrorManager.d.ts +39 -0
- package/dist/errors/ErrorManager.d.ts.map +1 -0
- package/dist/errors/ErrorManager.js +91 -0
- package/dist/errors/ErrorManager.js.map +1 -0
- package/dist/errors/handleError.d.ts +24 -0
- package/dist/errors/handleError.d.ts.map +1 -0
- package/dist/errors/handleError.js +62 -0
- package/dist/errors/handleError.js.map +1 -0
- package/dist/errors/index.d.ts +5 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +13 -0
- package/dist/errors/index.js.map +1 -0
- package/{src/events.ts → dist/events.d.ts} +4 -2
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +17 -0
- package/dist/events.js.map +1 -0
- package/dist/index.cjs +38 -0
- package/{src/index.ts → dist/index.d.ts} +1 -10
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/BlocLifecycle.d.ts +51 -0
- package/dist/lifecycle/BlocLifecycle.d.ts.map +1 -0
- package/dist/lifecycle/BlocLifecycle.js +123 -0
- package/dist/lifecycle/BlocLifecycle.js.map +1 -0
- package/dist/lifecycle/index.d.ts +2 -0
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/index.js +18 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/plugins/BlocPluginRegistry.d.ts +58 -0
- package/dist/plugins/BlocPluginRegistry.d.ts.map +1 -0
- package/dist/plugins/BlocPluginRegistry.js +201 -0
- package/dist/plugins/BlocPluginRegistry.js.map +1 -0
- package/dist/plugins/SystemPluginRegistry.d.ts +79 -0
- package/dist/plugins/SystemPluginRegistry.d.ts.map +1 -0
- package/dist/plugins/SystemPluginRegistry.js +184 -0
- package/dist/plugins/SystemPluginRegistry.js.map +1 -0
- package/{src/plugins/index.ts → dist/plugins/index.d.ts} +1 -5
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +26 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/types.d.ts +103 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +3 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/subscription/SubscriptionManager.d.ts +67 -0
- package/dist/subscription/SubscriptionManager.d.ts.map +1 -0
- package/dist/subscription/SubscriptionManager.js +317 -0
- package/dist/subscription/SubscriptionManager.js.map +1 -0
- package/{src/subscription/index.ts → dist/subscription/index.d.ts} +1 -0
- package/dist/subscription/index.d.ts.map +1 -0
- package/dist/subscription/index.js +19 -0
- package/dist/subscription/index.js.map +1 -0
- package/dist/subscription/types.d.ts +65 -0
- package/dist/subscription/types.d.ts.map +1 -0
- package/dist/subscription/types.js +3 -0
- package/dist/subscription/types.js.map +1 -0
- package/dist/testing.d.ts +33 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +68 -0
- package/dist/testing.js.map +1 -0
- package/{src/types.ts → dist/types.d.ts} +11 -28
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/BatchingManager.d.ts +28 -0
- package/dist/utils/BatchingManager.d.ts.map +1 -0
- package/dist/utils/BatchingManager.js +48 -0
- package/dist/utils/BatchingManager.js.map +1 -0
- package/dist/utils/RerenderLogger.d.ts +60 -0
- package/dist/utils/RerenderLogger.d.ts.map +1 -0
- package/dist/utils/RerenderLogger.js +205 -0
- package/dist/utils/RerenderLogger.js.map +1 -0
- package/dist/utils/generateInstanceId.d.ts +11 -0
- package/dist/utils/generateInstanceId.d.ts.map +1 -0
- package/dist/utils/generateInstanceId.js +50 -0
- package/dist/utils/generateInstanceId.js.map +1 -0
- package/dist/utils/shallowEqual.d.ts +9 -0
- package/dist/utils/shallowEqual.d.ts.map +1 -0
- package/dist/utils/shallowEqual.js +35 -0
- package/dist/utils/shallowEqual.js.map +1 -0
- package/dist/utils/uuid.d.ts +10 -0
- package/dist/utils/uuid.d.ts.map +1 -0
- package/dist/utils/uuid.js +24 -0
- package/dist/utils/uuid.js.map +1 -0
- package/package.json +19 -6
- package/src/Blac.ts +0 -802
- package/src/Bloc.ts +0 -180
- package/src/BlocBase.ts +0 -398
- package/src/Cubit.ts +0 -68
- package/src/__tests__/Blac.config.test.ts +0 -79
- package/src/__tests__/Bloc.event.test.ts +0 -394
- package/src/__tests__/BlocBase.subscription.test.ts +0 -349
- package/src/__tests__/Cubit.test.ts +0 -462
- package/src/__tests__/memory-leaks.test.ts +0 -383
- package/src/__tests__/plugins.test.ts +0 -464
- package/src/adapter/BlacAdapter.ts +0 -467
- package/src/adapter/ProxyFactory.ts +0 -249
- package/src/adapter/__tests__/BlacAdapter.test.ts +0 -555
- package/src/adapter/__tests__/ProxyFactory.test.ts +0 -655
- package/src/errors/BlacError.ts +0 -69
- package/src/errors/ErrorManager.ts +0 -101
- package/src/errors/handleError.ts +0 -114
- package/src/errors/index.ts +0 -13
- package/src/lifecycle/BlocLifecycle.ts +0 -156
- package/src/lifecycle/index.ts +0 -1
- package/src/plugins/BlocPluginRegistry.ts +0 -240
- package/src/plugins/SystemPluginRegistry.ts +0 -242
- package/src/plugins/__tests__/BlocPluginRegistry.test.ts +0 -450
- package/src/plugins/__tests__/SystemPluginRegistry.test.ts +0 -404
- package/src/plugins/types.ts +0 -129
- package/src/subscription/README.md +0 -132
- package/src/subscription/SubscriptionManager.ts +0 -395
- package/src/subscription/__tests__/SubscriptionManager.test.ts +0 -355
- package/src/subscription/types.ts +0 -90
- package/src/testing.ts +0 -246
- package/src/utils/BatchingManager.ts +0 -59
- package/src/utils/RerenderLogger.ts +0 -265
- package/src/utils/__tests__/generateInstanceId.test.ts +0 -104
- package/src/utils/__tests__/shallowEqual.test.ts +0 -171
- package/src/utils/__tests__/uuid.test.ts +0 -144
- package/src/utils/generateInstanceId.ts +0 -54
- package/src/utils/shallowEqual.ts +0 -40
- package/src/utils/uuid.ts +0 -22
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
import { BlocBase } from '../BlocBase';
|
|
2
|
-
import { Blac } from '../Blac';
|
|
3
|
-
import { generateUUID } from '../utils/uuid';
|
|
4
|
-
import {
|
|
5
|
-
Subscription,
|
|
6
|
-
SubscriptionOptions,
|
|
7
|
-
SubscriptionManagerStats,
|
|
8
|
-
} from './types';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Unified subscription manager that replaces the dual consumer/observer system.
|
|
12
|
-
* Handles all state change subscriptions with a single, consistent interface.
|
|
13
|
-
*/
|
|
14
|
-
export class SubscriptionManager<S = unknown> {
|
|
15
|
-
private subscriptions = new Map<string, Subscription<S>>();
|
|
16
|
-
private pathToSubscriptions = new Map<string, Set<string>>();
|
|
17
|
-
private weakRefCleanupScheduled = false;
|
|
18
|
-
private totalNotifications = 0;
|
|
19
|
-
|
|
20
|
-
constructor(private bloc: BlocBase<S>) {}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Subscribe to state changes
|
|
24
|
-
*/
|
|
25
|
-
subscribe(options: SubscriptionOptions<S>): () => void {
|
|
26
|
-
const id = `${options.type}-${generateUUID()}`;
|
|
27
|
-
|
|
28
|
-
const subscription: Subscription<S> = {
|
|
29
|
-
id,
|
|
30
|
-
type: options.type,
|
|
31
|
-
selector: options.selector,
|
|
32
|
-
equalityFn: options.equalityFn || Object.is,
|
|
33
|
-
notify: options.notify,
|
|
34
|
-
priority: options.priority ?? 0,
|
|
35
|
-
weakRef: options.weakRef,
|
|
36
|
-
dependencies: new Set(),
|
|
37
|
-
metadata: {
|
|
38
|
-
lastNotified: Date.now(),
|
|
39
|
-
hasRendered: false,
|
|
40
|
-
accessCount: 0,
|
|
41
|
-
firstAccessTime: Date.now(),
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// Initialize selector value if provided
|
|
46
|
-
if (subscription.selector) {
|
|
47
|
-
try {
|
|
48
|
-
subscription.lastValue = subscription.selector(
|
|
49
|
-
this.bloc.state,
|
|
50
|
-
this.bloc,
|
|
51
|
-
);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
Blac.error(`SubscriptionManager: Error in selector for ${id}:`, error);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
this.subscriptions.set(id, subscription);
|
|
58
|
-
|
|
59
|
-
Blac.log(
|
|
60
|
-
`[${this.bloc._name}:${this.bloc._id}] Subscription added: ${id}. Total: ${this.subscriptions.size}`,
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
// Cancel disposal if bloc is in disposal_requested state
|
|
64
|
-
(this.bloc as any)._cancelDisposalIfRequested();
|
|
65
|
-
|
|
66
|
-
// Return unsubscribe function
|
|
67
|
-
return () => this.unsubscribe(id);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Unsubscribe by ID
|
|
72
|
-
*/
|
|
73
|
-
unsubscribe(id: string): void {
|
|
74
|
-
const subscription = this.subscriptions.get(id);
|
|
75
|
-
if (!subscription) return;
|
|
76
|
-
|
|
77
|
-
// Remove from path dependencies
|
|
78
|
-
if (subscription.dependencies) {
|
|
79
|
-
for (const path of subscription.dependencies) {
|
|
80
|
-
const subs = this.pathToSubscriptions.get(path);
|
|
81
|
-
if (subs) {
|
|
82
|
-
subs.delete(id);
|
|
83
|
-
if (subs.size === 0) {
|
|
84
|
-
this.pathToSubscriptions.delete(path);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this.subscriptions.delete(id);
|
|
91
|
-
|
|
92
|
-
Blac.log(
|
|
93
|
-
`[${this.bloc._name}:${this.bloc._id}] Subscription removed: ${id}. Remaining: ${this.subscriptions.size}`,
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
// Check if bloc should be disposed
|
|
97
|
-
this.bloc.checkDisposal();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Notify all subscriptions of state change
|
|
102
|
-
*/
|
|
103
|
-
notify(newState: S, oldState: S, action?: unknown): void {
|
|
104
|
-
// Clean up dead weak references if needed
|
|
105
|
-
this.cleanupDeadReferences();
|
|
106
|
-
|
|
107
|
-
// Sort subscriptions by priority (descending)
|
|
108
|
-
const sortedSubscriptions = Array.from(this.subscriptions.values()).sort(
|
|
109
|
-
(a, b) => (b.priority ?? 0) - (a.priority ?? 0),
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
for (const subscription of sortedSubscriptions) {
|
|
113
|
-
// Check if WeakRef is still alive
|
|
114
|
-
if (subscription.weakRef && !subscription.weakRef.deref()) {
|
|
115
|
-
this.scheduleWeakRefCleanup();
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
let shouldNotify = false;
|
|
120
|
-
let newValue: unknown;
|
|
121
|
-
let oldValue: unknown;
|
|
122
|
-
|
|
123
|
-
if (subscription.selector) {
|
|
124
|
-
// Use selector to determine if notification is needed
|
|
125
|
-
try {
|
|
126
|
-
newValue = subscription.selector(newState, this.bloc);
|
|
127
|
-
oldValue = subscription.lastValue;
|
|
128
|
-
|
|
129
|
-
const equalityFn = subscription.equalityFn || Object.is;
|
|
130
|
-
shouldNotify = !equalityFn(oldValue, newValue);
|
|
131
|
-
|
|
132
|
-
if (shouldNotify) {
|
|
133
|
-
subscription.lastValue = newValue;
|
|
134
|
-
}
|
|
135
|
-
} catch (error) {
|
|
136
|
-
Blac.error(
|
|
137
|
-
`SubscriptionManager: Error in selector for ${subscription.id}:`,
|
|
138
|
-
error,
|
|
139
|
-
);
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
} else {
|
|
143
|
-
// No selector - check if tracked dependencies changed
|
|
144
|
-
if (subscription.dependencies && subscription.dependencies.size > 0) {
|
|
145
|
-
// Check which paths changed between old and new state
|
|
146
|
-
const changedPaths = this.getChangedPaths(oldState, newState);
|
|
147
|
-
shouldNotify = this.shouldNotifyForPaths(
|
|
148
|
-
subscription.id,
|
|
149
|
-
changedPaths,
|
|
150
|
-
);
|
|
151
|
-
if ((Blac.config as any).logLevel === 'debug') {
|
|
152
|
-
Blac.log(
|
|
153
|
-
`[SubscriptionManager] Subscription ${subscription.id} dependencies:`,
|
|
154
|
-
Array.from(subscription.dependencies),
|
|
155
|
-
);
|
|
156
|
-
Blac.log(
|
|
157
|
-
`[SubscriptionManager] Changed paths:`,
|
|
158
|
-
Array.from(changedPaths),
|
|
159
|
-
);
|
|
160
|
-
Blac.log(`[SubscriptionManager] Should notify:`, shouldNotify);
|
|
161
|
-
}
|
|
162
|
-
} else {
|
|
163
|
-
// No tracked dependencies, always notify
|
|
164
|
-
shouldNotify = true;
|
|
165
|
-
}
|
|
166
|
-
newValue = newState;
|
|
167
|
-
oldValue = oldState;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (shouldNotify) {
|
|
171
|
-
try {
|
|
172
|
-
subscription.notify(newValue, oldValue, action);
|
|
173
|
-
this.totalNotifications++;
|
|
174
|
-
|
|
175
|
-
if (subscription.metadata) {
|
|
176
|
-
subscription.metadata.lastNotified = Date.now();
|
|
177
|
-
subscription.metadata.hasRendered = true;
|
|
178
|
-
}
|
|
179
|
-
} catch (error) {
|
|
180
|
-
Blac.error(
|
|
181
|
-
`SubscriptionManager: Error in notify for ${subscription.id}:`,
|
|
182
|
-
error,
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Track a path access for a subscription
|
|
191
|
-
*/
|
|
192
|
-
trackAccess(subscriptionId: string, path: string, value?: unknown): void {
|
|
193
|
-
const subscription = this.subscriptions.get(subscriptionId);
|
|
194
|
-
if (!subscription) return;
|
|
195
|
-
|
|
196
|
-
// Update dependencies
|
|
197
|
-
if (!subscription.dependencies) {
|
|
198
|
-
subscription.dependencies = new Set();
|
|
199
|
-
}
|
|
200
|
-
subscription.dependencies.add(path);
|
|
201
|
-
|
|
202
|
-
// Update path-to-subscription mapping
|
|
203
|
-
let subs = this.pathToSubscriptions.get(path);
|
|
204
|
-
if (!subs) {
|
|
205
|
-
subs = new Set();
|
|
206
|
-
this.pathToSubscriptions.set(path, subs);
|
|
207
|
-
}
|
|
208
|
-
subs.add(subscriptionId);
|
|
209
|
-
|
|
210
|
-
// Update metadata
|
|
211
|
-
if (subscription.metadata) {
|
|
212
|
-
subscription.metadata.accessCount =
|
|
213
|
-
(subscription.metadata.accessCount || 0) + 1;
|
|
214
|
-
subscription.metadata.lastAccessTime = Date.now();
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Get the paths that changed between two states
|
|
220
|
-
*/
|
|
221
|
-
private getChangedPaths(
|
|
222
|
-
oldState: any,
|
|
223
|
-
newState: any,
|
|
224
|
-
path = '',
|
|
225
|
-
): Set<string> {
|
|
226
|
-
const changedPaths = new Set<string>();
|
|
227
|
-
|
|
228
|
-
if (oldState === newState) return changedPaths;
|
|
229
|
-
|
|
230
|
-
// Handle primitives
|
|
231
|
-
if (
|
|
232
|
-
typeof oldState !== 'object' ||
|
|
233
|
-
typeof newState !== 'object' ||
|
|
234
|
-
oldState === null ||
|
|
235
|
-
newState === null
|
|
236
|
-
) {
|
|
237
|
-
if (path) changedPaths.add(path);
|
|
238
|
-
return changedPaths;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Get all keys from both objects
|
|
242
|
-
const allKeys = new Set([
|
|
243
|
-
...Object.keys(oldState),
|
|
244
|
-
...Object.keys(newState),
|
|
245
|
-
]);
|
|
246
|
-
|
|
247
|
-
for (const key of allKeys) {
|
|
248
|
-
const fullPath = path ? `${path}.${key}` : key;
|
|
249
|
-
const oldValue = oldState[key];
|
|
250
|
-
const newValue = newState[key];
|
|
251
|
-
|
|
252
|
-
if (oldValue !== newValue) {
|
|
253
|
-
changedPaths.add(fullPath);
|
|
254
|
-
|
|
255
|
-
// For nested objects, get all nested changed paths
|
|
256
|
-
if (
|
|
257
|
-
typeof oldValue === 'object' &&
|
|
258
|
-
typeof newValue === 'object' &&
|
|
259
|
-
oldValue !== null &&
|
|
260
|
-
newValue !== null
|
|
261
|
-
) {
|
|
262
|
-
const nestedChanges = this.getChangedPaths(
|
|
263
|
-
oldValue,
|
|
264
|
-
newValue,
|
|
265
|
-
fullPath,
|
|
266
|
-
);
|
|
267
|
-
nestedChanges.forEach((p) => changedPaths.add(p));
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return changedPaths;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Check if a subscription should be notified based on changed paths
|
|
277
|
-
*/
|
|
278
|
-
shouldNotifyForPaths(
|
|
279
|
-
subscriptionId: string,
|
|
280
|
-
changedPaths: Set<string>,
|
|
281
|
-
): boolean {
|
|
282
|
-
const subscription = this.subscriptions.get(subscriptionId);
|
|
283
|
-
if (!subscription || !subscription.dependencies) return true;
|
|
284
|
-
|
|
285
|
-
// Check if any tracked dependencies match changed paths
|
|
286
|
-
for (const trackedPath of subscription.dependencies) {
|
|
287
|
-
// Handle class getter dependencies (_class.propertyName)
|
|
288
|
-
if (trackedPath.startsWith('_class.')) {
|
|
289
|
-
// For class getters, we need to notify on any state change
|
|
290
|
-
// since we can't determine which state properties the getter depends on
|
|
291
|
-
// This is conservative but ensures correctness
|
|
292
|
-
if (changedPaths.size > 0) {
|
|
293
|
-
return true;
|
|
294
|
-
}
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Check direct path matches
|
|
299
|
-
if (changedPaths.has(trackedPath)) return true;
|
|
300
|
-
|
|
301
|
-
// Check nested paths
|
|
302
|
-
for (const changedPath of changedPaths) {
|
|
303
|
-
if (
|
|
304
|
-
changedPath.startsWith(trackedPath + '.') ||
|
|
305
|
-
trackedPath.startsWith(changedPath + '.')
|
|
306
|
-
) {
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return false;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Get statistics about subscriptions
|
|
317
|
-
*/
|
|
318
|
-
getStats(): SubscriptionManagerStats {
|
|
319
|
-
let consumerCount = 0;
|
|
320
|
-
let observerCount = 0;
|
|
321
|
-
|
|
322
|
-
for (const sub of this.subscriptions.values()) {
|
|
323
|
-
if (sub.type === 'consumer') consumerCount++;
|
|
324
|
-
else observerCount++;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return {
|
|
328
|
-
activeSubscriptions: this.subscriptions.size,
|
|
329
|
-
consumerCount,
|
|
330
|
-
observerCount,
|
|
331
|
-
totalNotifications: this.totalNotifications,
|
|
332
|
-
trackedDependencies: this.pathToSubscriptions.size,
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Clear all subscriptions
|
|
338
|
-
*/
|
|
339
|
-
clear(): void {
|
|
340
|
-
this.subscriptions.clear();
|
|
341
|
-
this.pathToSubscriptions.clear();
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Get subscription by ID
|
|
346
|
-
*/
|
|
347
|
-
getSubscription(id: string): Subscription<S> | undefined {
|
|
348
|
-
return this.subscriptions.get(id);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Check if there are any active subscriptions
|
|
353
|
-
*/
|
|
354
|
-
get hasSubscriptions(): boolean {
|
|
355
|
-
return this.subscriptions.size > 0;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Get count of active subscriptions
|
|
360
|
-
*/
|
|
361
|
-
get size(): number {
|
|
362
|
-
return this.subscriptions.size;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Clean up subscriptions with dead weak references
|
|
367
|
-
*/
|
|
368
|
-
private cleanupDeadReferences(): void {
|
|
369
|
-
if (!this.weakRefCleanupScheduled) return;
|
|
370
|
-
|
|
371
|
-
const deadIds: string[] = [];
|
|
372
|
-
|
|
373
|
-
for (const [id, subscription] of this.subscriptions) {
|
|
374
|
-
if (subscription.weakRef && !subscription.weakRef.deref()) {
|
|
375
|
-
deadIds.push(id);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
for (const id of deadIds) {
|
|
380
|
-
this.unsubscribe(id);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
this.weakRefCleanupScheduled = false;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Schedule weak reference cleanup for next tick
|
|
388
|
-
*/
|
|
389
|
-
private scheduleWeakRefCleanup(): void {
|
|
390
|
-
if (this.weakRefCleanupScheduled) return;
|
|
391
|
-
|
|
392
|
-
this.weakRefCleanupScheduled = true;
|
|
393
|
-
queueMicrotask(() => this.cleanupDeadReferences());
|
|
394
|
-
}
|
|
395
|
-
}
|