@pixpilot/chrome-lifecycle 0.5.0 → 0.6.0

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/README.md CHANGED
@@ -42,45 +42,45 @@ Tracks whether side panels are visible or hidden across different windows.
42
42
 
43
43
  #### Setup
44
44
 
45
- **Background script (service worker):**
45
+ This feature requires initialization in both your background script and side panel script.
46
+
47
+ **1. Background script (service worker):**
48
+
49
+ Call `initSidePanelStateManager()` at the top of your background script, before any other side panel functions. All other functions (`getSidePanelStateForWindow`, `isWindowSidePanelVisible`, `onSidePanelStateChange`) will throw an error if called before initialization.
46
50
 
47
51
  ```typescript
52
+ // background.ts
48
53
  import { initSidePanelStateManager } from '@pixpilot/chrome-lifecycle';
49
54
 
50
- // Initialize once at startup
55
+ // ⚠️ Critical Setup
56
+ // Must be called first, before any other side panel functions
51
57
  initSidePanelStateManager();
58
+
59
+ // Now you can use other functions
52
60
  ```
53
61
 
54
- **Side panel script (frontend):**
62
+ **2. Side panel script (frontend):**
63
+
64
+ Call `initializeSidePanelStateTracker()` when your side panel loads. This sets up visibility tracking and a heartbeat to keep the connection alive.
55
65
 
56
66
  ```typescript
67
+ // sidepanel.ts
57
68
  import { initializeSidePanelStateTracker } from '@pixpilot/chrome-lifecycle';
58
69
 
59
- // Initialize when side panel loads
60
70
  const cleanup = initializeSidePanelStateTracker();
71
+
72
+ // Optional: call cleanup() when done to remove listeners and disconnect
61
73
  ```
62
74
 
63
75
  #### Functions
64
76
 
65
77
  ##### `initSidePanelStateManager()`
66
78
 
67
- Initializes the backend state manager. Must be called once in your background script before using other side panel functions. Subsequent calls log a warning and are ignored.
68
-
69
- ```typescript
70
- import { initSidePanelStateManager } from '@pixpilot/chrome-lifecycle';
71
-
72
- initSidePanelStateManager();
73
- ```
79
+ Initializes the backend state manager. **Must be called once at the top of your background script before using any other side panel functions.** Subsequent calls log a warning and are ignored.
74
80
 
75
81
  ##### `initializeSidePanelStateTracker()`
76
82
 
77
- Initializes the frontend tracker in your side panel. Sets up visibility tracking and heartbeat to keep the connection alive.
78
-
79
- ```typescript
80
- import { initializeSidePanelStateTracker } from '@pixpilot/chrome-lifecycle';
81
-
82
- const cleanup = initializeSidePanelStateTracker();
83
- ```
83
+ Initializes the frontend tracker in your side panel. Sets up visibility change detection and a heartbeat (every 15 seconds) to maintain the connection.
84
84
 
85
85
  **Returns:** Cleanup function to remove listeners and disconnect
