web-manager 4.0.0 → 4.0.1
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 +4 -0
- package/_legacy/service-worker copy.js +347 -0
- package/dist/index.js +1 -1
- package/dist/modules/auth.js +64 -15
- package/dist/modules/bindings.js +2 -2
- package/dist/modules/dom.js +8 -14
- package/dist/modules/service-worker.js +39 -31
- package/package.json +4 -5
package/CHANGELOG.md
CHANGED
@@ -15,6 +15,10 @@ 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
|
+
## [4.0.0] - 2025-09-11
|
19
|
+
### BREAKING
|
20
|
+
- Updated to ITW 3.0 standard.
|
21
|
+
|
18
22
|
## [3.2.74] - 2025-07-17
|
19
23
|
### Added
|
20
24
|
- Now looks for `build.json` in the `/@output/build/` directory to ensure it works with Vite's output structure.
|
@@ -0,0 +1,347 @@
|
|
1
|
+
class ServiceWorker {
|
2
|
+
constructor(manager) {
|
3
|
+
this.manager = manager;
|
4
|
+
this._registration = null;
|
5
|
+
this._updateCallbacks = [];
|
6
|
+
this._messageHandlers = new Map();
|
7
|
+
}
|
8
|
+
|
9
|
+
// Check if service workers are supported
|
10
|
+
isSupported() {
|
11
|
+
return 'serviceWorker' in navigator;
|
12
|
+
}
|
13
|
+
|
14
|
+
// Register service worker
|
15
|
+
async register(options = {}) {
|
16
|
+
try {
|
17
|
+
if (!this.isSupported()) {
|
18
|
+
console.warn('Service Workers are not supported');
|
19
|
+
return null;
|
20
|
+
}
|
21
|
+
|
22
|
+
const swPath = options.path || this.manager.config.serviceWorker?.config?.path || '/service-worker.js';
|
23
|
+
const scope = options.scope || '/';
|
24
|
+
|
25
|
+
// Build config object to pass to service worker
|
26
|
+
const config = {
|
27
|
+
app: this.manager.config.brand?.id,
|
28
|
+
environment: this.manager.config.environment,
|
29
|
+
buildTime: this.manager.config.buildTime,
|
30
|
+
firebase: this.manager.config.firebase?.app?.config || null
|
31
|
+
};
|
32
|
+
|
33
|
+
// Get service worker URL with just cache breaker
|
34
|
+
const cacheBreaker = config.buildTime || Date.now();
|
35
|
+
const swUrl = `${swPath}?cb=${cacheBreaker}`;
|
36
|
+
|
37
|
+
// Get existing registrations
|
38
|
+
const registrations = await navigator.serviceWorker.getRegistrations();
|
39
|
+
|
40
|
+
// Check if service worker is already registered for this scope
|
41
|
+
let registration = registrations.find(reg =>
|
42
|
+
reg.scope === new URL(scope, window.location.href).href
|
43
|
+
);
|
44
|
+
|
45
|
+
// Always register/re-register to ensure we have the correct URL with config
|
46
|
+
console.log('----WM SW 1');
|
47
|
+
|
48
|
+
if (registration) {
|
49
|
+
console.log('----WM SW 2');
|
50
|
+
console.log('Unregistering existing service worker to update config');
|
51
|
+
await registration.unregister();
|
52
|
+
// Wait a bit for unregistration to complete
|
53
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
54
|
+
}
|
55
|
+
console.log('----WM SW 3');
|
56
|
+
|
57
|
+
console.log('Registering service worker with cache breaker');
|
58
|
+
registration = await navigator.serviceWorker.register(swUrl, {
|
59
|
+
scope,
|
60
|
+
updateViaCache: options.updateViaCache || 'imports'
|
61
|
+
});
|
62
|
+
|
63
|
+
// Wait for the service worker to be ready
|
64
|
+
await navigator.serviceWorker.ready;
|
65
|
+
|
66
|
+
// Send the full config via postMessage after registration
|
67
|
+
console.log('----WM SW 4');
|
68
|
+
if (registration.active) {
|
69
|
+
console.log('----WM SW 5');
|
70
|
+
try {
|
71
|
+
this.postMessage({
|
72
|
+
command: 'update-config',
|
73
|
+
payload: config
|
74
|
+
});
|
75
|
+
} catch (error) {
|
76
|
+
console.warn('Could not send config to service worker:', error);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
this._registration = registration;
|
81
|
+
this.manager.state.serviceWorker = registration;
|
82
|
+
console.log('----WM SW 6');
|
83
|
+
|
84
|
+
// Set up update handlers
|
85
|
+
this._setupUpdateHandlers(registration);
|
86
|
+
console.log('----WM SW 7');
|
87
|
+
|
88
|
+
// Check for updates
|
89
|
+
if (options.checkForUpdate !== false) {
|
90
|
+
registration.update();
|
91
|
+
}
|
92
|
+
console.log('----WM SW 8');
|
93
|
+
|
94
|
+
// Set up message channel
|
95
|
+
if (registration.active) {
|
96
|
+
this._setupMessageChannel();
|
97
|
+
}
|
98
|
+
console.log('----WM SW 9');
|
99
|
+
|
100
|
+
return registration;
|
101
|
+
} catch (error) {
|
102
|
+
console.error('Service Worker registration failed:', error);
|
103
|
+
throw error;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
// Unregister service worker
|
108
|
+
async unregister() {
|
109
|
+
try {
|
110
|
+
if (!this._registration) {
|
111
|
+
const registrations = await navigator.serviceWorker.getRegistrations();
|
112
|
+
for (const registration of registrations) {
|
113
|
+
await registration.unregister();
|
114
|
+
}
|
115
|
+
} else {
|
116
|
+
await this._registration.unregister();
|
117
|
+
}
|
118
|
+
|
119
|
+
this._registration = null;
|
120
|
+
this.manager.state.serviceWorker = null;
|
121
|
+
|
122
|
+
return true;
|
123
|
+
} catch (error) {
|
124
|
+
console.error('Service Worker unregistration failed:', error);
|
125
|
+
return false;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
// Get current registration
|
130
|
+
getRegistration() {
|
131
|
+
return this._registration;
|
132
|
+
}
|
133
|
+
|
134
|
+
// Check for updates
|
135
|
+
async update() {
|
136
|
+
try {
|
137
|
+
if (!this._registration) {
|
138
|
+
throw new Error('No service worker registered');
|
139
|
+
}
|
140
|
+
|
141
|
+
await this._registration.update();
|
142
|
+
return true;
|
143
|
+
} catch (error) {
|
144
|
+
console.error('Service Worker update failed:', error);
|
145
|
+
return false;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
// Post message to service worker
|
150
|
+
postMessage(message, options = {}) {
|
151
|
+
return new Promise((resolve, reject) => {
|
152
|
+
if (!this.isSupported()) {
|
153
|
+
return reject(new Error('Service Workers not supported'));
|
154
|
+
}
|
155
|
+
|
156
|
+
const controller = this._registration?.active || navigator.serviceWorker.controller;
|
157
|
+
|
158
|
+
if (!controller) {
|
159
|
+
return reject(new Error('No active service worker'));
|
160
|
+
}
|
161
|
+
|
162
|
+
const messageChannel = new MessageChannel();
|
163
|
+
const timeout = options.timeout || 5000;
|
164
|
+
let timeoutId;
|
165
|
+
|
166
|
+
// Set up timeout
|
167
|
+
if (timeout > 0) {
|
168
|
+
timeoutId = setTimeout(() => {
|
169
|
+
messageChannel.port1.close();
|
170
|
+
reject(new Error('Service worker message timeout'));
|
171
|
+
}, timeout);
|
172
|
+
}
|
173
|
+
|
174
|
+
// Listen for response
|
175
|
+
messageChannel.port1.onmessage = (event) => {
|
176
|
+
clearTimeout(timeoutId);
|
177
|
+
|
178
|
+
if (event.data.error) {
|
179
|
+
reject(new Error(event.data.error));
|
180
|
+
} else {
|
181
|
+
resolve(event.data);
|
182
|
+
}
|
183
|
+
};
|
184
|
+
|
185
|
+
// Send message
|
186
|
+
controller.postMessage(message, [messageChannel.port2]);
|
187
|
+
});
|
188
|
+
}
|
189
|
+
|
190
|
+
// Listen for messages from service worker
|
191
|
+
onMessage(type, handler) {
|
192
|
+
if (!this.isSupported()) {
|
193
|
+
return () => {};
|
194
|
+
}
|
195
|
+
|
196
|
+
// Store handler
|
197
|
+
if (!this._messageHandlers.has(type)) {
|
198
|
+
this._messageHandlers.set(type, new Set());
|
199
|
+
}
|
200
|
+
this._messageHandlers.get(type).add(handler);
|
201
|
+
|
202
|
+
// Set up global message listener if not already done
|
203
|
+
if (this._messageHandlers.size === 1) {
|
204
|
+
navigator.serviceWorker.addEventListener('message', this._handleMessage.bind(this));
|
205
|
+
}
|
206
|
+
|
207
|
+
// Return unsubscribe function
|
208
|
+
return () => {
|
209
|
+
const handlers = this._messageHandlers.get(type);
|
210
|
+
if (handlers) {
|
211
|
+
handlers.delete(handler);
|
212
|
+
if (handlers.size === 0) {
|
213
|
+
this._messageHandlers.delete(type);
|
214
|
+
}
|
215
|
+
}
|
216
|
+
};
|
217
|
+
}
|
218
|
+
|
219
|
+
// Skip waiting and activate new service worker
|
220
|
+
async skipWaiting() {
|
221
|
+
try {
|
222
|
+
if (!this._registration?.waiting) {
|
223
|
+
throw new Error('No service worker waiting');
|
224
|
+
}
|
225
|
+
|
226
|
+
// Post message to skip waiting
|
227
|
+
await this.postMessage({ action: 'skipWaiting' });
|
228
|
+
|
229
|
+
// Reload page after activation
|
230
|
+
let refreshing = false;
|
231
|
+
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
232
|
+
if (!refreshing) {
|
233
|
+
refreshing = true;
|
234
|
+
window.location.reload();
|
235
|
+
}
|
236
|
+
});
|
237
|
+
|
238
|
+
return true;
|
239
|
+
} catch (error) {
|
240
|
+
console.error('Skip waiting failed:', error);
|
241
|
+
return false;
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
245
|
+
// Listen for update events
|
246
|
+
onUpdateFound(callback) {
|
247
|
+
this._updateCallbacks.push(callback);
|
248
|
+
|
249
|
+
return () => {
|
250
|
+
const index = this._updateCallbacks.indexOf(callback);
|
251
|
+
if (index > -1) {
|
252
|
+
this._updateCallbacks.splice(index, 1);
|
253
|
+
}
|
254
|
+
};
|
255
|
+
}
|
256
|
+
|
257
|
+
// Get service worker state
|
258
|
+
getState() {
|
259
|
+
if (!this._registration) {
|
260
|
+
return 'none';
|
261
|
+
}
|
262
|
+
|
263
|
+
if (this._registration.installing) {
|
264
|
+
return 'installing';
|
265
|
+
} else if (this._registration.waiting) {
|
266
|
+
return 'waiting';
|
267
|
+
} else if (this._registration.active) {
|
268
|
+
return 'active';
|
269
|
+
}
|
270
|
+
|
271
|
+
return 'unknown';
|
272
|
+
}
|
273
|
+
|
274
|
+
// Private: Set up update handlers
|
275
|
+
_setupUpdateHandlers(registration) {
|
276
|
+
// Listen for updates
|
277
|
+
registration.addEventListener('updatefound', () => {
|
278
|
+
const newWorker = registration.installing;
|
279
|
+
|
280
|
+
if (!newWorker) return;
|
281
|
+
|
282
|
+
newWorker.addEventListener('statechange', () => {
|
283
|
+
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
|
284
|
+
// New service worker available
|
285
|
+
this._notifyUpdateCallbacks({
|
286
|
+
type: 'update-available',
|
287
|
+
worker: newWorker
|
288
|
+
});
|
289
|
+
|
290
|
+
// Automatically skip waiting and activate new worker
|
291
|
+
if (this.manager.config.serviceWorker?.autoUpdate !== false) {
|
292
|
+
this.skipWaiting();
|
293
|
+
}
|
294
|
+
}
|
295
|
+
});
|
296
|
+
});
|
297
|
+
|
298
|
+
// Listen for controller changes
|
299
|
+
let refreshing = false;
|
300
|
+
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
301
|
+
if (!refreshing) {
|
302
|
+
this._notifyUpdateCallbacks({
|
303
|
+
type: 'controller-change'
|
304
|
+
});
|
305
|
+
}
|
306
|
+
});
|
307
|
+
}
|
308
|
+
|
309
|
+
// Private: Notify update callbacks
|
310
|
+
_notifyUpdateCallbacks(event) {
|
311
|
+
this._updateCallbacks.forEach(callback => {
|
312
|
+
try {
|
313
|
+
callback(event);
|
314
|
+
} catch (error) {
|
315
|
+
console.error('Update callback error:', error);
|
316
|
+
}
|
317
|
+
});
|
318
|
+
}
|
319
|
+
|
320
|
+
// Private: Handle incoming messages
|
321
|
+
_handleMessage(event) {
|
322
|
+
const { type, ...data } = event.data || {};
|
323
|
+
|
324
|
+
if (!type) return;
|
325
|
+
|
326
|
+
const handlers = this._messageHandlers.get(type);
|
327
|
+
if (handlers) {
|
328
|
+
handlers.forEach(handler => {
|
329
|
+
try {
|
330
|
+
handler(data, event);
|
331
|
+
} catch (error) {
|
332
|
+
console.error('Message handler error:', error);
|
333
|
+
}
|
334
|
+
});
|
335
|
+
}
|
336
|
+
}
|
337
|
+
|
338
|
+
// Private: Set up message channel
|
339
|
+
_setupMessageChannel() {
|
340
|
+
// This ensures we can communicate with the service worker
|
341
|
+
navigator.serviceWorker.ready.then(() => {
|
342
|
+
console.log('Service Worker ready for messaging');
|
343
|
+
});
|
344
|
+
}
|
345
|
+
}
|
346
|
+
|
347
|
+
export default ServiceWorker;
|
package/dist/index.js
CHANGED
package/dist/modules/auth.js
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
import resolveAccount from 'resolve-account';
|
2
|
+
|
1
3
|
class Auth {
|
2
4
|
constructor(manager) {
|
3
5
|
this.manager = manager;
|
4
6
|
this._authStateCallbacks = [];
|
5
7
|
this._readyCallbacks = [];
|
8
|
+
this._hasUpdatedBindings = false;
|
6
9
|
}
|
7
10
|
|
8
11
|
// Check if user is authenticated
|
@@ -67,8 +70,14 @@ class Auth {
|
|
67
70
|
|
68
71
|
// If Firebase is not enabled, call callback immediately with null
|
69
72
|
if (!this.manager.config.firebase?.app?.enabled) {
|
70
|
-
callback
|
71
|
-
|
73
|
+
// Call callback with null user and empty account
|
74
|
+
callback({
|
75
|
+
user: null,
|
76
|
+
account: resolveAccount({}, {})
|
77
|
+
});
|
78
|
+
|
79
|
+
// Return empty unsubscribe function
|
80
|
+
return () => {};
|
72
81
|
}
|
73
82
|
|
74
83
|
// Function to get current state and call callback
|
@@ -77,18 +86,34 @@ class Auth {
|
|
77
86
|
const state = { user: this.getUser() };
|
78
87
|
|
79
88
|
// Then, add account data if requested and user exists
|
80
|
-
if (options.account && user && this.manager.firebaseFirestore) {
|
89
|
+
// if (options.account && user && this.manager.firebaseFirestore) {
|
90
|
+
// Fetch account if the user is logged in AND Firestore is available
|
91
|
+
if (user && this.manager.firebaseFirestore) {
|
81
92
|
try {
|
82
93
|
state.account = await this._getAccountData(user.uid);
|
83
94
|
} catch (error) {
|
84
|
-
|
95
|
+
// Pass error to Sentry
|
96
|
+
this.manager.sentry().captureException(new Error('Failed to get account data', { cause: error }));
|
85
97
|
}
|
86
|
-
} else {
|
87
|
-
state.account = null;
|
88
98
|
}
|
89
99
|
|
90
|
-
//
|
91
|
-
|
100
|
+
// Always ensure account is at least a default resolved object
|
101
|
+
state.account = state.account || resolveAccount({}, { uid: user?.uid });
|
102
|
+
|
103
|
+
// Update bindings with auth data (only once across all callbacks)
|
104
|
+
// Now ONLY the first listener will update bindings until the next auth state change
|
105
|
+
if (!this._hasUpdatedBindings) {
|
106
|
+
// Run update
|
107
|
+
this.manager.bindings().update(state);
|
108
|
+
|
109
|
+
// Save to storage
|
110
|
+
const storage = this.manager.storage();
|
111
|
+
storage.set('user.auth', state.user || null);
|
112
|
+
storage.set('user.account', state.account || {});
|
113
|
+
|
114
|
+
// Mark that we've updated bindings
|
115
|
+
this._hasUpdatedBindings = true;
|
116
|
+
}
|
92
117
|
|
93
118
|
// Call the provided callback with the state
|
94
119
|
callback(state);
|
@@ -97,15 +122,27 @@ class Auth {
|
|
97
122
|
let hasCalledback = false;
|
98
123
|
|
99
124
|
// Set up listener for auth state changes
|
100
|
-
|
125
|
+
const unsubscribe = this.onAuthStateChanged((user) => {
|
126
|
+
// If once option is set, unsubscribe
|
127
|
+
// We have to do this here because unsubscribe is only available after this call
|
128
|
+
if (options.once && unsubscribe) {
|
129
|
+
unsubscribe();
|
130
|
+
return;
|
131
|
+
}
|
132
|
+
|
101
133
|
// Wait for settled state before first callback
|
102
134
|
if (!hasCalledback && !this.manager._firebaseAuthInitialized) {
|
103
135
|
return; // Auth state not yet determined
|
104
136
|
}
|
105
137
|
|
138
|
+
// Mark that we've called back at least once
|
106
139
|
hasCalledback = true;
|
140
|
+
|
141
|
+
// Get current state and call the callback
|
107
142
|
getStateAndCallback(user);
|
108
143
|
});
|
144
|
+
|
145
|
+
return unsubscribe;
|
109
146
|
}
|
110
147
|
|
111
148
|
// Listen for auth state changes
|
@@ -128,11 +165,8 @@ class Auth {
|
|
128
165
|
|
129
166
|
// Internal method to handle auth state changes
|
130
167
|
_handleAuthStateChange(user) {
|
131
|
-
//
|
132
|
-
this.
|
133
|
-
user: this.getUser(),
|
134
|
-
account: null
|
135
|
-
});
|
168
|
+
// Reset bindings flag for new auth state
|
169
|
+
this._hasUpdatedBindings = false;
|
136
170
|
|
137
171
|
// Call all registered callbacks
|
138
172
|
this._authStateCallbacks.forEach(callback => {
|
@@ -173,6 +207,22 @@ class Auth {
|
|
173
207
|
}
|
174
208
|
}
|
175
209
|
|
210
|
+
// Sign in with email and password
|
211
|
+
async signInWithEmailAndPassword(email, password) {
|
212
|
+
try {
|
213
|
+
if (!this.manager.firebaseAuth) {
|
214
|
+
throw new Error('Firebase Auth is not initialized');
|
215
|
+
}
|
216
|
+
|
217
|
+
const { signInWithEmailAndPassword } = await import('firebase/auth');
|
218
|
+
const userCredential = await signInWithEmailAndPassword(this.manager.firebaseAuth, email, password);
|
219
|
+
return userCredential.user;
|
220
|
+
} catch (error) {
|
221
|
+
console.error('Sign in with email and password error:', error);
|
222
|
+
throw error;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
176
226
|
// Sign out the current user
|
177
227
|
async signOut() {
|
178
228
|
try {
|
@@ -193,7 +243,6 @@ class Auth {
|
|
193
243
|
}
|
194
244
|
|
195
245
|
const { doc, getDoc } = await import('firebase/firestore');
|
196
|
-
const resolveAccount = (await import('resolve-account')).default;
|
197
246
|
|
198
247
|
const accountDoc = doc(this.manager.firebaseFirestore, 'users', uid);
|
199
248
|
const snapshot = await getDoc(accountDoc);
|
package/dist/modules/bindings.js
CHANGED
@@ -81,14 +81,14 @@ class Bindings {
|
|
81
81
|
const attrName = attrParts[0];
|
82
82
|
const attrExpression = attrParts.slice(1).join(' ');
|
83
83
|
const attrValue = this._resolvePath(context, attrExpression) || '';
|
84
|
-
|
84
|
+
|
85
85
|
if (attrValue) {
|
86
86
|
element.setAttribute(attrName, attrValue);
|
87
87
|
} else {
|
88
88
|
element.removeAttribute(attrName);
|
89
89
|
}
|
90
90
|
break;
|
91
|
-
|
91
|
+
|
92
92
|
case '@text':
|
93
93
|
default:
|
94
94
|
// Set text content (default behavior)
|
package/dist/modules/dom.js
CHANGED
@@ -12,21 +12,16 @@ export function loadScript(options) {
|
|
12
12
|
defer = false,
|
13
13
|
crossorigin = false,
|
14
14
|
integrity = null,
|
15
|
-
attributes =
|
15
|
+
attributes = {},
|
16
16
|
timeout = 60000,
|
17
|
-
retries = 0
|
17
|
+
retries = 0,
|
18
|
+
parent = null
|
18
19
|
} = options;
|
19
20
|
|
20
21
|
if (!src) {
|
21
22
|
return reject(new Error('Script source is required'));
|
22
23
|
}
|
23
24
|
|
24
|
-
// Check if script already exists
|
25
|
-
const existingScript = document.querySelector(`script[src="${src}"]`);
|
26
|
-
if (existingScript) {
|
27
|
-
return resolve({ script: existingScript, cached: true });
|
28
|
-
}
|
29
|
-
|
30
25
|
let timeoutId;
|
31
26
|
let retryCount = 0;
|
32
27
|
|
@@ -45,10 +40,8 @@ export function loadScript(options) {
|
|
45
40
|
}
|
46
41
|
|
47
42
|
// Add custom attributes
|
48
|
-
attributes.forEach(
|
49
|
-
|
50
|
-
script.setAttribute(attr.name, attr.value);
|
51
|
-
}
|
43
|
+
Object.keys(attributes).forEach(name => {
|
44
|
+
script.setAttribute(name, attributes[name]);
|
52
45
|
});
|
53
46
|
|
54
47
|
// Set up timeout
|
@@ -68,11 +61,12 @@ export function loadScript(options) {
|
|
68
61
|
script.onerror = (error) => {
|
69
62
|
clearTimeout(timeoutId);
|
70
63
|
script.remove();
|
71
|
-
handleError(new Error(`Failed to load script
|
64
|
+
handleError(new Error(`Failed to load script ${src}`, { cause: error }));
|
72
65
|
};
|
73
66
|
|
74
67
|
// Append to document
|
75
|
-
|
68
|
+
const $targetParent = parent || document.head || document.documentElement;
|
69
|
+
$targetParent.appendChild(script);
|
76
70
|
}
|
77
71
|
|
78
72
|
function handleError(error) {
|
@@ -11,6 +11,22 @@ class ServiceWorker {
|
|
11
11
|
return 'serviceWorker' in navigator;
|
12
12
|
}
|
13
13
|
|
14
|
+
// Return promise that resolves when service worker is ready
|
15
|
+
async ready() {
|
16
|
+
if (!this.isSupported()) {
|
17
|
+
throw new Error('Service Workers not supported');
|
18
|
+
}
|
19
|
+
|
20
|
+
// If already registered and active
|
21
|
+
if (this._registration?.active) {
|
22
|
+
return this._registration;
|
23
|
+
}
|
24
|
+
|
25
|
+
// Wait for service worker to be ready
|
26
|
+
const registration = await navigator.serviceWorker.ready;
|
27
|
+
return registration;
|
28
|
+
}
|
29
|
+
|
14
30
|
// Register service worker
|
15
31
|
async register(options = {}) {
|
16
32
|
try {
|
@@ -30,30 +46,11 @@ class ServiceWorker {
|
|
30
46
|
firebase: this.manager.config.firebase?.app?.config || null
|
31
47
|
};
|
32
48
|
|
33
|
-
//
|
34
|
-
const
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
// Check if service worker is already registered for this scope
|
40
|
-
let registration = registrations.find(reg =>
|
41
|
-
reg.scope === new URL(scope, window.location.href).href
|
42
|
-
);
|
43
|
-
|
44
|
-
// This helps the .register() method NOT HANG FOREVER
|
45
|
-
if (registration) {
|
46
|
-
console.log('Using existing service worker registration');
|
47
|
-
// Check for updates on existing registration
|
48
|
-
registration.update();
|
49
|
-
} else {
|
50
|
-
console.log('Registering new service worker');
|
51
|
-
// Register with config in URL
|
52
|
-
registration = await navigator.serviceWorker.register(swUrl, {
|
53
|
-
scope,
|
54
|
-
updateViaCache: options.updateViaCache || 'imports'
|
55
|
-
});
|
56
|
-
}
|
49
|
+
// Register and handle everything
|
50
|
+
const registration = await navigator.serviceWorker.register(swPath, {
|
51
|
+
scope,
|
52
|
+
updateViaCache: 'none' // Always check server for updates
|
53
|
+
});
|
57
54
|
|
58
55
|
this._registration = registration;
|
59
56
|
this.manager.state.serviceWorker = registration;
|
@@ -61,16 +58,27 @@ class ServiceWorker {
|
|
61
58
|
// Set up update handlers
|
62
59
|
this._setupUpdateHandlers(registration);
|
63
60
|
|
64
|
-
//
|
65
|
-
|
66
|
-
|
67
|
-
}
|
68
|
-
|
69
|
-
// Set up message channel
|
61
|
+
// Wait for service worker to be ready and send config
|
62
|
+
await navigator.serviceWorker.ready;
|
63
|
+
|
70
64
|
if (registration.active) {
|
65
|
+
try {
|
66
|
+
this.postMessage({
|
67
|
+
command: 'update-config',
|
68
|
+
payload: config
|
69
|
+
});
|
70
|
+
} catch (error) {
|
71
|
+
console.warn('Could not send config to service worker:', error);
|
72
|
+
}
|
73
|
+
|
71
74
|
this._setupMessageChannel();
|
72
75
|
}
|
73
76
|
|
77
|
+
// Check for updates (this will detect if service worker file changed)
|
78
|
+
if (options.checkForUpdate !== false) {
|
79
|
+
registration.update();
|
80
|
+
}
|
81
|
+
|
74
82
|
return registration;
|
75
83
|
} catch (error) {
|
76
84
|
console.error('Service Worker registration failed:', error);
|
@@ -260,7 +268,7 @@ class ServiceWorker {
|
|
260
268
|
type: 'update-available',
|
261
269
|
worker: newWorker
|
262
270
|
});
|
263
|
-
|
271
|
+
|
264
272
|
// Automatically skip waiting and activate new worker
|
265
273
|
if (this.manager.config.serviceWorker?.autoUpdate !== false) {
|
266
274
|
this.skipWaiting();
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "web-manager",
|
3
|
-
"version": "4.0.
|
3
|
+
"version": "4.0.1",
|
4
4
|
"description": "Easily access important variables such as the query string, current domain, and current page in a single object.",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"module": "src/index.js",
|
@@ -41,14 +41,13 @@
|
|
41
41
|
"replace": {}
|
42
42
|
},
|
43
43
|
"dependencies": {
|
44
|
-
"@sentry/browser": "^10.
|
45
|
-
"firebase": "^12.
|
44
|
+
"@sentry/browser": "^10.15.0",
|
45
|
+
"firebase": "^12.3.0",
|
46
46
|
"itwcw-package-analytics": "^1.0.6",
|
47
47
|
"lodash": "^4.17.21",
|
48
|
-
"resolve-account": "^2.0.
|
48
|
+
"resolve-account": "^2.0.1"
|
49
49
|
},
|
50
50
|
"devDependencies": {
|
51
|
-
"lodash": "^4.17.21",
|
52
51
|
"mocha": "^8.4.0",
|
53
52
|
"prepare-package": "^1.2.2"
|
54
53
|
}
|