@geogirafe/lib-geoportal 1.2.0 → 1.2.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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geogirafe.org"
7
7
  },
8
- "version": "1.2.0",
8
+ "version": "1.2.1",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -1 +1 @@
1
- {"version":"1.2.0", "build":"2922327721", "date":"07/10/2026"}
1
+ {"version":"1.2.1", "build":"2968136297", "date":"20/10/2026"}
@@ -14,4 +14,6 @@ export default class GeoGirafeApp {
14
14
  protected defineCoreComponents(): void;
15
15
  private initializeServiceWorker;
16
16
  private waitForServiceWorkerControl;
17
+ private registerServiceWorker;
18
+ private waitForServiceWorkerActivation;
17
19
  }
@@ -215,23 +215,18 @@ export default class GeoGirafeApp {
215
215
  }
216
216
  async waitForServiceWorkerControl() {
217
217
  const sw = navigator.serviceWorker;
218
- const registration = await sw.register('service-worker.js', { type: 'module' });
218
+ const registration = await this.registerServiceWorker();
219
219
  // If a service worker already controls the current page, everything is ready.
220
220
  // `registration.active` only tells us that a service worker is active for the registration;
221
221
  // `sw.controller` tells us that it actually controls this page.
222
222
  if (sw.controller) {
223
223
  return sw.controller;
224
224
  }
225
- // The page is not currently controlled by a service worker.
226
- // This can happen, for example, after a force refresh (Ctrl+F5), even though
227
- // an active service worker already exists. In that case, the service worker's
228
- // `activate` event is not triggered again, so the `clients.claim()` call from
229
- // the activation phase cannot take control of this newly loaded page.
230
- // If an active service worker already exists, explicitly ask it to claim the
231
- // current page. The service worker handles this message by calling `clients.claim()`.
232
- const active = registration.active;
233
- if (active) {
234
- active.postMessage({ type: 'claim' });
225
+ // If the page is still outside of the service worker scope (see registerServiceWorker),
226
+ // the `controllerchange` event will never be fired, so we only wait for the service worker to be activated.
227
+ if (!globalThis.location.href.startsWith(registration.scope)) {
228
+ console.warn(`The current page is outside of the service worker scope (${registration.scope}), it won't be controlled by the service worker.`);
229
+ return this.waitForServiceWorkerActivation(registration);
235
230
  }
236
231
  // Wait until the service worker takes control of the current page.
237
232
  // Once `clients.claim()` succeeds, the browser updates `sw.controller` and
@@ -243,6 +238,60 @@ export default class GeoGirafeApp {
243
238
  resolve(controller);
244
239
  }
245
240
  }, { once: true });
241
+ // The page is not currently controlled by a service worker.
242
+ // This can happen, for example, after a force refresh (Ctrl+F5), even though
243
+ // an active service worker already exists. In that case, the service worker's
244
+ // `activate` event is not triggered again, so the `clients.claim()` call from
245
+ // the activation phase cannot take control of this newly loaded page.
246
+ // If an active service worker already exists, explicitly ask it to claim the
247
+ // current page. The service worker handles this message by calling `clients.claim()`.
248
+ const active = registration.active;
249
+ if (active) {
250
+ active.postMessage({ type: 'claim' });
251
+ }
252
+ // Safety check: This is exactly the same test as the begining of the method
253
+ // but the worker may have claimed the page before the listener
254
+ // above was registered, in which case `controllerchange` never fires.
255
+ if (sw.controller) {
256
+ resolve(sw.controller);
257
+ }
258
+ });
259
+ }
260
+ async registerServiceWorker() {
261
+ // The default scope of the service worker is the folder of service-worker.js (resolved against <base href>).
262
+ // When the application page is served from another path than its static files
263
+ // (e.g. page at /iframe and files at /static/), the page is outside of this scope and can't be controlled.
264
+ // In that case, try to register the service worker at path of the page as scope.
265
+ // This is only allowed by the browser if the server sends the "Service-Worker-Allowed" header.
266
+ const scriptUrl = new URL('service-worker.js', document.baseURI);
267
+ const defaultScope = new URL('./', scriptUrl).href;
268
+ if (!globalThis.location.href.startsWith(defaultScope)) {
269
+ const pageScope = new URL('./', globalThis.location.href).href;
270
+ try {
271
+ return await navigator.serviceWorker.register(scriptUrl, { type: 'module', scope: pageScope });
272
+ }
273
+ catch (err) {
274
+ console.warn(`Service worker could not be registered with the scope ${pageScope}. ` +
275
+ `Check that the server sends the header "Service-Worker-Allowed" with the service worker script.`, err);
276
+ }
277
+ }
278
+ return navigator.serviceWorker.register(scriptUrl, { type: 'module' });
279
+ }
280
+ async waitForServiceWorkerActivation(registration) {
281
+ if (registration.active) {
282
+ return registration.active;
283
+ }
284
+ const sw = registration.installing ?? registration.waiting;
285
+ if (!sw) {
286
+ throw new Error('No service worker is installing or waiting.');
287
+ }
288
+ return new Promise((resolve) => {
289
+ sw.addEventListener('statechange', function onStateChange() {
290
+ if (sw.state === 'activated') {
291
+ sw.removeEventListener('statechange', onStateChange);
292
+ resolve(sw);
293
+ }
294
+ });
246
295
  });
247
296
  }
248
297
  }