86
86
 
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}const i=15e3;let a=!1;function o(){a&&console.warn(`Side panel state tracker already initialized`),a=!0;let e,t,n;return chrome.windows.getCurrent(r=>{if(r.id==null){console.error(`[side-panel-state-tracker] Could not get window ID`);return}e=chrome.runtime.connect({name:chrome.runtime.id});let i=r.id;function a(t){try{e.postMessage({...t,windowId:i,type:`side-panel-state-tracker`,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Failed to send message:`,e)}}t=setInterval(()=>{try{e.postMessage({type:`side-panel-heartbeat`,windowId:i,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Heartbeat failed:`,e),t&&clearInterval(t)}},15e3),n=()=>{a({state:document.hidden?`hidden`:`visible`,reason:`visibility-change`})},document.addEventListener(`visibilitychange`,n),e.onDisconnect.addListener(()=>{console.warn(`[side-panel-state-tracker] Background connection lost`),t&&clearInterval(t)}),e.onMessage.addListener(e=>{e.type===`close-side-panel`&&(t&&clearInterval(t),window.close())}),a({state:document.hidden?`hidden`:`visible`,reason:`document-load`})}),()=>{t&&clearInterval(t),n&&document.removeEventListener(`visibilitychange`,n),e&&e.disconnect(),a=!1}}const s=new Map,c=new Set;let l=!1;function u(){if(!l)throw Error(`Side panel state manager must be initialized with initSidePanelStateManager() before use.`)}function d(){l||(l=!0,chrome.action.onClicked.addListener(e=>{let t=s.get(e.windowId);t&&t.state===`visible`?t.port&&(s.delete(e.windowId),t.port.postMessage({type:`close-side-panel`})):chrome.sidePanel.open({windowId:e.windowId}).catch(console.error)}),chrome.runtime.onConnect.addListener(e=>{e.name===chrome.runtime.id&&(e.onMessage.addListener(t=>{t.type===`side-panel-state-tracker`&&t.state&&p({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(s.entries()).forEach(([t,n])=>{n.port&&n.port===e&&p({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function f(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};c.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function p(e){let{windowId:t,state:n}=e;if(n===`hidden`){s.delete(t),f(e);return}s.set(t,e),f(e)}function m(e){return u(),s.get(e)?.state}function h(e){return u(),m(e)===`visible`}function g(e){return u(),c.add(e),()=>{c.delete(e)}}exports.getSidePanelStateForWindow=m,exports.initSidePanelStateManager=d,exports.initializeSidePanelStateTracker=o,exports.isWindowSidePanelVisible=h,exports.onSidePanelStateChange=g,exports.onWindowClose=r;
1
+ const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}const i=15e3;let a=!1;function o(){a&&console.warn(`Side panel state tracker already initialized`),a=!0;let e,t,n;return chrome.windows.getCurrent(r=>{if(r.id==null){console.error(`[side-panel-state-tracker] Could not get window ID`);return}e=chrome.runtime.connect({name:chrome.runtime.id});let i=r.id;function a(t){try{e.postMessage({...t,windowId:i,type:`side-panel-state-tracker`,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Failed to send message:`,e)}}t=setInterval(()=>{try{e.postMessage({type:`side-panel-heartbeat`,windowId:i,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Heartbeat failed:`,e),t&&clearInterval(t)}},15e3),n=()=>{a({state:document.hidden?`hidden`:`visible`,reason:`visibility-change`})},document.addEventListener(`visibilitychange`,n),e.onDisconnect.addListener(()=>{console.warn(`[side-panel-state-tracker] Background connection lost`),t&&clearInterval(t)}),e.onMessage.addListener(e=>{e.type===`close-side-panel`&&(t&&clearInterval(t),window.close())}),a({state:document.hidden?`hidden`:`visible`,reason:`document-load`})}),()=>{t&&clearInterval(t),n&&document.removeEventListener(`visibilitychange`,n),e&&e.disconnect(),a=!1}}const s=new Map,c=new Set;let l=!1;function u(){l||console.error(`Side panel state manager is not initialized.`,`Call initSidePanelStateManager() at the top of your background script before using any other functions.`)}function d(){l||(l=!0,chrome.action.onClicked.addListener(e=>{let t=s.get(e.windowId);t&&t.state===`visible`?t.port&&(s.delete(e.windowId),t.port.postMessage({type:`close-side-panel`})):chrome.sidePanel.open({windowId:e.windowId}).catch(console.error)}),chrome.runtime.onConnect.addListener(e=>{e.name===chrome.runtime.id&&(e.onMessage.addListener(t=>{t.type===`side-panel-state-tracker`&&t.state&&p({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(s.entries()).forEach(([t,n])=>{n.port&&n.port===e&&p({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function f(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};c.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function p(e){let{windowId:t,state:n}=e;if(n===`hidden`){s.delete(t),f(e);return}s.set(t,e),f(e)}function m(e){return u(),s.get(e)?.state}function h(e){return u(),m(e)===`visible`}function g(e){return u(),c.add(e),()=>{c.delete(e)}}exports.getSidePanelStateForWindow=m,exports.initSidePanelStateManager=d,exports.initializeSidePanelStateTracker=o,exports.isWindowSidePanelVisible=h,exports.onSidePanelStateChange=g,exports.onWindowClose=r;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}let i=!1;function a(){i&&console.warn(`Side panel state tracker already initialized`),i=!0;let e,t,n;return chrome.windows.getCurrent(r=>{if(r.id==null){console.error(`[side-panel-state-tracker] Could not get window ID`);return}e=chrome.runtime.connect({name:chrome.runtime.id});let i=r.id;function a(t){try{e.postMessage({...t,windowId:i,type:`side-panel-state-tracker`,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Failed to send message:`,e)}}t=setInterval(()=>{try{e.postMessage({type:`side-panel-heartbeat`,windowId:i,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Heartbeat failed:`,e),t&&clearInterval(t)}},15e3),n=()=>{a({state:document.hidden?`hidden`:`visible`,reason:`visibility-change`})},document.addEventListener(`visibilitychange`,n),e.onDisconnect.addListener(()=>{console.warn(`[side-panel-state-tracker] Background connection lost`),t&&clearInterval(t)}),e.onMessage.addListener(e=>{e.type===`close-side-panel`&&(t&&clearInterval(t),window.close())}),a({state:document.hidden?`hidden`:`visible`,reason:`document-load`})}),()=>{t&&clearInterval(t),n&&document.removeEventListener(`visibilitychange`,n),e&&e.disconnect(),i=!1}}const o=new Map,s=new Set;let c=!1;function l(){if(!c)throw Error(`Side panel state manager must be initialized with initSidePanelStateManager() before use.`)}function u(){c||(c=!0,chrome.action.onClicked.addListener(e=>{let t=o.get(e.windowId);t&&t.state===`visible`?t.port&&(o.delete(e.windowId),t.port.postMessage({type:`close-side-panel`})):chrome.sidePanel.open({windowId:e.windowId}).catch(console.error)}),chrome.runtime.onConnect.addListener(e=>{e.name===chrome.runtime.id&&(e.onMessage.addListener(t=>{t.type===`side-panel-state-tracker`&&t.state&&f({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(o.entries()).forEach(([t,n])=>{n.port&&n.port===e&&f({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function d(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};s.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function f(e){let{windowId:t,state:n}=e;if(n===`hidden`){o.delete(t),d(e);return}o.set(t,e),d(e)}function p(e){return l(),o.get(e)?.state}function m(e){return l(),p(e)===`visible`}function h(e){return l(),s.add(e),()=>{s.delete(e)}}export{p as getSidePanelStateForWindow,u as initSidePanelStateManager,a as initializeSidePanelStateTracker,m as isWindowSidePanelVisible,h as onSidePanelStateChange,r as onWindowClose};
1
+ const e=new Map;let t=!1;function n(){t||(t=!0,chrome.windows.onRemoved.addListener(t=>{let n=e.get(t);n&&(n.forEach(e=>{e()}),e.delete(t))}))}function r(t,r){n();let i=e.get(t);return i||(i=new Set,e.set(t,i)),i.add(r),()=>{let n=e.get(t);n&&(n.delete(r),n.size===0&&e.delete(t))}}let i=!1;function a(){i&&console.warn(`Side panel state tracker already initialized`),i=!0;let e,t,n;return chrome.windows.getCurrent(r=>{if(r.id==null){console.error(`[side-panel-state-tracker] Could not get window ID`);return}e=chrome.runtime.connect({name:chrome.runtime.id});let i=r.id;function a(t){try{e.postMessage({...t,windowId:i,type:`side-panel-state-tracker`,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Failed to send message:`,e)}}t=setInterval(()=>{try{e.postMessage({type:`side-panel-heartbeat`,windowId:i,timestamp:Date.now()})}catch(e){console.error(`[side-panel-state-tracker] Heartbeat failed:`,e),t&&clearInterval(t)}},15e3),n=()=>{a({state:document.hidden?`hidden`:`visible`,reason:`visibility-change`})},document.addEventListener(`visibilitychange`,n),e.onDisconnect.addListener(()=>{console.warn(`[side-panel-state-tracker] Background connection lost`),t&&clearInterval(t)}),e.onMessage.addListener(e=>{e.type===`close-side-panel`&&(t&&clearInterval(t),window.close())}),a({state:document.hidden?`hidden`:`visible`,reason:`document-load`})}),()=>{t&&clearInterval(t),n&&document.removeEventListener(`visibilitychange`,n),e&&e.disconnect(),i=!1}}const o=new Map,s=new Set;let c=!1;function l(){c||console.error(`Side panel state manager is not initialized.`,`Call initSidePanelStateManager() at the top of your background script before using any other functions.`)}function u(){c||(c=!0,chrome.action.onClicked.addListener(e=>{let t=o.get(e.windowId);t&&t.state===`visible`?t.port&&(o.delete(e.windowId),t.port.postMessage({type:`close-side-panel`})):chrome.sidePanel.open({windowId:e.windowId}).catch(console.error)}),chrome.runtime.onConnect.addListener(e=>{e.name===chrome.runtime.id&&(e.onMessage.addListener(t=>{t.type===`side-panel-state-tracker`&&t.state&&f({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(o.entries()).forEach(([t,n])=>{n.port&&n.port===e&&f({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function d(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};s.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function f(e){let{windowId:t,state:n}=e;if(n===`hidden`){o.delete(t),d(e);return}o.set(t,e),d(e)}function p(e){return l(),o.get(e)?.state}function m(e){return l(),p(e)===`visible`}function h(e){return l(),s.add(e),()=>{s.delete(e)}}export{p as getSidePanelStateForWindow,u as initSidePanelStateManager,a as initializeSidePanelStateTracker,m as isWindowSidePanelVisible,h as onSidePanelStateChange,r as onWindowClose};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pixpilot/chrome-lifecycle",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.6.0",
5
5
  "description": "Lifecycle management utilities for Chrome extensions.",
6
6
  "author": "m.doaie <m.doaie@hotmail.com>",
7
7
  "license": "MIT",
@@ -29,11 +29,11 @@
29
29
  "eslint": "^9.38.0",
30
30
  "tsdown": "^0.15.9",
31
31
  "typescript": "^5.9.3",
32
- "@internal/prettier-config": "0.1.0",
33
- "@internal/tsconfig": "0.1.0",
34
- "@internal/tsdown-config": "0.1.0",
35
32
  "@internal/eslint-config": "0.3.0",
36
- "@internal/vitest-config": "0.1.0"
33
+ "@internal/tsdown-config": "0.1.0",
34
+ "@internal/prettier-config": "0.1.0",
35
+ "@internal/vitest-config": "0.1.0",
36
+ "@internal/tsconfig": "0.1.0"
37
37
  },
38
38
  "prettier": "@internal/prettier-config",
39
39
  "scripts": {