@pixpilot/chrome-lifecycle 0.1.1 → 0.2.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 +112 -12
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,30 +1,130 @@
|
|
|
1
1
|
# @pixpilot/chrome-lifecycle
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Utilities for managing Chrome extension lifecycle events.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install @pixpilot/chrome-lifecycle
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### Window Events
|
|
14
|
+
|
|
15
|
+
#### `onWindowClose(windowId, callback)`
|
|
8
16
|
|
|
9
|
-
|
|
17
|
+
Registers a callback when a specific Chrome window closes.
|
|
10
18
|
|
|
11
19
|
```typescript
|
|
12
20
|
import { onWindowClose } from '@pixpilot/chrome-lifecycle';
|
|
13
21
|
|
|
14
22
|
const unsubscribe = onWindowClose(windowId, () => {
|
|
15
|
-
console.log('Window
|
|
16
|
-
// Perform cleanup or other actions
|
|
23
|
+
console.log('Window closed');
|
|
17
24
|
});
|
|
18
25
|
|
|
19
|
-
//
|
|
26
|
+
// Stop listening
|
|
20
27
|
unsubscribe();
|
|
21
28
|
```
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
| Parameter | Type | Description |
|
|
31
|
+
| ---------- | ------------ | ---------------------------- |
|
|
32
|
+
| `windowId` | `number` | Chrome window ID to watch |
|
|
33
|
+
| `callback` | `() => void` | Function to execute on close |
|
|
34
|
+
|
|
35
|
+
**Returns:** Unsubscribe function
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
### Side Panel State Manager
|
|
40
|
+
|
|
41
|
+
Tracks whether side panels are visible or hidden across different windows.
|
|
42
|
+
|
|
43
|
+
#### Setup
|
|
44
|
+
|
|
45
|
+
**Background script (service worker):**
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { initSidePanelStateManager } from '@pixpilot/chrome-lifecycle';
|
|
49
|
+
|
|
50
|
+
// Initialize once at startup
|
|
51
|
+
initSidePanelStateManager();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Side panel script (frontend):**
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { initializeSidePanelStateTracker } from '@pixpilot/chrome-lifecycle';
|
|
58
|
+
|
|
59
|
+
// Initialize when side panel loads
|
|
60
|
+
const cleanup = initializeSidePanelStateTracker();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Functions
|
|
64
|
+
|
|
65
|
+
##### `initSidePanelStateManager()`
|
|
66
|
+
|
|
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
|
+
```
|
|
74
|
+
|
|
75
|
+
##### `initializeSidePanelStateTracker()`
|
|
76
|
+
|
|
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
|
+
```
|
|
84
|
+
|
|
85
|
+
**Returns:** Cleanup function to remove listeners and disconnect
|
|
86
|
+
|
|
87
|
+
##### `isWindowSidePanelVisible(windowId)`
|
|
88
|
+
|
|
89
|
+
Returns `true` if the side panel is visible for the given window.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { isWindowSidePanelVisible } from '@pixpilot/chrome-lifecycle';
|
|
93
|
+
|
|
94
|
+
const isVisible = isWindowSidePanelVisible(windowId);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
##### `getSidePanelStateForWindow(windowId)`
|
|
98
|
+
|
|
99
|
+
Returns the current state (`'visible'` | `'hidden'` | `undefined`) for the given window.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { getSidePanelStateForWindow } from '@pixpilot/chrome-lifecycle';
|
|
103
|
+
|
|
104
|
+
const state = getSidePanelStateForWindow(windowId);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
##### `onSidePanelStateChange(listener)`
|
|
108
|
+
|
|
109
|
+
Listens for side panel state changes across all windows.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { onSidePanelStateChange } from '@pixpilot/chrome-lifecycle';
|
|
113
|
+
|
|
114
|
+
const unsubscribe = onSidePanelStateChange(({ windowId, state, reason }) => {
|
|
115
|
+
console.log(`Window ${windowId}: ${state}`);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Stop listening
|
|
119
|
+
unsubscribe();
|
|
120
|
+
```
|
|
24
121
|
|
|
25
|
-
|
|
26
|
-
- `callback` (function): Function to execute when the window closes
|
|
122
|
+
**Callback data:**
|
|
27
123
|
|
|
28
|
-
|
|
124
|
+
| Property | Type | Description |
|
|
125
|
+
| ---------- | ------------------------- | ------------------------- |
|
|
126
|
+
| `windowId` | `number` | Chrome window ID |
|
|
127
|
+
| `state` | `'visible'` \| `'hidden'` | Current side panel state |
|
|
128
|
+
| `reason` | `string` | What triggered the change |
|
|
29
129
|
|
|
30
|
-
|
|
130
|
+
**Returns:** Unsubscribe function
|
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))}}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=new Map,a=new Set;let o=!1;function s(){if(!o)throw Error(`Side panel state manager must be initialized with initSidePanelStateManager() before use.`)}function c(){o||(o=!0,chrome.action.onClicked.addListener(e=>{let t=i.get(e.windowId);t&&t.state===`visible`?t.port&&(i.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&&u({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(i.entries()).forEach(([t,n])=>{n.port&&n.port===e&&u({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function l(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};a.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function u(e){let{windowId:t,state:n}=e;if(n===`hidden`){i.delete(t),l(e);return}i.set(t,e),l(e)}function d(e){return s(),i.get(e)?.state}function f(e){return s(),d(e)===`visible`}function p(e){return s(),a.add(e),()=>{a.delete(e)}}exports.getSidePanelStateForWindow=d,exports.initSidePanelStateManager=c,exports.isWindowSidePanelVisible=f,exports.onSidePanelStateChange=p,exports.onWindowClose=r;
|
package/dist/index.d.cts
CHANGED
|
@@ -17,4 +17,38 @@ type CloseCallback = () => void;
|
|
|
17
17
|
*/
|
|
18
18
|
declare function onWindowClose(windowId: number, callback: CloseCallback): () => void;
|
|
19
19
|
//#endregion
|
|
20
|
-
|
|
20
|
+
//#region src/types/side-panel.d.ts
|
|
21
|
+
type SidePanelState = 'visible' | 'hidden';
|
|
22
|
+
interface BaseSidePanelMessage {
|
|
23
|
+
windowId: number;
|
|
24
|
+
timestamp?: number;
|
|
25
|
+
}
|
|
26
|
+
interface SidePanelStateData extends BaseSidePanelMessage {
|
|
27
|
+
type: 'side-panel-heartbeat' | 'side-panel-state-tracker' | 'side-panel-state-open';
|
|
28
|
+
state: SidePanelState;
|
|
29
|
+
reason: string;
|
|
30
|
+
}
|
|
31
|
+
type SidePanelStateChangeData = Omit<SidePanelStateData, 'timestamp' | 'type'>;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/sidepanel-state-manager.d.ts
|
|
34
|
+
type SidePanelStateListener = (data: SidePanelStateChangeData) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Initializes the side panel state manager.
|
|
37
|
+
* Sets up Chrome event listeners for action clicks and runtime connections.
|
|
38
|
+
* This function should be called once before using other functions in this module.
|
|
39
|
+
* Subsequent calls will log a warning and do nothing.
|
|
40
|
+
*/
|
|
41
|
+
declare function initSidePanelStateManager(): void;
|
|
42
|
+
declare function getSidePanelStateForWindow(windowId: number): SidePanelState | undefined;
|
|
43
|
+
declare function isWindowSidePanelVisible(windowId: number): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Adds a listener for side panel state changes.
|
|
46
|
+
* The listener will be called whenever the side panel state changes (visible/hidden).
|
|
47
|
+
* Note: Heartbeat messages do not trigger listeners, and timestamp is excluded from the data.
|
|
48
|
+
*
|
|
49
|
+
* @param listener - Callback function that receives state change data
|
|
50
|
+
* @returns Unsubscribe function to remove the listener
|
|
51
|
+
*/
|
|
52
|
+
declare function onSidePanelStateChange(listener: SidePanelStateListener): () => void;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { getSidePanelStateForWindow, initSidePanelStateManager, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
package/dist/index.d.ts
CHANGED
|
@@ -17,4 +17,38 @@ type CloseCallback = () => void;
|
|
|
17
17
|
*/
|
|
18
18
|
declare function onWindowClose(windowId: number, callback: CloseCallback): () => void;
|
|
19
19
|
//#endregion
|
|
20
|
-
|
|
20
|
+
//#region src/types/side-panel.d.ts
|
|
21
|
+
type SidePanelState = 'visible' | 'hidden';
|
|
22
|
+
interface BaseSidePanelMessage {
|
|
23
|
+
windowId: number;
|
|
24
|
+
timestamp?: number;
|
|
25
|
+
}
|
|
26
|
+
interface SidePanelStateData extends BaseSidePanelMessage {
|
|
27
|
+
type: 'side-panel-heartbeat' | 'side-panel-state-tracker' | 'side-panel-state-open';
|
|
28
|
+
state: SidePanelState;
|
|
29
|
+
reason: string;
|
|
30
|
+
}
|
|
31
|
+
type SidePanelStateChangeData = Omit<SidePanelStateData, 'timestamp' | 'type'>;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/sidepanel-state-manager.d.ts
|
|
34
|
+
type SidePanelStateListener = (data: SidePanelStateChangeData) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Initializes the side panel state manager.
|
|
37
|
+
* Sets up Chrome event listeners for action clicks and runtime connections.
|
|
38
|
+
* This function should be called once before using other functions in this module.
|
|
39
|
+
* Subsequent calls will log a warning and do nothing.
|
|
40
|
+
*/
|
|
41
|
+
declare function initSidePanelStateManager(): void;
|
|
42
|
+
declare function getSidePanelStateForWindow(windowId: number): SidePanelState | undefined;
|
|
43
|
+
declare function isWindowSidePanelVisible(windowId: number): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Adds a listener for side panel state changes.
|
|
46
|
+
* The listener will be called whenever the side panel state changes (visible/hidden).
|
|
47
|
+
* Note: Heartbeat messages do not trigger listeners, and timestamp is excluded from the data.
|
|
48
|
+
*
|
|
49
|
+
* @param listener - Callback function that receives state change data
|
|
50
|
+
* @returns Unsubscribe function to remove the listener
|
|
51
|
+
*/
|
|
52
|
+
declare function onSidePanelStateChange(listener: SidePanelStateListener): () => void;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { getSidePanelStateForWindow, initSidePanelStateManager, isWindowSidePanelVisible, onSidePanelStateChange, onWindowClose };
|
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))}}export{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))}}const i=new Map,a=new Set;let o=!1;function s(){if(!o)throw Error(`Side panel state manager must be initialized with initSidePanelStateManager() before use.`)}function c(){o||(o=!0,chrome.action.onClicked.addListener(e=>{let t=i.get(e.windowId);t&&t.state===`visible`?t.port&&(i.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&&u({port:e,state:t.state,reason:t.reason??`unknown`,windowId:t.windowId,type:t.type})}),e.onDisconnect.addListener(e=>{Array.from(i.entries()).forEach(([t,n])=>{n.port&&n.port===e&&u({port:void 0,state:`hidden`,reason:`port-disconnected`,windowId:t,type:`side-panel-state-tracker`})})}))}))}function l(e){if(e.type!==`side-panel-state-tracker`)return;let t={state:e.state,reason:e.reason,windowId:e.windowId};a.forEach(e=>{try{e(t)}catch(e){console.error(`Error in side panel state listener:`,e)}})}function u(e){let{windowId:t,state:n}=e;if(n===`hidden`){i.delete(t),l(e);return}i.set(t,e),l(e)}function d(e){return s(),i.get(e)?.state}function f(e){return s(),d(e)===`visible`}function p(e){return s(),a.add(e),()=>{a.delete(e)}}export{d as getSidePanelStateForWindow,c as initSidePanelStateManager,f as isWindowSidePanelVisible,p 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.
|
|
4
|
+
"version": "0.2.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/tsdown-config": "0.1.0",
|
|
34
32
|
"@internal/eslint-config": "0.3.0",
|
|
33
|
+
"@internal/tsdown-config": "0.1.0",
|
|
35
34
|
"@internal/tsconfig": "0.1.0",
|
|
36
|
-
"@internal/vitest-config": "0.1.0"
|
|
35
|
+
"@internal/vitest-config": "0.1.0",
|
|
36
|
+
"@internal/prettier-config": "0.1.0"
|
|
37
37
|
},
|
|
38
38
|
"prettier": "@internal/prettier-config",
|
|
39
39
|
"scripts": {
|