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