@chromahq/core 1.0.56 → 1.0.57
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/{boot-c2gJZWBc.js → boot-C2Rq9czO.js} +182 -2
- package/dist/boot-C2Rq9czO.js.map +1 -0
- package/dist/{boot-CUFlC4bu.js → boot-DIMyFZvd.js} +185 -1
- package/dist/boot-DIMyFZvd.js.map +1 -0
- package/dist/boot.cjs.js +2 -1
- package/dist/boot.cjs.js.map +1 -1
- package/dist/boot.es.js +2 -1
- package/dist/boot.es.js.map +1 -1
- package/dist/index.cjs.js +11 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +152 -2
- package/dist/index.es.js +3 -2
- package/dist/index.es.js.map +1 -1
- package/package.json +1 -1
- package/dist/boot-CUFlC4bu.js.map +0 -1
- package/dist/boot-c2gJZWBc.js.map +0 -1
|
@@ -1,4 +1,124 @@
|
|
|
1
1
|
import { Container } from '@inversifyjs/container';
|
|
2
|
+
import { injectable } from '@inversifyjs/core';
|
|
3
|
+
|
|
4
|
+
const SUBSCRIBE_METADATA_KEY = "chroma:subscribe";
|
|
5
|
+
function Subscribe(eventName) {
|
|
6
|
+
return function(target, propertyKey, _descriptor) {
|
|
7
|
+
const key = "chroma:subscribe";
|
|
8
|
+
const constructor = target.constructor;
|
|
9
|
+
const existing = Reflect.getMetadata(key, constructor) || [];
|
|
10
|
+
existing.push({ eventName, methodName: propertyKey });
|
|
11
|
+
Reflect.defineMetadata(key, existing, constructor);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function getSubscribeMetadata(constructor) {
|
|
15
|
+
return Reflect.getMetadata("chroma:subscribe", constructor) || [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
19
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
20
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
21
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
22
|
+
if (decorator = decorators[i])
|
|
23
|
+
result = (decorator(result)) || result;
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
const EventBusToken = /* @__PURE__ */ Symbol.for("EventBus");
|
|
27
|
+
let AppEventBus = class {
|
|
28
|
+
constructor() {
|
|
29
|
+
/** Registry of all active subscriptions */
|
|
30
|
+
this.subscriptions = [];
|
|
31
|
+
/** Auto-incrementing ID counter */
|
|
32
|
+
this.nextId = 0;
|
|
33
|
+
}
|
|
34
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
35
|
+
// Subscribe
|
|
36
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* Subscribe to a named event.
|
|
39
|
+
*
|
|
40
|
+
* @param eventName - the event to listen for
|
|
41
|
+
* @param handler - callback invoked with the event payload
|
|
42
|
+
* @param handlerName - human-readable name for logging
|
|
43
|
+
* @returns an unsubscribe function
|
|
44
|
+
*/
|
|
45
|
+
on(eventName, handler, handlerName) {
|
|
46
|
+
const id = ++this.nextId;
|
|
47
|
+
this.subscriptions.push({
|
|
48
|
+
id,
|
|
49
|
+
eventName,
|
|
50
|
+
handler,
|
|
51
|
+
handlerName
|
|
52
|
+
});
|
|
53
|
+
return () => {
|
|
54
|
+
this.subscriptions = this.subscriptions.filter((s) => s.id !== id);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
58
|
+
// Emit
|
|
59
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Emit a named event to all matching subscribers.
|
|
62
|
+
*
|
|
63
|
+
* Handlers execute in parallel. Individual handler failures are caught
|
|
64
|
+
* and logged — they do not propagate or block other handlers.
|
|
65
|
+
*
|
|
66
|
+
* @param eventName - the event to emit
|
|
67
|
+
* @param payload - optional data passed to every handler
|
|
68
|
+
*/
|
|
69
|
+
async emit(eventName, payload) {
|
|
70
|
+
const matching = this.subscriptions.filter((s) => s.eventName === eventName);
|
|
71
|
+
if (matching.length === 0) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const results = await Promise.allSettled(
|
|
75
|
+
matching.map(async (sub) => {
|
|
76
|
+
try {
|
|
77
|
+
await sub.handler(payload);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(
|
|
80
|
+
`[AppEventBus] Handler "${sub.handlerName}" failed for event "${eventName}":`,
|
|
81
|
+
error
|
|
82
|
+
);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
const failed = results.filter((r) => r.status === "rejected").length;
|
|
88
|
+
if (failed > 0) {
|
|
89
|
+
console.warn(
|
|
90
|
+
`[AppEventBus] ${failed}/${matching.length} handler(s) failed for event "${eventName}"`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
95
|
+
// Utilities
|
|
96
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
97
|
+
/**
|
|
98
|
+
* Get the total number of active subscriptions.
|
|
99
|
+
* Useful for debugging and testing.
|
|
100
|
+
*/
|
|
101
|
+
getSubscriptionCount() {
|
|
102
|
+
return this.subscriptions.length;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get the number of subscriptions for a specific event.
|
|
106
|
+
*
|
|
107
|
+
* @param eventName - the event to count subscriptions for
|
|
108
|
+
*/
|
|
109
|
+
getSubscriptionCountForEvent(eventName) {
|
|
110
|
+
return this.subscriptions.filter((s) => s.eventName === eventName).length;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Remove all subscriptions. Primarily for testing.
|
|
114
|
+
*/
|
|
115
|
+
clearAllSubscriptions() {
|
|
116
|
+
this.subscriptions = [];
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
AppEventBus = __decorateClass([
|
|
120
|
+
injectable()
|
|
121
|
+
], AppEventBus);
|
|
2
122
|
|
|
3
123
|
const NONCE_STORE_STORAGE_KEY = "__CHROMA_NONCE_STORE__";
|
|
4
124
|
class NonceService {
|
|
@@ -2200,6 +2320,7 @@ class ApplicationBootstrap {
|
|
|
2200
2320
|
constructor() {
|
|
2201
2321
|
this.serviceDependencies = /* @__PURE__ */ new Map();
|
|
2202
2322
|
this.serviceRegistry = /* @__PURE__ */ new Map();
|
|
2323
|
+
this.jobRegistry = /* @__PURE__ */ new Map();
|
|
2203
2324
|
this.logger = new BootstrapLogger();
|
|
2204
2325
|
this.storeDefinitions = [];
|
|
2205
2326
|
}
|
|
@@ -2231,6 +2352,7 @@ class ApplicationBootstrap {
|
|
|
2231
2352
|
try {
|
|
2232
2353
|
this.logger = new BootstrapLogger(enableLogs);
|
|
2233
2354
|
this.logger.info("Starting Chroma application bootstrap...");
|
|
2355
|
+
this.initializeEventBus();
|
|
2234
2356
|
await this.discoverAndInitializeStores();
|
|
2235
2357
|
await this.discoverServices();
|
|
2236
2358
|
const store = this.storeDefinitions[0].store;
|
|
@@ -2250,6 +2372,7 @@ class ApplicationBootstrap {
|
|
|
2250
2372
|
if (!disableBootMethods) {
|
|
2251
2373
|
await this.bootMessages();
|
|
2252
2374
|
await this.bootServices();
|
|
2375
|
+
this.wireEventSubscriptions();
|
|
2253
2376
|
}
|
|
2254
2377
|
this.logger.success("Chroma application initialization complete");
|
|
2255
2378
|
} catch (error) {
|
|
@@ -2280,6 +2403,62 @@ class ApplicationBootstrap {
|
|
|
2280
2403
|
);
|
|
2281
2404
|
await Promise.all(bootPromises);
|
|
2282
2405
|
}
|
|
2406
|
+
/**
|
|
2407
|
+
* Create and bind the global AppEventBus singleton to the DI container.
|
|
2408
|
+
* Called early in bootstrap so any service can inject it.
|
|
2409
|
+
*/
|
|
2410
|
+
initializeEventBus() {
|
|
2411
|
+
if (!container.isBound(AppEventBus)) {
|
|
2412
|
+
container.bind(AppEventBus).toSelf().inSingletonScope();
|
|
2413
|
+
}
|
|
2414
|
+
if (!container.isBound(EventBusToken)) {
|
|
2415
|
+
container.bind(EventBusToken).toDynamicValue(() => container.get(AppEventBus)).inSingletonScope();
|
|
2416
|
+
}
|
|
2417
|
+
this.logger.debug("AppEventBus bound to DI container");
|
|
2418
|
+
}
|
|
2419
|
+
/**
|
|
2420
|
+
* Scan all registered services and jobs for @Subscribe metadata and
|
|
2421
|
+
* wire the decorated methods to the AppEventBus.
|
|
2422
|
+
*
|
|
2423
|
+
* This runs after bootServices so every singleton is already instantiated.
|
|
2424
|
+
*/
|
|
2425
|
+
wireEventSubscriptions() {
|
|
2426
|
+
this.logger.info("Wiring @Subscribe event subscriptions...");
|
|
2427
|
+
const bus = container.get(AppEventBus);
|
|
2428
|
+
let wiredCount = 0;
|
|
2429
|
+
const scan = (name, Constructor) => {
|
|
2430
|
+
const metadata = getSubscribeMetadata(Constructor);
|
|
2431
|
+
if (metadata.length === 0) {
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2434
|
+
let instance;
|
|
2435
|
+
try {
|
|
2436
|
+
instance = container.get(Constructor);
|
|
2437
|
+
} catch {
|
|
2438
|
+
this.logger.warn(`Could not resolve instance for ${name}, skipping @Subscribe wiring`);
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
for (const { eventName, methodName } of metadata) {
|
|
2442
|
+
const method = instance[methodName];
|
|
2443
|
+
if (typeof method !== "function") {
|
|
2444
|
+
this.logger.warn(
|
|
2445
|
+
`@Subscribe('${eventName}') on ${name}.${methodName} is not a function, skipping`
|
|
2446
|
+
);
|
|
2447
|
+
continue;
|
|
2448
|
+
}
|
|
2449
|
+
bus.on(eventName, method.bind(instance), `${name}.${methodName}`);
|
|
2450
|
+
wiredCount++;
|
|
2451
|
+
this.logger.debug(`Wired @Subscribe('${eventName}') \u2192 ${name}.${methodName}`);
|
|
2452
|
+
}
|
|
2453
|
+
};
|
|
2454
|
+
for (const [name, Constructor] of this.serviceRegistry) {
|
|
2455
|
+
scan(name, Constructor);
|
|
2456
|
+
}
|
|
2457
|
+
for (const [name, Constructor] of this.jobRegistry) {
|
|
2458
|
+
scan(name, Constructor);
|
|
2459
|
+
}
|
|
2460
|
+
this.logger.success(`Wired ${wiredCount} @Subscribe handler(s) to AppEventBus`);
|
|
2461
|
+
}
|
|
2283
2462
|
/**
|
|
2284
2463
|
* Discover all services in the application directory
|
|
2285
2464
|
*/
|
|
@@ -2622,6 +2801,7 @@ class ApplicationBootstrap {
|
|
|
2622
2801
|
container.bind(id).to(JobClass).inSingletonScope();
|
|
2623
2802
|
const options = Reflect.getMetadata("job:options", JobClass) || {};
|
|
2624
2803
|
jobEntries.push({ JobClass, jobName, id, options });
|
|
2804
|
+
this.jobRegistry.set(jobName, JobClass);
|
|
2625
2805
|
this.logger.debug(`Bound job: ${jobName}`);
|
|
2626
2806
|
} catch (error) {
|
|
2627
2807
|
this.logger.error(`Failed to bind job ${JobClass.name}:`, error);
|
|
@@ -2742,5 +2922,5 @@ class BootstrapBuilder {
|
|
|
2742
2922
|
}
|
|
2743
2923
|
}
|
|
2744
2924
|
|
|
2745
|
-
export { JobRegistry as J, NonceService as N, PopupVisibilityService as P,
|
|
2746
|
-
//# sourceMappingURL=boot-
|
|
2925
|
+
export { AppEventBus as A, EventBusToken as E, JobRegistry as J, NonceService as N, PopupVisibilityService as P, Subscribe as S, SUBSCRIBE_METADATA_KEY as a, getNonceService as b, getPopupVisibilityService as c, claimEarlyPorts as d, arePortsClaimed as e, container as f, getSubscribeMetadata as g, create as h, isEarlyListenerSetup as i, bootstrap as j, Scheduler as k, JobState as l, setupEarlyListener as s };
|
|
2926
|
+
//# sourceMappingURL=boot-C2Rq9czO.js.map
|