browser-extension-manager 1.3.16 → 1.3.18
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/CHANGELOG.md +9 -0
- package/CLAUDE.md +27 -37
- package/README.md +18 -87
- package/dist/background.js +171 -114
- package/dist/lib/auth-helpers.js +98 -97
- package/dist/options.js +9 -3
- package/dist/page.js +9 -3
- package/dist/popup.js +9 -3
- package/dist/sidepanel.js +9 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
15
15
|
- `Security` in case of vulnerabilities.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
|
+
## [1.3.17] - 2025-12-23
|
|
19
|
+
### Changed
|
|
20
|
+
- Auth system now uses messaging instead of `chrome.storage` for cross-context sync
|
|
21
|
+
- Background.js is the source of truth; contexts sync via `bxm:syncAuth` message on load
|
|
22
|
+
- Fresh custom tokens fetched from server only when context UID differs from background UID
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- Auth failures caused by expired custom tokens (tokens no longer stored, fetched fresh when needed)
|
|
26
|
+
|
|
18
27
|
## [1.3.0] - 2025-12-16
|
|
19
28
|
|
|
20
29
|
### Added
|
package/CLAUDE.md
CHANGED
|
@@ -354,11 +354,7 @@ Provides cross-context auth synchronization and reusable auth UI event handlers.
|
|
|
354
354
|
|
|
355
355
|
### Cross-Context Auth Architecture
|
|
356
356
|
|
|
357
|
-
**Background.js is the source of truth** for authentication. Browser extensions have multiple isolated JavaScript contexts (background, popup, options, pages, sidepanel) - each runs its own Firebase instance. BEM
|
|
358
|
-
|
|
359
|
-
1. Background.js monitors for auth tokens via `tabs.onUpdated`
|
|
360
|
-
2. When detected, background signs in Firebase and saves to `chrome.storage`
|
|
361
|
-
3. Other contexts listen to storage changes and sync their Firebase instances
|
|
357
|
+
**Background.js is the source of truth** for authentication. Browser extensions have multiple isolated JavaScript contexts (background, popup, options, pages, sidepanel) - each runs its own Firebase instance. BEM syncs them via messaging (no storage).
|
|
362
358
|
|
|
363
359
|
**Sign-in Flow:**
|
|
364
360
|
```
|
|
@@ -366,29 +362,36 @@ User clicks .auth-signin-btn
|
|
|
366
362
|
→ openAuthPage() opens https://{authDomain}/token?authSourceTabId=123
|
|
367
363
|
→ Website authenticates, redirects to /token?authToken=xxx
|
|
368
364
|
→ background.js tabs.onUpdated detects authDomain URL with authToken param
|
|
369
|
-
→ background.js
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
365
|
+
→ background.js signs in with signInWithCustomToken()
|
|
366
|
+
→ background.js broadcasts token to all open contexts via postMessage()
|
|
367
|
+
→ Closes the /token tab, reactivates original tab
|
|
368
|
+
→ Open contexts receive broadcast and sign in with the token
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Context Load Flow:**
|
|
372
|
+
```
|
|
373
|
+
Context loads (popup, page, options, sidepanel)
|
|
374
|
+
→ Web Manager initializes, waits for auth to settle via auth.listen({once: true})
|
|
375
|
+
→ Sends bxm:syncAuth message to background with local UID
|
|
376
|
+
→ Background compares UIDs:
|
|
377
|
+
→ Same UID (including both null) → already in sync, no action
|
|
378
|
+
→ Different UID → background fetches fresh custom token from server, sends to context
|
|
379
|
+
→ Background signed out, context signed in → tells context to sign out
|
|
376
380
|
```
|
|
377
381
|
|
|
378
382
|
**Sign-out Flow:**
|
|
379
383
|
```
|
|
380
384
|
User clicks .auth-signout-btn
|
|
381
|
-
→ Web Manager signs out Firebase
|
|
382
|
-
→
|
|
383
|
-
→
|
|
384
|
-
→ background.js
|
|
385
|
-
→
|
|
386
|
-
→ Other contexts detect storage cleared and sign out
|
|
385
|
+
→ Web Manager signs out that context's Firebase
|
|
386
|
+
→ setupSignOutListener() detects sign-out, sends bxm:signOut to background
|
|
387
|
+
→ background.js signs out its Firebase
|
|
388
|
+
→ background.js broadcasts bxm:signOut to all other contexts
|
|
389
|
+
→ All contexts sign out
|
|
387
390
|
```
|
|
388
391
|
|
|
389
392
|
**Key Implementation Details:**
|
|
390
393
|
|
|
391
|
-
1. **
|
|
394
|
+
1. **No storage**: Auth state is NOT stored in `chrome.storage`. Firebase persists sessions in IndexedDB per context. Web Manager handles UI bindings.
|
|
392
395
|
|
|
393
396
|
2. **Firebase in service workers**: Static ES6 imports are required. Dynamic `import()` fails with webpack chunking in service workers.
|
|
394
397
|
|
|
@@ -397,7 +400,9 @@ User clicks .auth-signout-btn
|
|
|
397
400
|
4. **Required permission**: `tabs` permission needed for `tabs.onUpdated` listener.
|
|
398
401
|
|
|
399
402
|
**Functions:**
|
|
400
|
-
- `
|
|
403
|
+
- `syncWithBackground(context)` - Compares context's UID with background's UID on load, syncs if different
|
|
404
|
+
- `setupAuthBroadcastListener(context)` - Listens for sign-in/sign-out broadcasts from background
|
|
405
|
+
- `setupSignOutListener(context)` - Notifies background when context signs out
|
|
401
406
|
- `setupAuthEventListeners(context)` - Sets up delegated click handlers for auth buttons
|
|
402
407
|
- `openAuthPage(context, options)` - Opens auth page on the website with authSourceTabId for tab restoration
|
|
403
408
|
|
|
@@ -432,21 +437,6 @@ Add these classes to your HTML elements to enable automatic auth handling:
|
|
|
432
437
|
- `data-wm-bind="@text auth.user.email"` - Display user's email
|
|
433
438
|
- `data-wm-bind="@attr src auth.user.photoURL"` - Set avatar image src
|
|
434
439
|
|
|
435
|
-
**Storage Schema (`bxm:authState`):**
|
|
436
|
-
```javascript
|
|
437
|
-
{
|
|
438
|
-
token: "firebase-custom-token", // Used by other contexts to sign in
|
|
439
|
-
user: {
|
|
440
|
-
uid: "...",
|
|
441
|
-
email: "...",
|
|
442
|
-
displayName: "...",
|
|
443
|
-
photoURL: "...",
|
|
444
|
-
emailVerified: true
|
|
445
|
-
},
|
|
446
|
-
timestamp: 1234567890
|
|
447
|
-
}
|
|
448
|
-
```
|
|
449
|
-
|
|
450
440
|
**Logger:** [src/lib/logger.js](src/lib/logger.js)
|
|
451
441
|
- Full logging utility
|
|
452
442
|
- [src/lib/logger-lite.js](src/lib/logger-lite.js) for lightweight contexts
|
|
@@ -808,8 +798,8 @@ Manager.initialize().then(() => {
|
|
|
808
798
|
- [src/cli.js](src/cli.js) - CLI implementation
|
|
809
799
|
|
|
810
800
|
**Auth System (Cross-Context):**
|
|
811
|
-
- [src/background.js](src/background.js) - Source of truth
|
|
812
|
-
- [src/lib/auth-helpers.js](src/lib/auth-helpers.js) - `
|
|
801
|
+
- [src/background.js](src/background.js) - Source of truth; `handleSyncAuth()`, `handleSignOut()`, `broadcastAuthToken()`
|
|
802
|
+
- [src/lib/auth-helpers.js](src/lib/auth-helpers.js) - `syncWithBackground()`, `setupAuthBroadcastListener()`, `setupSignOutListener()`
|
|
813
803
|
|
|
814
804
|
**CSS Framework:**
|
|
815
805
|
- [src/assets/css/browser-extension-manager.scss](src/assets/css/browser-extension-manager.scss) - Main entry
|
package/README.md
CHANGED
|
@@ -88,112 +88,43 @@ Only stores with configured credentials will be published to.
|
|
|
88
88
|
|
|
89
89
|
## 🔐 Authentication
|
|
90
90
|
|
|
91
|
-
BEM provides built-in authentication
|
|
91
|
+
BEM provides built-in authentication that syncs across all extension contexts (popup, options, pages, sidepanel, background).
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### How It Works
|
|
94
94
|
|
|
95
|
-
**Background.js is the source of truth
|
|
95
|
+
**Background.js is the source of truth.** Auth syncs via messaging (no storage).
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
├─────────────────────────────────────────────────────────────────────────┤
|
|
101
|
-
│ 1. User clicks .auth-signin-btn in any context │
|
|
102
|
-
│ 2. Extension opens https://{authDomain}/token?authSourceTabId=123 │
|
|
103
|
-
│ 3. Website authenticates user, redirects to /token?authToken=xxx │
|
|
104
|
-
│ 4. Background.js detects URL via tabs.onUpdated listener │
|
|
105
|
-
│ 5. Background signs in Firebase with custom token │
|
|
106
|
-
│ 6. Background saves auth state to chrome.storage (bxm:authState) │
|
|
107
|
-
│ 7. Background closes /token tab and reactivates original tab │
|
|
108
|
-
│ 8. Other contexts detect storage change and sign in their Firebase │
|
|
109
|
-
└─────────────────────────────────────────────────────────────────────────┘
|
|
110
|
-
|
|
111
|
-
┌─────────────────────────────────────────────────────────────────────────┐
|
|
112
|
-
│ SIGN-OUT FLOW │
|
|
113
|
-
├─────────────────────────────────────────────────────────────────────────┤
|
|
114
|
-
│ 1. User clicks .auth-signout-btn in any context │
|
|
115
|
-
│ 2. Web Manager signs out Firebase locally │
|
|
116
|
-
│ 3. Auth helper detects WM auth change, clears bxm:authState storage │
|
|
117
|
-
│ 4. Background.js detects storage cleared, signs out its Firebase │
|
|
118
|
-
│ 5. Other contexts detect storage change and sign out │
|
|
119
|
-
└─────────────────────────────────────────────────────────────────────────┘
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Required Configuration
|
|
123
|
-
|
|
124
|
-
Add `authDomain` to your Firebase config in `config/browser-extension-manager.json`:
|
|
125
|
-
|
|
126
|
-
```json
|
|
127
|
-
{
|
|
128
|
-
"firebaseConfig": {
|
|
129
|
-
"apiKey": "...",
|
|
130
|
-
"authDomain": "your-app.firebaseapp.com",
|
|
131
|
-
"projectId": "..."
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
```
|
|
97
|
+
- **Sign-in**: User clicks `.auth-signin-btn` → opens `/token` page on website → website authenticates and redirects with token → background.js signs in and broadcasts to all open contexts
|
|
98
|
+
- **Context load**: Each context compares its UID with background's UID on load; syncs if different
|
|
99
|
+
- **Sign-out**: User clicks `.auth-signout-btn` → context signs out → notifies background → background broadcasts sign-out to all contexts
|
|
135
100
|
|
|
136
|
-
### Required
|
|
101
|
+
### Required Setup
|
|
137
102
|
|
|
138
|
-
Add
|
|
139
|
-
|
|
140
|
-
```json
|
|
141
|
-
{
|
|
142
|
-
"permissions": ["tabs"]
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
This is required for background.js to monitor tab URL changes and detect auth tokens.
|
|
103
|
+
1. Add `authDomain` to your Firebase config in `config/browser-extension-manager.json`
|
|
104
|
+
2. Add `tabs` permission to `src/manifest.json` (for URL monitoring)
|
|
147
105
|
|
|
148
106
|
### Auth Button Classes
|
|
149
107
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
|
153
|
-
|
|
154
|
-
| `.auth-
|
|
155
|
-
| `.auth-signout-btn` | Sign out button | Signs out via Web Manager (which triggers storage sync) |
|
|
156
|
-
| `.auth-account-btn` | Account button | Opens `/account` page on website |
|
|
108
|
+
| Class | Action |
|
|
109
|
+
|-------|--------|
|
|
110
|
+
| `.auth-signin-btn` | Opens `/token` page on website |
|
|
111
|
+
| `.auth-signout-btn` | Signs out via Web Manager |
|
|
112
|
+
| `.auth-account-btn` | Opens `/account` page on website |
|
|
157
113
|
|
|
158
114
|
### Example
|
|
159
115
|
```html
|
|
160
|
-
|
|
161
|
-
<button class="btn auth-signin-btn" data-wm-bind="@show !auth.user">
|
|
162
|
-
Sign In
|
|
163
|
-
</button>
|
|
116
|
+
<button class="btn auth-signin-btn" data-wm-bind="@show !auth.user">Sign In</button>
|
|
164
117
|
|
|
165
|
-
<!-- Account Section (shown when logged in) -->
|
|
166
118
|
<div data-wm-bind="@show auth.user" hidden>
|
|
167
119
|
<span data-wm-bind="@text auth.user.displayName">User</span>
|
|
168
|
-
<a class="auth-account-btn" href="#">Account</a>
|
|
169
120
|
<button class="auth-signout-btn">Sign Out</button>
|
|
170
121
|
</div>
|
|
171
122
|
```
|
|
172
123
|
|
|
173
124
|
### Reactive Bindings
|
|
174
|
-
- `
|
|
175
|
-
- `
|
|
176
|
-
-
|
|
177
|
-
- `data-wm-bind="@text auth.user.email"` - Display user's email
|
|
178
|
-
- `data-wm-bind="@attr src auth.user.photoURL"` - Set avatar image src
|
|
179
|
-
|
|
180
|
-
### Storage Key
|
|
181
|
-
|
|
182
|
-
Auth state is stored in `chrome.storage` under the key `bxm:authState`:
|
|
183
|
-
|
|
184
|
-
```javascript
|
|
185
|
-
{
|
|
186
|
-
token: "firebase-custom-token",
|
|
187
|
-
user: {
|
|
188
|
-
uid: "...",
|
|
189
|
-
email: "...",
|
|
190
|
-
displayName: "...",
|
|
191
|
-
photoURL: "...",
|
|
192
|
-
emailVerified: true
|
|
193
|
-
},
|
|
194
|
-
timestamp: 1234567890
|
|
195
|
-
}
|
|
196
|
-
```
|
|
125
|
+
- `@show auth.user` / `@show !auth.user` - Show/hide based on auth state
|
|
126
|
+
- `@text auth.user.displayName` / `@text auth.user.email` - Display user info
|
|
127
|
+
- `@attr src auth.user.photoURL` - Set avatar image
|
|
197
128
|
|
|
198
129
|
<!-- ## ⛳️ Flags
|
|
199
130
|
* `--test=false` - Coming soon
|
package/dist/background.js
CHANGED
|
@@ -65,11 +65,8 @@ class Manager {
|
|
|
65
65
|
// Setup auth token listener (for cross-runtime auth)
|
|
66
66
|
this.setupAuthTokenListener();
|
|
67
67
|
|
|
68
|
-
//
|
|
69
|
-
this.
|
|
70
|
-
|
|
71
|
-
// Restore auth state from storage on startup
|
|
72
|
-
this.restoreAuthState();
|
|
68
|
+
// Initialize Firebase auth on startup (restores persisted session if any)
|
|
69
|
+
this.initializeAuth();
|
|
73
70
|
|
|
74
71
|
// Setup livereload
|
|
75
72
|
this.setupLiveReload();
|
|
@@ -125,10 +122,15 @@ class Manager {
|
|
|
125
122
|
|
|
126
123
|
// Listen for runtime messages (from popup, options, pages, etc.)
|
|
127
124
|
this.extension.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|
128
|
-
// Handle auth
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
// Handle auth sync requests - contexts ask background for auth state on load
|
|
126
|
+
if (message.command === 'bxm:syncAuth') {
|
|
127
|
+
this.handleSyncAuth(message, sendResponse);
|
|
128
|
+
return true; // Keep channel open for async response
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Handle sign-out requests from contexts
|
|
132
|
+
if (message.command === 'bxm:signOut') {
|
|
133
|
+
this.handleSignOut(sendResponse);
|
|
132
134
|
return true; // Keep channel open for async response
|
|
133
135
|
}
|
|
134
136
|
});
|
|
@@ -137,28 +139,128 @@ class Manager {
|
|
|
137
139
|
this.logger.log('Set up message handlers');
|
|
138
140
|
}
|
|
139
141
|
|
|
140
|
-
// Handle
|
|
141
|
-
//
|
|
142
|
-
async
|
|
142
|
+
// Handle auth sync request from other contexts (popup, page, options, sidepanel)
|
|
143
|
+
// Compares context's UID with background's UID and provides fresh token only if different
|
|
144
|
+
async handleSyncAuth(message, sendResponse) {
|
|
143
145
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
const contextUid = message.contextUid || null; // UID from asking context (or null)
|
|
147
|
+
|
|
148
|
+
// Get or initialize Firebase auth
|
|
149
|
+
const auth = this.getFirebaseAuth();
|
|
150
|
+
const bgUser = auth.currentUser;
|
|
151
|
+
const bgUid = bgUser?.uid || null;
|
|
152
|
+
|
|
153
|
+
this.logger.log('[AUTH] syncAuth: Comparing UIDs - context:', contextUid, 'background:', bgUid);
|
|
154
|
+
|
|
155
|
+
// Already in sync (both null, or same UID)
|
|
156
|
+
if (contextUid === bgUid) {
|
|
157
|
+
this.logger.log('[AUTH] syncAuth: Already in sync');
|
|
158
|
+
sendResponse({ needsSync: false });
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Context is signed in but background is not → context should sign out
|
|
163
|
+
if (!bgUser && contextUid) {
|
|
164
|
+
this.logger.log('[AUTH] syncAuth: Background signed out, telling context to sign out');
|
|
165
|
+
sendResponse({ needsSync: true, signOut: true });
|
|
148
166
|
return;
|
|
149
167
|
}
|
|
150
168
|
|
|
151
|
-
//
|
|
152
|
-
|
|
169
|
+
// Background is signed in, context is not (or different user) → provide token
|
|
170
|
+
this.logger.log('[AUTH] syncAuth: Fetching fresh custom token for context...', bgUser.email);
|
|
171
|
+
|
|
172
|
+
// Get API URL from config
|
|
173
|
+
const apiUrl = this.config?.web_manager?.api?.url || 'https://api.itwcreativeworks.com';
|
|
174
|
+
|
|
175
|
+
// Get fresh ID token for authorization
|
|
176
|
+
const idToken = await bgUser.getIdToken(true);
|
|
177
|
+
|
|
178
|
+
// Fetch fresh custom token from server
|
|
179
|
+
const response = await fetch(`${apiUrl}/backend-manager`, {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
headers: {
|
|
182
|
+
'Content-Type': 'application/json',
|
|
183
|
+
'Authorization': `Bearer ${idToken}`,
|
|
184
|
+
},
|
|
185
|
+
body: JSON.stringify({
|
|
186
|
+
command: 'user:create-custom-token',
|
|
187
|
+
payload: {},
|
|
188
|
+
}),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Check response
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
throw new Error(`Server responded with ${response.status}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Parse response
|
|
197
|
+
const data = await response.json();
|
|
198
|
+
|
|
199
|
+
// Check for token in response
|
|
200
|
+
if (!data.response?.token) {
|
|
201
|
+
throw new Error('No token in server response');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.logger.log('[AUTH] syncAuth: Got fresh custom token, sending to context');
|
|
205
|
+
|
|
206
|
+
// Send user info and fresh custom token
|
|
207
|
+
sendResponse({
|
|
208
|
+
needsSync: true,
|
|
209
|
+
customToken: data.response.token,
|
|
210
|
+
user: {
|
|
211
|
+
uid: bgUser.uid,
|
|
212
|
+
email: bgUser.email,
|
|
213
|
+
displayName: bgUser.displayName,
|
|
214
|
+
photoURL: bgUser.photoURL,
|
|
215
|
+
emailVerified: bgUser.emailVerified,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
} catch (error) {
|
|
220
|
+
this.logger.error('[AUTH] syncAuth error:', error.message);
|
|
221
|
+
sendResponse({ needsSync: false, error: error.message });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Handle sign-out request from a context
|
|
226
|
+
// Signs out background's Firebase and broadcasts to all other contexts
|
|
227
|
+
async handleSignOut(sendResponse) {
|
|
228
|
+
try {
|
|
229
|
+
this.logger.log('[AUTH] handleSignOut: Signing out background Firebase...');
|
|
230
|
+
|
|
231
|
+
// Sign out background's Firebase
|
|
232
|
+
if (this.libraries.firebaseAuth?.currentUser) {
|
|
233
|
+
await this.libraries.firebaseAuth.signOut();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Broadcast to all contexts
|
|
237
|
+
await this.broadcastSignOut();
|
|
153
238
|
|
|
154
|
-
this.logger.log('[AUTH]
|
|
155
|
-
sendResponse({ success: true
|
|
239
|
+
this.logger.log('[AUTH] handleSignOut: Complete');
|
|
240
|
+
sendResponse({ success: true });
|
|
156
241
|
} catch (error) {
|
|
157
|
-
this.logger.error('[AUTH]
|
|
242
|
+
this.logger.error('[AUTH] handleSignOut error:', error.message);
|
|
158
243
|
sendResponse({ success: false, error: error.message });
|
|
159
244
|
}
|
|
160
245
|
}
|
|
161
246
|
|
|
247
|
+
// Broadcast sign-out to all open extension contexts
|
|
248
|
+
async broadcastSignOut() {
|
|
249
|
+
try {
|
|
250
|
+
const clients = await self.clients.matchAll({ type: 'all' });
|
|
251
|
+
|
|
252
|
+
this.logger.log(`[AUTH] Broadcasting sign-out to ${clients.length} clients...`);
|
|
253
|
+
|
|
254
|
+
for (const client of clients) {
|
|
255
|
+
client.postMessage({ command: 'bxm:signOut' });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
this.logger.log('[AUTH] Sign-out broadcast complete');
|
|
259
|
+
} catch (error) {
|
|
260
|
+
this.logger.error('[AUTH] Error broadcasting sign-out:', error.message);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
162
264
|
// Initialize Firebase
|
|
163
265
|
initializeFirebase() {
|
|
164
266
|
// Get Firebase config
|
|
@@ -281,75 +383,25 @@ class Manager {
|
|
|
281
383
|
});
|
|
282
384
|
}
|
|
283
385
|
|
|
284
|
-
//
|
|
285
|
-
setupAuthStorageListener() {
|
|
286
|
-
this.extension.storage.onChanged.addListener((changes) => {
|
|
287
|
-
const authChange = changes['bxm:authState'];
|
|
288
|
-
if (!authChange) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
this.logger.log('[AUTH] Storage auth state changed:', authChange.newValue ? 'signed in' : 'signed out');
|
|
293
|
-
|
|
294
|
-
// If storage was cleared (sign-out from a page) and we have Firebase initialized, sign out
|
|
295
|
-
if (!authChange.newValue && this.libraries.firebaseAuth) {
|
|
296
|
-
this.logger.log('[AUTH] Signing out background Firebase...');
|
|
297
|
-
this.libraries.firebaseAuth.signOut();
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
this.logger.log('[AUTH] Auth storage listener set up');
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Restore auth state on startup
|
|
386
|
+
// Initialize Firebase auth on startup
|
|
305
387
|
// Firebase Auth persists sessions in IndexedDB - we just need to initialize it
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const authState = result['bxm:authState'];
|
|
314
|
-
|
|
315
|
-
// Log existing storage state
|
|
316
|
-
if (authState) {
|
|
317
|
-
this.logger.log('[AUTH] Found existing auth state in storage on startup:', {
|
|
318
|
-
user: authState.user?.email || 'unknown',
|
|
319
|
-
timestamp: authState.timestamp,
|
|
320
|
-
age: authState.timestamp ? `${Math.round((Date.now() - authState.timestamp) / 1000 / 60)} minutes ago` : 'unknown',
|
|
321
|
-
});
|
|
322
|
-
} else {
|
|
323
|
-
this.logger.log('[AUTH] No existing auth state found in storage on startup');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Get Firebase config
|
|
327
|
-
const firebaseConfig = this.config?.firebase?.app?.config;
|
|
328
|
-
if (!firebaseConfig) {
|
|
329
|
-
this.logger.log('[AUTH] Firebase config not available, skipping auth restore');
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Initialize Firebase auth - it will auto-restore from IndexedDB if session exists
|
|
334
|
-
// onAuthStateChanged (set up in getFirebaseAuth) will fire and sync to storage
|
|
335
|
-
this.logger.log('[AUTH] Initializing Firebase Auth (will restore persisted session if any)...');
|
|
336
|
-
const auth = this.getFirebaseAuth();
|
|
388
|
+
initializeAuth() {
|
|
389
|
+
// Get Firebase config
|
|
390
|
+
const firebaseConfig = this.config?.firebase?.app?.config;
|
|
391
|
+
if (!firebaseConfig) {
|
|
392
|
+
this.logger.log('[AUTH] Firebase config not available, skipping auth initialization');
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
337
395
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
} else {
|
|
342
|
-
this.logger.log('[AUTH] No persisted Firebase session found');
|
|
396
|
+
// Initialize Firebase auth - it will auto-restore from IndexedDB if session exists
|
|
397
|
+
this.logger.log('[AUTH] Initializing Firebase Auth (will restore persisted session if any)...');
|
|
398
|
+
const auth = this.getFirebaseAuth();
|
|
343
399
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
} catch (error) {
|
|
352
|
-
this.logger.error('[AUTH] Error restoring auth state:', error.message);
|
|
400
|
+
// Check if already signed in (Firebase restored from IndexedDB)
|
|
401
|
+
if (auth.currentUser) {
|
|
402
|
+
this.logger.log('[AUTH] Firebase restored session from persistence:', auth.currentUser.email);
|
|
403
|
+
} else {
|
|
404
|
+
this.logger.log('[AUTH] No persisted Firebase session found');
|
|
353
405
|
}
|
|
354
406
|
}
|
|
355
407
|
|
|
@@ -385,31 +437,10 @@ class Manager {
|
|
|
385
437
|
}
|
|
386
438
|
|
|
387
439
|
// Handle Firebase auth state changes (source of truth for all contexts)
|
|
388
|
-
//
|
|
389
|
-
|
|
440
|
+
// No storage operations - Web Manager handles auth state internally
|
|
441
|
+
handleAuthStateChange(user) {
|
|
390
442
|
this.logger.log('[AUTH] Auth state changed:', user?.email || 'signed out');
|
|
391
|
-
|
|
392
|
-
if (user) {
|
|
393
|
-
// User is signed in - store user info only (no tokens, they expire)
|
|
394
|
-
// Other contexts will request fresh ID tokens via bxm:getIdToken message
|
|
395
|
-
const authState = {
|
|
396
|
-
user: {
|
|
397
|
-
uid: user.uid,
|
|
398
|
-
email: user.email,
|
|
399
|
-
displayName: user.displayName,
|
|
400
|
-
photoURL: user.photoURL,
|
|
401
|
-
emailVerified: user.emailVerified,
|
|
402
|
-
},
|
|
403
|
-
timestamp: Date.now(),
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
await this.extension.storage.local.set({ 'bxm:authState': authState });
|
|
407
|
-
this.logger.log('[AUTH] Auth state synced to storage (user info only)');
|
|
408
|
-
} else {
|
|
409
|
-
// User is signed out - clear storage
|
|
410
|
-
await this.extension.storage.local.remove('bxm:authState');
|
|
411
|
-
this.logger.log('[AUTH] Auth state cleared from storage');
|
|
412
|
-
}
|
|
443
|
+
// Nothing else to do - contexts sync via messages, WM handles UI
|
|
413
444
|
}
|
|
414
445
|
|
|
415
446
|
// Handle auth token from website (custom token from /token page)
|
|
@@ -422,8 +453,6 @@ class Manager {
|
|
|
422
453
|
const auth = this.getFirebaseAuth();
|
|
423
454
|
|
|
424
455
|
// Sign in with custom token
|
|
425
|
-
// Firebase Auth will persist the session - we don't store the custom token (it expires in 1 hour)
|
|
426
|
-
// Other contexts will request fresh ID tokens via bxm:getIdToken message
|
|
427
456
|
this.logger.log('[AUTH] Calling signInWithCustomToken...');
|
|
428
457
|
const userCredential = await signInWithCustomToken(auth, token);
|
|
429
458
|
const user = userCredential.user;
|
|
@@ -431,7 +460,12 @@ class Manager {
|
|
|
431
460
|
// Log
|
|
432
461
|
this.logger.log('[AUTH] Signed in successfully:', user.email);
|
|
433
462
|
|
|
434
|
-
//
|
|
463
|
+
// Broadcast token to all open extension contexts so they can sign in immediately
|
|
464
|
+
// Token is NOT stored - it expires in 1 hour and is only needed for initial sign-in
|
|
465
|
+
this.broadcastAuthToken(token);
|
|
466
|
+
|
|
467
|
+
// Note: onAuthStateChanged will fire and store user info (without token) in storage
|
|
468
|
+
// This allows UI to show auth state, but token is never persisted
|
|
435
469
|
|
|
436
470
|
// Close the auth tab
|
|
437
471
|
await this.extension.tabs.remove(tabId);
|
|
@@ -453,6 +487,29 @@ class Manager {
|
|
|
453
487
|
}
|
|
454
488
|
}
|
|
455
489
|
|
|
490
|
+
// Broadcast auth token to all open extension contexts
|
|
491
|
+
// Used during initial sign-in to immediately sync all open popups, pages, etc.
|
|
492
|
+
async broadcastAuthToken(token) {
|
|
493
|
+
try {
|
|
494
|
+
// Get all clients (extension pages, popups, etc.)
|
|
495
|
+
const clients = await self.clients.matchAll({ type: 'all' });
|
|
496
|
+
|
|
497
|
+
this.logger.log(`[AUTH] Broadcasting token to ${clients.length} clients...`);
|
|
498
|
+
|
|
499
|
+
// Send token to each client
|
|
500
|
+
for (const client of clients) {
|
|
501
|
+
client.postMessage({
|
|
502
|
+
command: 'bxm:signInWithToken',
|
|
503
|
+
token: token,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
this.logger.log('[AUTH] Token broadcast complete');
|
|
508
|
+
} catch (error) {
|
|
509
|
+
this.logger.error('[AUTH] Error broadcasting token:', error.message);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
456
513
|
// Setup livereload
|
|
457
514
|
setupLiveReload() {
|
|
458
515
|
// Quit if not in dev mode
|
package/dist/lib/auth-helpers.js
CHANGED
|
@@ -2,120 +2,135 @@
|
|
|
2
2
|
// Used by popup.js, options.js, sidepanel.js, page.js
|
|
3
3
|
//
|
|
4
4
|
// Architecture:
|
|
5
|
-
// - Background.js is the
|
|
6
|
-
// -
|
|
7
|
-
// -
|
|
8
|
-
//
|
|
9
|
-
// Flow:
|
|
10
|
-
// 1. Storage listener detects auth state change (user signed in/out)
|
|
11
|
-
// 2. If signed in, request fresh ID token from background.js via message
|
|
12
|
-
// 3. Sign in local Firebase with the ID token using signInWithCustomToken workaround
|
|
5
|
+
// - Background.js is the SOURCE OF TRUTH for authentication
|
|
6
|
+
// - On context load, contexts wait for WM auth to settle, then ask background if in sync
|
|
7
|
+
// - If out of sync, background provides a fresh custom token (fetched from server)
|
|
8
|
+
// - No BEM-specific storage - Web Manager handles auth state internally
|
|
13
9
|
|
|
14
10
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @param {Object} context - The manager instance
|
|
18
|
-
* @returns {Promise<string|null>} The ID token or null if not signed in
|
|
11
|
+
* Sync auth state with background.js on context load
|
|
12
|
+
* Waits for WM auth to settle, then asks background if in sync
|
|
13
|
+
* @param {Object} context - The manager instance (must have extension, webManager, logger)
|
|
19
14
|
*/
|
|
20
|
-
export async function
|
|
21
|
-
const { extension, logger } = context;
|
|
15
|
+
export async function syncWithBackground(context) {
|
|
16
|
+
const { extension, webManager, logger } = context;
|
|
22
17
|
|
|
23
18
|
try {
|
|
24
|
-
|
|
19
|
+
// Wait for WM auth state to settle FIRST (prevents race conditions)
|
|
20
|
+
const localState = await new Promise(resolve => {
|
|
21
|
+
webManager.auth().listen({ once: true }, resolve);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const localUid = localState.user?.uid || null;
|
|
25
|
+
logger.log('[AUTH-SYNC] Local auth state settled, UID:', localUid);
|
|
25
26
|
|
|
26
|
-
//
|
|
27
|
+
// Ask background for auth state comparison
|
|
27
28
|
const response = await new Promise((resolve) => {
|
|
28
|
-
extension.runtime.sendMessage(
|
|
29
|
+
extension.runtime.sendMessage(
|
|
30
|
+
{ command: 'bxm:syncAuth', contextUid: localUid },
|
|
31
|
+
(res) => {
|
|
32
|
+
if (extension.runtime.lastError) {
|
|
33
|
+
logger.log('[AUTH-SYNC] Background not ready:', extension.runtime.lastError.message);
|
|
34
|
+
resolve({ needsSync: false });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
resolve(res || { needsSync: false });
|
|
38
|
+
}
|
|
39
|
+
);
|
|
29
40
|
});
|
|
30
41
|
|
|
31
|
-
//
|
|
32
|
-
if (!response
|
|
33
|
-
logger.log('[AUTH-SYNC]
|
|
34
|
-
return
|
|
42
|
+
// Already in sync
|
|
43
|
+
if (!response.needsSync) {
|
|
44
|
+
logger.log('[AUTH-SYNC] Already in sync with background');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Need to sign out (background is signed out, context is signed in)
|
|
49
|
+
if (response.signOut) {
|
|
50
|
+
logger.log('[AUTH-SYNC] Background signed out, signing out context...');
|
|
51
|
+
await webManager.auth().signOut();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Need to sign in with token
|
|
56
|
+
if (response.customToken) {
|
|
57
|
+
logger.log('[AUTH-SYNC] Syncing with background...', response.user?.email);
|
|
58
|
+
await webManager.auth().signInWithCustomToken(response.customToken);
|
|
59
|
+
logger.log('[AUTH-SYNC] Synced successfully');
|
|
35
60
|
}
|
|
36
61
|
|
|
37
|
-
logger.log('[AUTH-SYNC] Got fresh ID token from background');
|
|
38
|
-
return response.idToken;
|
|
39
62
|
} catch (error) {
|
|
40
|
-
logger.error('[AUTH-SYNC] Error
|
|
41
|
-
return null;
|
|
63
|
+
logger.error('[AUTH-SYNC] Error syncing with background:', error.message);
|
|
42
64
|
}
|
|
43
65
|
}
|
|
44
66
|
|
|
45
67
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* @param {Object} context - The manager instance
|
|
68
|
+
* Set up listener for auth token broadcasts from background.js
|
|
69
|
+
* Handles both sign-in broadcasts and sign-out broadcasts
|
|
70
|
+
* @param {Object} context - The manager instance (must have extension, webManager, logger)
|
|
49
71
|
*/
|
|
50
|
-
|
|
51
|
-
const
|
|
72
|
+
export function setupAuthBroadcastListener(context) {
|
|
73
|
+
const { webManager, logger } = context;
|
|
74
|
+
|
|
75
|
+
// Listen for messages from service worker (background.js)
|
|
76
|
+
navigator.serviceWorker?.addEventListener('message', async (event) => {
|
|
77
|
+
const { command, token } = event.data || {};
|
|
78
|
+
|
|
79
|
+
// Handle sign-in broadcast
|
|
80
|
+
if (command === 'bxm:signInWithToken' && token) {
|
|
81
|
+
logger.log('[AUTH-BROADCAST] Received sign-in broadcast');
|
|
82
|
+
try {
|
|
83
|
+
await webManager.auth().signInWithCustomToken(token);
|
|
84
|
+
logger.log('[AUTH-BROADCAST] Signed in via broadcast');
|
|
85
|
+
} catch (error) {
|
|
86
|
+
logger.error('[AUTH-BROADCAST] Error signing in:', error.message);
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
52
90
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
91
|
+
// Handle sign-out broadcast
|
|
92
|
+
if (command === 'bxm:signOut') {
|
|
93
|
+
// Skip if already signed out (prevents loops)
|
|
94
|
+
if (!webManager.auth().getUser()) {
|
|
95
|
+
logger.log('[AUTH-BROADCAST] Already signed out, ignoring broadcast');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
logger.log('[AUTH-BROADCAST] Received sign-out broadcast');
|
|
99
|
+
try {
|
|
100
|
+
await webManager.auth().signOut();
|
|
101
|
+
logger.log('[AUTH-BROADCAST] Signed out via broadcast');
|
|
102
|
+
} catch (error) {
|
|
103
|
+
logger.error('[AUTH-BROADCAST] Error signing out:', error.message);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
logger.log('[AUTH-BROADCAST] Broadcast listener set up');
|
|
58
109
|
}
|
|
59
110
|
|
|
60
111
|
/**
|
|
61
|
-
* Set up
|
|
62
|
-
* Listens for auth state changes from background.js and syncs Firebase auth
|
|
112
|
+
* Set up listener to notify background when user signs out from this context
|
|
63
113
|
* @param {Object} context - The manager instance (must have extension, webManager, logger)
|
|
64
114
|
*/
|
|
65
|
-
export function
|
|
115
|
+
export function setupSignOutListener(context) {
|
|
66
116
|
const { extension, webManager, logger } = context;
|
|
67
117
|
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
const authState = result['bxm:authState'];
|
|
71
|
-
|
|
72
|
-
if (authState?.user) {
|
|
73
|
-
logger.log('[AUTH-SYNC] Found existing auth state on load:', authState.user?.email);
|
|
74
|
-
// Request fresh ID token from background for any API calls
|
|
75
|
-
syncAuthFromBackground(context);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
118
|
+
// Track previous user to detect sign-out
|
|
119
|
+
let previousUid = null;
|
|
78
120
|
|
|
79
|
-
// Listen for WM auth state changes and sync to storage
|
|
80
|
-
// When user signs out via WM, clear storage so background.js knows
|
|
81
121
|
webManager.auth().listen((state) => {
|
|
82
|
-
|
|
83
|
-
// User signed out - clear storage so all contexts sync
|
|
84
|
-
logger.log('[AUTH-SYNC] WM auth signed out, clearing storage...');
|
|
85
|
-
extension.storage.local.remove('bxm:authState');
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Listen for storage changes from background.js
|
|
90
|
-
extension.storage.onChanged.addListener((changes) => {
|
|
91
|
-
// Check for auth state change
|
|
92
|
-
const authChange = changes['bxm:authState'];
|
|
93
|
-
if (!authChange) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Log
|
|
98
|
-
logger.log('[AUTH-SYNC] Auth state changed in storage:', authChange);
|
|
99
|
-
|
|
100
|
-
// Get the new auth state
|
|
101
|
-
const newAuthState = authChange.newValue;
|
|
122
|
+
const currentUid = state.user?.uid || null;
|
|
102
123
|
|
|
103
|
-
//
|
|
104
|
-
if (!
|
|
105
|
-
logger.log('[AUTH-SYNC]
|
|
106
|
-
|
|
107
|
-
webManager.auth().signOut();
|
|
108
|
-
return;
|
|
124
|
+
// Detect sign-out (had user, now don't)
|
|
125
|
+
if (previousUid && !currentUid) {
|
|
126
|
+
logger.log('[AUTH-SYNC] Detected sign-out, notifying background...');
|
|
127
|
+
extension.runtime.sendMessage({ command: 'bxm:signOut' });
|
|
109
128
|
}
|
|
110
129
|
|
|
111
|
-
|
|
112
|
-
if (newAuthState?.user) {
|
|
113
|
-
syncAuthFromBackground(context);
|
|
114
|
-
}
|
|
130
|
+
previousUid = currentUid;
|
|
115
131
|
});
|
|
116
132
|
|
|
117
|
-
|
|
118
|
-
logger.log('Auth storage listener set up');
|
|
133
|
+
logger.log('[AUTH-SYNC] Sign-out listener set up');
|
|
119
134
|
}
|
|
120
135
|
|
|
121
136
|
/**
|
|
@@ -186,22 +201,8 @@ export function setupAuthEventListeners(context) {
|
|
|
186
201
|
openAuthPage(context);
|
|
187
202
|
});
|
|
188
203
|
|
|
189
|
-
// Account button (.auth-account-btn) - opens account page on website
|
|
190
|
-
document.addEventListener('click', (event) => {
|
|
191
|
-
const $accountBtn = event.target.closest('.auth-account-btn');
|
|
192
|
-
if (!$accountBtn) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
event.preventDefault();
|
|
197
|
-
event.stopPropagation();
|
|
198
|
-
|
|
199
|
-
openAuthPage(context, { path: '/account' });
|
|
200
|
-
});
|
|
201
|
-
|
|
202
204
|
// Note: .auth-signout-btn is handled by web-manager's auth module
|
|
203
|
-
//
|
|
204
|
-
// If background hasn't initialized Firebase yet, stale storage is cleared on next auth attempt
|
|
205
|
+
// setupSignOutListener detects sign-out and notifies background
|
|
205
206
|
|
|
206
207
|
// Log
|
|
207
208
|
context.logger.log('Auth event listeners set up');
|
package/dist/options.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Manager as WebManager } from 'web-manager';
|
|
3
3
|
import extension from './lib/extension.js';
|
|
4
4
|
import LoggerLite from './lib/logger-lite.js';
|
|
5
|
-
import {
|
|
5
|
+
import { syncWithBackground, setupAuthBroadcastListener, setupSignOutListener, setupAuthEventListeners, openAuthPage as openAuthPageHelper } from './lib/auth-helpers.js';
|
|
6
6
|
|
|
7
7
|
// Import theme (exposes Bootstrap to window.bootstrap)
|
|
8
8
|
import '__theme__/_theme.js';
|
|
@@ -35,8 +35,14 @@ class Manager {
|
|
|
35
35
|
this.logger.log('Auth state changed:', state);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
|
|
38
|
+
// Sync auth with background.js (waits for WM auth to settle first)
|
|
39
|
+
await syncWithBackground(this);
|
|
40
|
+
|
|
41
|
+
// Set up broadcast listener for sign-in/sign-out from background
|
|
42
|
+
setupAuthBroadcastListener(this);
|
|
43
|
+
|
|
44
|
+
// Set up sign-out listener to notify background when user signs out
|
|
45
|
+
setupSignOutListener(this);
|
|
40
46
|
|
|
41
47
|
// Set up auth event listeners (sign in, account buttons)
|
|
42
48
|
setupAuthEventListeners(this);
|
package/dist/page.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Manager as WebManager } from 'web-manager';
|
|
3
3
|
import extension from './lib/extension.js';
|
|
4
4
|
import LoggerLite from './lib/logger-lite.js';
|
|
5
|
-
import {
|
|
5
|
+
import { syncWithBackground, setupAuthBroadcastListener, setupSignOutListener, setupAuthEventListeners, openAuthPage as openAuthPageHelper } from './lib/auth-helpers.js';
|
|
6
6
|
|
|
7
7
|
// Import theme (exposes Bootstrap to window.bootstrap)
|
|
8
8
|
import '__theme__/_theme.js';
|
|
@@ -35,8 +35,14 @@ class Manager {
|
|
|
35
35
|
this.logger.log('Auth state changed:', state);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
|
|
38
|
+
// Sync auth with background.js (waits for WM auth to settle first)
|
|
39
|
+
await syncWithBackground(this);
|
|
40
|
+
|
|
41
|
+
// Set up broadcast listener for sign-in/sign-out from background
|
|
42
|
+
setupAuthBroadcastListener(this);
|
|
43
|
+
|
|
44
|
+
// Set up sign-out listener to notify background when user signs out
|
|
45
|
+
setupSignOutListener(this);
|
|
40
46
|
|
|
41
47
|
// Set up auth event listeners (sign in, account buttons)
|
|
42
48
|
setupAuthEventListeners(this);
|
package/dist/popup.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Manager as WebManager } from 'web-manager';
|
|
3
3
|
import extension from './lib/extension.js';
|
|
4
4
|
import LoggerLite from './lib/logger-lite.js';
|
|
5
|
-
import {
|
|
5
|
+
import { syncWithBackground, setupAuthBroadcastListener, setupSignOutListener, setupAuthEventListeners, openAuthPage as openAuthPageHelper } from './lib/auth-helpers.js';
|
|
6
6
|
|
|
7
7
|
// Import theme (exposes Bootstrap to window.bootstrap)
|
|
8
8
|
import '__theme__/_theme.js';
|
|
@@ -35,8 +35,14 @@ class Manager {
|
|
|
35
35
|
this.logger.log('Auth state changed:', state);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
|
|
38
|
+
// Sync auth with background.js (waits for WM auth to settle first)
|
|
39
|
+
await syncWithBackground(this);
|
|
40
|
+
|
|
41
|
+
// Set up broadcast listener for sign-in/sign-out from background
|
|
42
|
+
setupAuthBroadcastListener(this);
|
|
43
|
+
|
|
44
|
+
// Set up sign-out listener to notify background when user signs out
|
|
45
|
+
setupSignOutListener(this);
|
|
40
46
|
|
|
41
47
|
// Set up auth event listeners (sign in, account buttons)
|
|
42
48
|
setupAuthEventListeners(this);
|
package/dist/sidepanel.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Manager as WebManager } from 'web-manager';
|
|
3
3
|
import extension from './lib/extension.js';
|
|
4
4
|
import LoggerLite from './lib/logger-lite.js';
|
|
5
|
-
import {
|
|
5
|
+
import { syncWithBackground, setupAuthBroadcastListener, setupSignOutListener, setupAuthEventListeners, openAuthPage as openAuthPageHelper } from './lib/auth-helpers.js';
|
|
6
6
|
|
|
7
7
|
// Import theme (exposes Bootstrap to window.bootstrap)
|
|
8
8
|
import '__theme__/_theme.js';
|
|
@@ -35,8 +35,14 @@ class Manager {
|
|
|
35
35
|
this.logger.log('Auth state changed:', state);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
|
|
38
|
+
// Sync auth with background.js (waits for WM auth to settle first)
|
|
39
|
+
await syncWithBackground(this);
|
|
40
|
+
|
|
41
|
+
// Set up broadcast listener for sign-in/sign-out from background
|
|
42
|
+
setupAuthBroadcastListener(this);
|
|
43
|
+
|
|
44
|
+
// Set up sign-out listener to notify background when user signs out
|
|
45
|
+
setupSignOutListener(this);
|
|
40
46
|
|
|
41
47
|
// Set up auth event listeners (sign in, account buttons)
|
|
42
48
|
setupAuthEventListeners(this);
|