@chromahq/core 1.0.52 → 1.0.54
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-B33Lf5tn.js → boot-CcvC3GTE.js} +216 -3
- package/dist/boot-CcvC3GTE.js.map +1 -0
- package/dist/{boot-DmW_OC5R.js → boot-DRsz4LpW.js} +215 -4
- package/dist/boot-DRsz4LpW.js.map +1 -0
- package/dist/boot.cjs.js +1 -1
- package/dist/boot.es.js +1 -1
- package/dist/index.cjs.js +18 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +198 -4
- package/dist/index.es.js +16 -4
- package/dist/index.es.js.map +1 -1
- package/package.json +1 -1
- package/dist/boot-B33Lf5tn.js.map +0 -1
- package/dist/boot-DmW_OC5R.js.map +0 -1
|
@@ -263,6 +263,139 @@ function getNonceService() {
|
|
|
263
263
|
return nonceServiceInstance;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
const _PopupVisibilityService = class _PopupVisibilityService {
|
|
267
|
+
/**
|
|
268
|
+
* Private constructor - use PopupVisibilityService.instance instead.
|
|
269
|
+
*/
|
|
270
|
+
constructor() {
|
|
271
|
+
/** Number of currently connected ports (popup views) */
|
|
272
|
+
this.connectedPortCount = 0;
|
|
273
|
+
/** Listeners for visibility changes */
|
|
274
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
275
|
+
/** Timestamp of last visibility change */
|
|
276
|
+
this.lastVisibilityChangeAt = 0;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get the singleton instance of the service.
|
|
280
|
+
*/
|
|
281
|
+
static get instance() {
|
|
282
|
+
if (!_PopupVisibilityService._instance) {
|
|
283
|
+
_PopupVisibilityService._instance = new _PopupVisibilityService();
|
|
284
|
+
}
|
|
285
|
+
return _PopupVisibilityService._instance;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Reset the singleton instance (primarily for testing).
|
|
289
|
+
* @internal
|
|
290
|
+
*/
|
|
291
|
+
static resetInstance() {
|
|
292
|
+
if (_PopupVisibilityService._instance) {
|
|
293
|
+
_PopupVisibilityService._instance.listeners.clear();
|
|
294
|
+
}
|
|
295
|
+
_PopupVisibilityService._instance = null;
|
|
296
|
+
}
|
|
297
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
298
|
+
// Public API
|
|
299
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
300
|
+
/**
|
|
301
|
+
* Check if the popup (or any extension view) is currently visible.
|
|
302
|
+
*
|
|
303
|
+
* @returns true if at least one port is connected (popup is open)
|
|
304
|
+
*/
|
|
305
|
+
isPopupVisible() {
|
|
306
|
+
return this.connectedPortCount > 0;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get the number of connected ports.
|
|
310
|
+
*
|
|
311
|
+
* @returns The current count of connected extension views
|
|
312
|
+
*/
|
|
313
|
+
getConnectedPortCount() {
|
|
314
|
+
return this.connectedPortCount;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get the timestamp of the last visibility change.
|
|
318
|
+
*
|
|
319
|
+
* @returns Unix timestamp in milliseconds, or 0 if never changed
|
|
320
|
+
*/
|
|
321
|
+
getLastVisibilityChangeAt() {
|
|
322
|
+
return this.lastVisibilityChangeAt;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Register a callback to be notified when visibility changes.
|
|
326
|
+
*
|
|
327
|
+
* @param callback - Function to call when visibility changes
|
|
328
|
+
* @returns Unsubscribe function to remove the listener
|
|
329
|
+
*/
|
|
330
|
+
onVisibilityChange(callback) {
|
|
331
|
+
this.listeners.add(callback);
|
|
332
|
+
return () => {
|
|
333
|
+
this.listeners.delete(callback);
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
337
|
+
// Internal API (called by BridgeRuntime)
|
|
338
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
339
|
+
/**
|
|
340
|
+
* Called when a port connects (popup opens).
|
|
341
|
+
* @internal
|
|
342
|
+
*/
|
|
343
|
+
onPortConnected() {
|
|
344
|
+
const wasVisible = this.isPopupVisible();
|
|
345
|
+
this.connectedPortCount++;
|
|
346
|
+
if (!wasVisible && this.isPopupVisible()) {
|
|
347
|
+
this.lastVisibilityChangeAt = Date.now();
|
|
348
|
+
this.notifyListeners(true);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Called when a port disconnects (popup closes).
|
|
353
|
+
* @internal
|
|
354
|
+
*/
|
|
355
|
+
onPortDisconnected() {
|
|
356
|
+
const wasVisible = this.isPopupVisible();
|
|
357
|
+
this.connectedPortCount = Math.max(0, this.connectedPortCount - 1);
|
|
358
|
+
if (wasVisible && !this.isPopupVisible()) {
|
|
359
|
+
this.lastVisibilityChangeAt = Date.now();
|
|
360
|
+
this.notifyListeners(false);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Sync the port count with the actual connected ports set.
|
|
365
|
+
* Called by BridgeRuntime to ensure consistency.
|
|
366
|
+
* @internal
|
|
367
|
+
*/
|
|
368
|
+
syncPortCount(count) {
|
|
369
|
+
const wasVisible = this.isPopupVisible();
|
|
370
|
+
this.connectedPortCount = count;
|
|
371
|
+
const isNowVisible = this.isPopupVisible();
|
|
372
|
+
if (wasVisible !== isNowVisible) {
|
|
373
|
+
this.lastVisibilityChangeAt = Date.now();
|
|
374
|
+
this.notifyListeners(isNowVisible);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
378
|
+
// Private Methods
|
|
379
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
380
|
+
/**
|
|
381
|
+
* Notify all registered listeners of a visibility change.
|
|
382
|
+
*/
|
|
383
|
+
notifyListeners(isVisible) {
|
|
384
|
+
this.listeners.forEach((callback) => {
|
|
385
|
+
try {
|
|
386
|
+
callback(isVisible);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
console.error("[PopupVisibilityService] Listener error:", error);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
_PopupVisibilityService._instance = null;
|
|
394
|
+
let PopupVisibilityService = _PopupVisibilityService;
|
|
395
|
+
function getPopupVisibilityService() {
|
|
396
|
+
return PopupVisibilityService.instance;
|
|
397
|
+
}
|
|
398
|
+
|
|
266
399
|
const DEFAULT_PORT_NAME$1 = "chroma-bridge";
|
|
267
400
|
const earlyPorts = [];
|
|
268
401
|
let listenerSetup = false;
|
|
@@ -517,6 +650,7 @@ const _BridgeRuntimeManager = class _BridgeRuntimeManager {
|
|
|
517
650
|
*/
|
|
518
651
|
setupMessageHandler(port) {
|
|
519
652
|
this.connectedPorts.add(port);
|
|
653
|
+
PopupVisibilityService.instance.onPortConnected();
|
|
520
654
|
if (this.keepAlive && this.connectedPorts.size === 1) {
|
|
521
655
|
this.startKeepAlive();
|
|
522
656
|
}
|
|
@@ -552,6 +686,7 @@ const _BridgeRuntimeManager = class _BridgeRuntimeManager {
|
|
|
552
686
|
});
|
|
553
687
|
port.onDisconnect.addListener(() => {
|
|
554
688
|
this.connectedPorts.delete(port);
|
|
689
|
+
PopupVisibilityService.instance.onPortDisconnected();
|
|
555
690
|
const runtimeErrorMessage = chrome.runtime.lastError?.message;
|
|
556
691
|
if (runtimeErrorMessage) {
|
|
557
692
|
this.logger.warn(`\u{1F4F4} Port disconnected with error: ${runtimeErrorMessage}`);
|
|
@@ -1830,12 +1965,77 @@ class Scheduler {
|
|
|
1830
1965
|
this.logger.info("Scheduler initialized");
|
|
1831
1966
|
this.alarm.onTrigger(this.execute.bind(this));
|
|
1832
1967
|
this.timeout.onTrigger(this.execute.bind(this));
|
|
1968
|
+
this.setupPopupVisibilityListener();
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Setup listener for popup visibility changes.
|
|
1972
|
+
* When popup closes, pause all jobs with requiresPopup.
|
|
1973
|
+
* When popup opens, resume those jobs.
|
|
1974
|
+
*/
|
|
1975
|
+
setupPopupVisibilityListener() {
|
|
1976
|
+
const visibilityService = PopupVisibilityService.instance;
|
|
1977
|
+
this.popupVisibilityUnsubscribe = visibilityService.onVisibilityChange((isVisible) => {
|
|
1978
|
+
if (isVisible) {
|
|
1979
|
+
this.resumePopupDependentJobs();
|
|
1980
|
+
} else {
|
|
1981
|
+
this.pausePopupDependentJobs();
|
|
1982
|
+
}
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
/**
|
|
1986
|
+
* Pause all jobs that have requiresPopup: true
|
|
1987
|
+
*/
|
|
1988
|
+
pausePopupDependentJobs() {
|
|
1989
|
+
const jobs = this.registry.listAll();
|
|
1990
|
+
let pausedCount = 0;
|
|
1991
|
+
for (const job of jobs) {
|
|
1992
|
+
if (job.options?.requiresPopup && !this.registry.getContext(job.id)?.isPaused()) {
|
|
1993
|
+
this.logger.debug(`Pausing popup-dependent job: ${job.id}`);
|
|
1994
|
+
this.alarm.cancel(job.id);
|
|
1995
|
+
this.timeout.cancel(job.id);
|
|
1996
|
+
this.registry.pause(job.id);
|
|
1997
|
+
pausedCount++;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
if (pausedCount > 0) {
|
|
2001
|
+
this.logger.info(`Paused ${pausedCount} popup-dependent jobs (popup closed)`);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
/**
|
|
2005
|
+
* Resume all jobs that have requiresPopup: true
|
|
2006
|
+
*/
|
|
2007
|
+
resumePopupDependentJobs() {
|
|
2008
|
+
const jobs = this.registry.listAll();
|
|
2009
|
+
let resumedCount = 0;
|
|
2010
|
+
for (const job of jobs) {
|
|
2011
|
+
if (job.options?.requiresPopup && this.registry.getContext(job.id)?.isPaused()) {
|
|
2012
|
+
this.logger.debug(`Resuming popup-dependent job: ${job.id}`);
|
|
2013
|
+
this.registry.resume(job.id);
|
|
2014
|
+
this.schedule(job.id, job.options);
|
|
2015
|
+
resumedCount++;
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
if (resumedCount > 0) {
|
|
2019
|
+
this.logger.info(`Resumed ${resumedCount} popup-dependent jobs (popup opened)`);
|
|
2020
|
+
}
|
|
1833
2021
|
}
|
|
1834
2022
|
schedule(id, options) {
|
|
1835
2023
|
const context = this.registry.getContext(id);
|
|
1836
2024
|
if (!context || context.isStopped()) {
|
|
1837
2025
|
return;
|
|
1838
2026
|
}
|
|
2027
|
+
if (options?.requiresPopup) {
|
|
2028
|
+
const isPopupVisible = PopupVisibilityService.instance.isPopupVisible();
|
|
2029
|
+
if (!isPopupVisible) {
|
|
2030
|
+
this.logger.debug(
|
|
2031
|
+
`Job ${id} requires popup but popup is not visible, pausing instead of scheduling`
|
|
2032
|
+
);
|
|
2033
|
+
if (!context.isPaused()) {
|
|
2034
|
+
this.registry.pause(id);
|
|
2035
|
+
}
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
1839
2039
|
const when = this.getScheduleTime(options);
|
|
1840
2040
|
const now = Date.now();
|
|
1841
2041
|
if (when <= now) {
|
|
@@ -1886,6 +2086,7 @@ class Scheduler {
|
|
|
1886
2086
|
async execute(id) {
|
|
1887
2087
|
const job = this.registry.resolve(id);
|
|
1888
2088
|
const context = this.registry.getContext(id);
|
|
2089
|
+
const options = this.registry.meta(id);
|
|
1889
2090
|
if (!job || !context) {
|
|
1890
2091
|
this.logger.debug(`Job ${id} not found or no context`);
|
|
1891
2092
|
return;
|
|
@@ -1894,6 +2095,14 @@ class Scheduler {
|
|
|
1894
2095
|
this.logger.debug(`Job ${id} is paused or stopped, skipping execution`);
|
|
1895
2096
|
return;
|
|
1896
2097
|
}
|
|
2098
|
+
if (options?.requiresPopup) {
|
|
2099
|
+
const isPopupVisible = PopupVisibilityService.instance.isPopupVisible();
|
|
2100
|
+
if (!isPopupVisible) {
|
|
2101
|
+
this.logger.debug(`Job ${id} requires popup but popup closed, pausing job`);
|
|
2102
|
+
this.registry.pause(id);
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
1897
2106
|
try {
|
|
1898
2107
|
this.registry.updateState(id, JobState.RUNNING);
|
|
1899
2108
|
this.logger.info(`Executing job ${id}`);
|
|
@@ -1902,7 +2111,6 @@ class Scheduler {
|
|
|
1902
2111
|
await jobInstance.handle.bind(jobInstance).call(jobInstance, context);
|
|
1903
2112
|
if (!context.isStopped() && !context.isPaused()) {
|
|
1904
2113
|
this.registry.updateState(id, JobState.COMPLETED);
|
|
1905
|
-
const options = this.registry.meta(id);
|
|
1906
2114
|
if (options?.cron || options?.recurring) {
|
|
1907
2115
|
this.registry.updateState(id, JobState.SCHEDULED);
|
|
1908
2116
|
this.schedule(id, options);
|
|
@@ -1911,7 +2119,6 @@ class Scheduler {
|
|
|
1911
2119
|
} catch (error) {
|
|
1912
2120
|
this.logger.error(`Job ${id} execution failed:`, error);
|
|
1913
2121
|
context.fail(error);
|
|
1914
|
-
const options = this.registry.meta(id);
|
|
1915
2122
|
if (options?.cron || options?.recurring) {
|
|
1916
2123
|
this.logger.info(`Rescheduling failed recurring job ${id}`);
|
|
1917
2124
|
this.registry.updateState(id, JobState.SCHEDULED);
|
|
@@ -1942,6 +2149,10 @@ class Scheduler {
|
|
|
1942
2149
|
*/
|
|
1943
2150
|
shutdown() {
|
|
1944
2151
|
this.logger.info("Shutting down scheduler...");
|
|
2152
|
+
if (this.popupVisibilityUnsubscribe) {
|
|
2153
|
+
this.popupVisibilityUnsubscribe();
|
|
2154
|
+
this.popupVisibilityUnsubscribe = void 0;
|
|
2155
|
+
}
|
|
1945
2156
|
this.alarm.clear();
|
|
1946
2157
|
this.timeout.clear();
|
|
1947
2158
|
this.registry.clear();
|
|
@@ -2489,6 +2700,7 @@ class BootstrapBuilder {
|
|
|
2489
2700
|
exports.JobRegistry = JobRegistry;
|
|
2490
2701
|
exports.JobState = JobState;
|
|
2491
2702
|
exports.NonceService = NonceService;
|
|
2703
|
+
exports.PopupVisibilityService = PopupVisibilityService;
|
|
2492
2704
|
exports.Scheduler = Scheduler;
|
|
2493
2705
|
exports.arePortsClaimed = arePortsClaimed;
|
|
2494
2706
|
exports.bootstrap = bootstrap;
|
|
@@ -2496,6 +2708,7 @@ exports.claimEarlyPorts = claimEarlyPorts;
|
|
|
2496
2708
|
exports.container = container;
|
|
2497
2709
|
exports.create = create;
|
|
2498
2710
|
exports.getNonceService = getNonceService;
|
|
2711
|
+
exports.getPopupVisibilityService = getPopupVisibilityService;
|
|
2499
2712
|
exports.isEarlyListenerSetup = isEarlyListenerSetup;
|
|
2500
2713
|
exports.setupEarlyListener = setupEarlyListener;
|
|
2501
|
-
//# sourceMappingURL=boot-
|
|
2714
|
+
//# sourceMappingURL=boot-CcvC3GTE.js.map
|