@chromahq/core 1.0.56 → 1.0.58
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-CUFlC4bu.js → boot--zb14Gg3.js} +219 -17
- package/dist/boot--zb14Gg3.js.map +1 -0
- package/dist/{boot-c2gJZWBc.js → boot-DPtu_qKj.js} +216 -18
- package/dist/boot-DPtu_qKj.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 +153 -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 {
|
|
@@ -1023,10 +1143,10 @@ const _AlarmAdapter = class _AlarmAdapter {
|
|
|
1023
1143
|
/**
|
|
1024
1144
|
* Initialize the Chrome Alarms listener (once)
|
|
1025
1145
|
*/
|
|
1026
|
-
this.initializeAlarmListener = () => {
|
|
1146
|
+
this.initializeAlarmListener = async () => {
|
|
1027
1147
|
if (this.listenerRegistered) return;
|
|
1028
1148
|
if (this.isChromeAlarmsAvailable()) {
|
|
1029
|
-
this.clearStaleAlarms();
|
|
1149
|
+
await this.clearStaleAlarms();
|
|
1030
1150
|
chrome.alarms.onAlarm.addListener(this.handleAlarm);
|
|
1031
1151
|
this.listenerRegistered = true;
|
|
1032
1152
|
console.log("[AlarmAdapter] \u2705 Chrome Alarms API available and listener registered");
|
|
@@ -1037,20 +1157,31 @@ const _AlarmAdapter = class _AlarmAdapter {
|
|
|
1037
1157
|
}
|
|
1038
1158
|
};
|
|
1039
1159
|
/**
|
|
1040
|
-
* Clear any stale chroma alarms from previous SW instances
|
|
1160
|
+
* Clear any stale chroma alarms from previous SW instances.
|
|
1161
|
+
* Returns a promise that resolves once all stale alarms are cleared.
|
|
1041
1162
|
*/
|
|
1042
1163
|
this.clearStaleAlarms = () => {
|
|
1043
|
-
if (!this.isChromeAlarmsAvailable()) return;
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1164
|
+
if (!this.isChromeAlarmsAvailable()) return Promise.resolve();
|
|
1165
|
+
return new Promise((resolve) => {
|
|
1166
|
+
chrome.alarms.getAll((alarms) => {
|
|
1167
|
+
const staleAlarms = alarms.filter((a) => a.name.startsWith(_AlarmAdapter.ALARM_PREFIX));
|
|
1168
|
+
if (staleAlarms.length > 0) {
|
|
1169
|
+
console.log(
|
|
1170
|
+
`[AlarmAdapter] \u{1F9F9} Clearing ${staleAlarms.length} stale alarms from previous session`
|
|
1171
|
+
);
|
|
1172
|
+
let cleared = 0;
|
|
1173
|
+
staleAlarms.forEach((alarm) => {
|
|
1174
|
+
chrome.alarms.clear(alarm.name, () => {
|
|
1175
|
+
cleared++;
|
|
1176
|
+
if (cleared === staleAlarms.length) {
|
|
1177
|
+
resolve();
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
});
|
|
1181
|
+
} else {
|
|
1182
|
+
resolve();
|
|
1183
|
+
}
|
|
1184
|
+
});
|
|
1054
1185
|
});
|
|
1055
1186
|
};
|
|
1056
1187
|
/**
|
|
@@ -1155,7 +1286,7 @@ const _AlarmAdapter = class _AlarmAdapter {
|
|
|
1155
1286
|
usingChromeApi: this.isChromeAlarmsAvailable()
|
|
1156
1287
|
};
|
|
1157
1288
|
};
|
|
1158
|
-
this.initializeAlarmListener();
|
|
1289
|
+
this.ready = this.initializeAlarmListener();
|
|
1159
1290
|
}
|
|
1160
1291
|
};
|
|
1161
1292
|
_AlarmAdapter.ALARM_PREFIX = "chroma_job_";
|
|
@@ -2062,6 +2193,13 @@ class Scheduler {
|
|
|
2062
2193
|
return;
|
|
2063
2194
|
}
|
|
2064
2195
|
}
|
|
2196
|
+
this.alarm.ready.then(() => this.scheduleInternal(id, options));
|
|
2197
|
+
}
|
|
2198
|
+
scheduleInternal(id, options) {
|
|
2199
|
+
const context = this.registry.getContext(id);
|
|
2200
|
+
if (!context || context.isStopped() || context.isPaused()) {
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2065
2203
|
const when = this.getScheduleTime(options);
|
|
2066
2204
|
const now = Date.now();
|
|
2067
2205
|
if (when <= now) {
|
|
@@ -2200,6 +2338,7 @@ class ApplicationBootstrap {
|
|
|
2200
2338
|
constructor() {
|
|
2201
2339
|
this.serviceDependencies = /* @__PURE__ */ new Map();
|
|
2202
2340
|
this.serviceRegistry = /* @__PURE__ */ new Map();
|
|
2341
|
+
this.jobRegistry = /* @__PURE__ */ new Map();
|
|
2203
2342
|
this.logger = new BootstrapLogger();
|
|
2204
2343
|
this.storeDefinitions = [];
|
|
2205
2344
|
}
|
|
@@ -2231,6 +2370,7 @@ class ApplicationBootstrap {
|
|
|
2231
2370
|
try {
|
|
2232
2371
|
this.logger = new BootstrapLogger(enableLogs);
|
|
2233
2372
|
this.logger.info("Starting Chroma application bootstrap...");
|
|
2373
|
+
this.initializeEventBus();
|
|
2234
2374
|
await this.discoverAndInitializeStores();
|
|
2235
2375
|
await this.discoverServices();
|
|
2236
2376
|
const store = this.storeDefinitions[0].store;
|
|
@@ -2250,6 +2390,7 @@ class ApplicationBootstrap {
|
|
|
2250
2390
|
if (!disableBootMethods) {
|
|
2251
2391
|
await this.bootMessages();
|
|
2252
2392
|
await this.bootServices();
|
|
2393
|
+
this.wireEventSubscriptions();
|
|
2253
2394
|
}
|
|
2254
2395
|
this.logger.success("Chroma application initialization complete");
|
|
2255
2396
|
} catch (error) {
|
|
@@ -2280,6 +2421,62 @@ class ApplicationBootstrap {
|
|
|
2280
2421
|
);
|
|
2281
2422
|
await Promise.all(bootPromises);
|
|
2282
2423
|
}
|
|
2424
|
+
/**
|
|
2425
|
+
* Create and bind the global AppEventBus singleton to the DI container.
|
|
2426
|
+
* Called early in bootstrap so any service can inject it.
|
|
2427
|
+
*/
|
|
2428
|
+
initializeEventBus() {
|
|
2429
|
+
if (!container.isBound(AppEventBus)) {
|
|
2430
|
+
container.bind(AppEventBus).toSelf().inSingletonScope();
|
|
2431
|
+
}
|
|
2432
|
+
if (!container.isBound(EventBusToken)) {
|
|
2433
|
+
container.bind(EventBusToken).toDynamicValue(() => container.get(AppEventBus)).inSingletonScope();
|
|
2434
|
+
}
|
|
2435
|
+
this.logger.debug("AppEventBus bound to DI container");
|
|
2436
|
+
}
|
|
2437
|
+
/**
|
|
2438
|
+
* Scan all registered services and jobs for @Subscribe metadata and
|
|
2439
|
+
* wire the decorated methods to the AppEventBus.
|
|
2440
|
+
*
|
|
2441
|
+
* This runs after bootServices so every singleton is already instantiated.
|
|
2442
|
+
*/
|
|
2443
|
+
wireEventSubscriptions() {
|
|
2444
|
+
this.logger.info("Wiring @Subscribe event subscriptions...");
|
|
2445
|
+
const bus = container.get(AppEventBus);
|
|
2446
|
+
let wiredCount = 0;
|
|
2447
|
+
const scan = (name, Constructor) => {
|
|
2448
|
+
const metadata = getSubscribeMetadata(Constructor);
|
|
2449
|
+
if (metadata.length === 0) {
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2452
|
+
let instance;
|
|
2453
|
+
try {
|
|
2454
|
+
instance = container.get(Constructor);
|
|
2455
|
+
} catch {
|
|
2456
|
+
this.logger.warn(`Could not resolve instance for ${name}, skipping @Subscribe wiring`);
|
|
2457
|
+
return;
|
|
2458
|
+
}
|
|
2459
|
+
for (const { eventName, methodName } of metadata) {
|
|
2460
|
+
const method = instance[methodName];
|
|
2461
|
+
if (typeof method !== "function") {
|
|
2462
|
+
this.logger.warn(
|
|
2463
|
+
`@Subscribe('${eventName}') on ${name}.${methodName} is not a function, skipping`
|
|
2464
|
+
);
|
|
2465
|
+
continue;
|
|
2466
|
+
}
|
|
2467
|
+
bus.on(eventName, method.bind(instance), `${name}.${methodName}`);
|
|
2468
|
+
wiredCount++;
|
|
2469
|
+
this.logger.debug(`Wired @Subscribe('${eventName}') \u2192 ${name}.${methodName}`);
|
|
2470
|
+
}
|
|
2471
|
+
};
|
|
2472
|
+
for (const [name, Constructor] of this.serviceRegistry) {
|
|
2473
|
+
scan(name, Constructor);
|
|
2474
|
+
}
|
|
2475
|
+
for (const [name, Constructor] of this.jobRegistry) {
|
|
2476
|
+
scan(name, Constructor);
|
|
2477
|
+
}
|
|
2478
|
+
this.logger.success(`Wired ${wiredCount} @Subscribe handler(s) to AppEventBus`);
|
|
2479
|
+
}
|
|
2283
2480
|
/**
|
|
2284
2481
|
* Discover all services in the application directory
|
|
2285
2482
|
*/
|
|
@@ -2618,10 +2815,11 @@ class ApplicationBootstrap {
|
|
|
2618
2815
|
if (!container.isBound(JobClass)) {
|
|
2619
2816
|
container.bind(JobClass).toSelf().inSingletonScope();
|
|
2620
2817
|
}
|
|
2621
|
-
const id = `${jobName.toLowerCase()}:${JobClass.name.toLowerCase()}
|
|
2818
|
+
const id = `${jobName.toLowerCase()}:${JobClass.name.toLowerCase()}`;
|
|
2622
2819
|
container.bind(id).to(JobClass).inSingletonScope();
|
|
2623
2820
|
const options = Reflect.getMetadata("job:options", JobClass) || {};
|
|
2624
2821
|
jobEntries.push({ JobClass, jobName, id, options });
|
|
2822
|
+
this.jobRegistry.set(jobName, JobClass);
|
|
2625
2823
|
this.logger.debug(`Bound job: ${jobName}`);
|
|
2626
2824
|
} catch (error) {
|
|
2627
2825
|
this.logger.error(`Failed to bind job ${JobClass.name}:`, error);
|
|
@@ -2742,5 +2940,5 @@ class BootstrapBuilder {
|
|
|
2742
2940
|
}
|
|
2743
2941
|
}
|
|
2744
2942
|
|
|
2745
|
-
export { JobRegistry as J, NonceService as N, PopupVisibilityService as P,
|
|
2746
|
-
//# sourceMappingURL=boot-
|
|
2943
|
+
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 };
|
|
2944
|
+
//# sourceMappingURL=boot-DPtu_qKj.js.map
|