@india-boundary-corrector/service-worker 0.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/README.md +174 -0
- package/dist/index.cjs +235 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.global.js +622 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +204 -0
- package/dist/index.js.map +1 -0
- package/dist/worker.global.js +3085 -0
- package/dist/worker.global.js.map +1 -0
- package/package.json +55 -0
- package/src/index.d.ts +94 -0
- package/src/index.js +255 -0
- package/src/worker.js +189 -0
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @india-boundary-corrector/service-worker
|
|
2
|
+
|
|
3
|
+
Service worker that intercepts map tile requests and applies India boundary corrections automatically.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @india-boundary-corrector/service-worker
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### 1. Create a Service Worker File
|
|
14
|
+
|
|
15
|
+
Create `sw.js` in your public directory:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
importScripts('https://unpkg.com/@india-boundary-corrector/service-worker/dist/worker.global.js');
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or if bundling:
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
import '@india-boundary-corrector/service-worker/worker';
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Register from Main Thread
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import { registerCorrectionServiceWorker } from '@india-boundary-corrector/service-worker';
|
|
31
|
+
|
|
32
|
+
// Register and wait for control
|
|
33
|
+
const sw = await registerCorrectionServiceWorker('./sw.js');
|
|
34
|
+
|
|
35
|
+
// Now any matching tile requests will be automatically corrected
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3. Use with Any Map Library
|
|
39
|
+
|
|
40
|
+
The service worker intercepts tile requests transparently:
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
// Leaflet
|
|
44
|
+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
|
|
45
|
+
|
|
46
|
+
// OpenLayers
|
|
47
|
+
new TileLayer({ source: new XYZ({ url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png' }) });
|
|
48
|
+
|
|
49
|
+
// MapLibre
|
|
50
|
+
{ type: 'raster', tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'] }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### With Custom Layer Config
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
import {
|
|
57
|
+
registerCorrectionServiceWorker,
|
|
58
|
+
LayerConfig
|
|
59
|
+
} from '@india-boundary-corrector/service-worker';
|
|
60
|
+
|
|
61
|
+
const sw = await registerCorrectionServiceWorker('./sw.js');
|
|
62
|
+
|
|
63
|
+
// Add custom config
|
|
64
|
+
await sw.addLayerConfig(new LayerConfig({
|
|
65
|
+
id: 'osm-de',
|
|
66
|
+
tileUrlTemplates: ['https://tile.openstreetmap.de/{z}/{x}/{y}.png'],
|
|
67
|
+
lineWidthStops: { 1: 0.5, 2: 0.6, 3: 0.7, 4: 1.0, 10: 3.75 },
|
|
68
|
+
lineStyles: [
|
|
69
|
+
{ color: 'rgb(180, 200, 180)' },
|
|
70
|
+
{ color: 'rgb(121, 146, 127)', widthFraction: 1/3, dashArray: [30, 2, 8, 2] },
|
|
71
|
+
],
|
|
72
|
+
}));
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Usage with IIFE (No Bundler)
|
|
76
|
+
|
|
77
|
+
For projects without a module bundler, you can use the CDN builds directly.
|
|
78
|
+
|
|
79
|
+
### 1. Create a Service Worker File
|
|
80
|
+
|
|
81
|
+
Create `sw.js` in your public directory. This file **must** be hosted on your own domain (service workers cannot be loaded from a CDN):
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
importScripts('https://unpkg.com/@india-boundary-corrector/service-worker/dist/worker.global.js');
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. Include the Script and Register
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<script src="https://unpkg.com/@india-boundary-corrector/service-worker/dist/index.global.js"></script>
|
|
91
|
+
<script>
|
|
92
|
+
// The library is available as IndiaBoundaryCorrector on the global window object
|
|
93
|
+
const { registerCorrectionServiceWorker, LayerConfig } = IndiaBoundaryCorrector;
|
|
94
|
+
|
|
95
|
+
registerCorrectionServiceWorker('./sw.js').then(sw => {
|
|
96
|
+
console.log('Service worker registered');
|
|
97
|
+
|
|
98
|
+
// Now any matching tile requests will be automatically corrected
|
|
99
|
+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
|
|
100
|
+
});
|
|
101
|
+
</script>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### With Custom Layer Config (IIFE)
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<script src="https://unpkg.com/@india-boundary-corrector/service-worker/dist/index.global.js"></script>
|
|
108
|
+
<script>
|
|
109
|
+
const { registerCorrectionServiceWorker, LayerConfig } = IndiaBoundaryCorrector;
|
|
110
|
+
|
|
111
|
+
registerCorrectionServiceWorker('./sw.js').then(async sw => {
|
|
112
|
+
// Add custom config for a different tile provider
|
|
113
|
+
await sw.addLayerConfig(new LayerConfig({
|
|
114
|
+
id: 'my-tiles',
|
|
115
|
+
tileUrlTemplates: ['https://mytiles.example.com/{z}/{x}/{y}.png'],
|
|
116
|
+
lineStyles: [{ color: 'rgb(165, 180, 165)' }],
|
|
117
|
+
}));
|
|
118
|
+
});
|
|
119
|
+
</script>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## API
|
|
123
|
+
|
|
124
|
+
### `registerCorrectionServiceWorker(workerUrl, options?)`
|
|
125
|
+
|
|
126
|
+
Register the service worker and wait for it to take control.
|
|
127
|
+
|
|
128
|
+
| Parameter | Type | Description |
|
|
129
|
+
|-----------|------|-------------|
|
|
130
|
+
| `workerUrl` | string | URL to the service worker script |
|
|
131
|
+
| `options.scope` | string | Service worker scope |
|
|
132
|
+
| `options.pmtilesUrl` | string | PMTiles URL to use |
|
|
133
|
+
| `options.controllerTimeout` | number | Timeout for SW to take control (default: 3000ms) |
|
|
134
|
+
|
|
135
|
+
Returns: `Promise<CorrectionServiceWorker>`
|
|
136
|
+
|
|
137
|
+
### `CorrectionServiceWorker`
|
|
138
|
+
|
|
139
|
+
#### Methods
|
|
140
|
+
|
|
141
|
+
| Method | Returns | Description |
|
|
142
|
+
|--------|---------|-------------|
|
|
143
|
+
| `register()` | `Promise<this>` | Register and wait for control |
|
|
144
|
+
| `unregister()` | `Promise<boolean>` | Unregister the service worker |
|
|
145
|
+
| `isControlling()` | `boolean` | Check if SW is controlling the page |
|
|
146
|
+
| `addLayerConfig(config)` | `Promise<void>` | Add a layer config |
|
|
147
|
+
| `removeLayerConfig(id)` | `Promise<void>` | Remove a layer config |
|
|
148
|
+
| `setPmtilesUrl(url)` | `Promise<void>` | Set PMTiles URL |
|
|
149
|
+
| `setEnabled(enabled)` | `Promise<void>` | Enable/disable corrections |
|
|
150
|
+
| `clearCache()` | `Promise<void>` | Clear the tile cache |
|
|
151
|
+
| `getStatus()` | `Promise<Object>` | Get SW status |
|
|
152
|
+
| `resetConfig()` | `Promise<void>` | Reset to default pmtilesUrl and layer configs |
|
|
153
|
+
|
|
154
|
+
## Built-in Configs
|
|
155
|
+
|
|
156
|
+
The service worker comes with pre-registered configs:
|
|
157
|
+
|
|
158
|
+
- `cartodb-dark`: CartoDB dark tiles
|
|
159
|
+
- `cartodb-light`: CartoDB light/voyager tiles
|
|
160
|
+
- `open-topo`: OpenTopoMap tiles
|
|
161
|
+
- `osm-carto`: OpenStreetMap standard tiles
|
|
162
|
+
- `osm-hot`: Humanitarian OpenStreetMap tiles
|
|
163
|
+
|
|
164
|
+
## Scope Considerations
|
|
165
|
+
|
|
166
|
+
Service workers can only intercept requests within their scope. If your tiles are loaded from a different origin, the SW will still work because it intercepts the `fetch` event before the request goes out.
|
|
167
|
+
|
|
168
|
+
The SW scope must include the page that registers it. Typically:
|
|
169
|
+
- Place `sw.js` in your app's root directory
|
|
170
|
+
- Or specify a narrower scope if needed
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
Unlicense
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.js
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
CorrectionServiceWorker: () => CorrectionServiceWorker,
|
|
24
|
+
LayerConfig: () => import_layer_configs.LayerConfig,
|
|
25
|
+
MessageTypes: () => MessageTypes,
|
|
26
|
+
getPmtilesUrl: () => import_data.getPmtilesUrl,
|
|
27
|
+
getWorkerImportSnippet: () => getWorkerImportSnippet,
|
|
28
|
+
layerConfigs: () => import_layer_configs.layerConfigs,
|
|
29
|
+
registerCorrectionServiceWorker: () => registerCorrectionServiceWorker
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
var import_layer_configs = require("@india-boundary-corrector/layer-configs");
|
|
33
|
+
var import_data = require("@india-boundary-corrector/data");
|
|
34
|
+
var MessageTypes = {
|
|
35
|
+
ADD_LAYER_CONFIG: "ADD_LAYER_CONFIG",
|
|
36
|
+
REMOVE_LAYER_CONFIG: "REMOVE_LAYER_CONFIG",
|
|
37
|
+
SET_PMTILES_URL: "SET_PMTILES_URL",
|
|
38
|
+
SET_ENABLED: "SET_ENABLED",
|
|
39
|
+
CLEAR_CACHE: "CLEAR_CACHE",
|
|
40
|
+
GET_STATUS: "GET_STATUS",
|
|
41
|
+
RESET_CONFIG: "RESET_CONFIG"
|
|
42
|
+
};
|
|
43
|
+
var CorrectionServiceWorker = class {
|
|
44
|
+
/**
|
|
45
|
+
* @param {string} workerUrl - URL to the service worker script
|
|
46
|
+
* @param {Object} [options]
|
|
47
|
+
* @param {string} [options.scope] - Service worker scope (defaults to workerUrl directory)
|
|
48
|
+
* @param {string} [options.pmtilesUrl] - PMTiles URL to set after registration
|
|
49
|
+
* @param {number} [options.controllerTimeout=3000] - Timeout in ms to wait for SW to take control
|
|
50
|
+
*/
|
|
51
|
+
constructor(workerUrl, options = {}) {
|
|
52
|
+
this._workerUrl = workerUrl;
|
|
53
|
+
this._scope = options.scope;
|
|
54
|
+
this._pmtilesUrl = options.pmtilesUrl;
|
|
55
|
+
this._controllerTimeout = options.controllerTimeout ?? 3e3;
|
|
56
|
+
this._registration = null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Register the service worker and wait for it to take control.
|
|
60
|
+
* @returns {Promise<CorrectionServiceWorker>} Returns this instance for chaining
|
|
61
|
+
* @throws {Error} If service workers not supported or registration fails
|
|
62
|
+
*/
|
|
63
|
+
async register() {
|
|
64
|
+
if (!("serviceWorker" in navigator)) {
|
|
65
|
+
throw new Error("Service workers not supported");
|
|
66
|
+
}
|
|
67
|
+
const regOptions = this._scope ? { scope: this._scope } : void 0;
|
|
68
|
+
this._registration = await navigator.serviceWorker.register(
|
|
69
|
+
this._workerUrl,
|
|
70
|
+
regOptions
|
|
71
|
+
);
|
|
72
|
+
await navigator.serviceWorker.ready;
|
|
73
|
+
if (!navigator.serviceWorker.controller) {
|
|
74
|
+
await this._waitForController();
|
|
75
|
+
}
|
|
76
|
+
await this.resetConfig();
|
|
77
|
+
if (this._pmtilesUrl) {
|
|
78
|
+
await this.setPmtilesUrl(this._pmtilesUrl);
|
|
79
|
+
}
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Wait for the service worker to take control of the page.
|
|
84
|
+
* @returns {Promise<void>}
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
async _waitForController() {
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
const onControllerChange = () => {
|
|
90
|
+
navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange);
|
|
91
|
+
resolve();
|
|
92
|
+
};
|
|
93
|
+
navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
|
|
94
|
+
setTimeout(resolve, this._controllerTimeout);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if the service worker is controlling the page.
|
|
99
|
+
* @returns {boolean}
|
|
100
|
+
*/
|
|
101
|
+
isControlling() {
|
|
102
|
+
return !!navigator.serviceWorker.controller;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Unregister the service worker.
|
|
106
|
+
* @returns {Promise<boolean>}
|
|
107
|
+
*/
|
|
108
|
+
async unregister() {
|
|
109
|
+
if (this._registration) {
|
|
110
|
+
return this._registration.unregister();
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get the active service worker.
|
|
116
|
+
* @returns {ServiceWorker|null}
|
|
117
|
+
*/
|
|
118
|
+
getWorker() {
|
|
119
|
+
return this._registration?.active ?? navigator.serviceWorker.controller;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Send a message to the service worker.
|
|
123
|
+
* @param {Object} message
|
|
124
|
+
* @returns {Promise<any>}
|
|
125
|
+
*/
|
|
126
|
+
async sendMessage(message) {
|
|
127
|
+
const worker = this.getWorker();
|
|
128
|
+
if (!worker) {
|
|
129
|
+
throw new Error("Service worker not active");
|
|
130
|
+
}
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const channel = new MessageChannel();
|
|
133
|
+
channel.port1.onmessage = (event) => {
|
|
134
|
+
if (event.data.error) {
|
|
135
|
+
reject(new Error(event.data.error));
|
|
136
|
+
} else {
|
|
137
|
+
resolve(event.data);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
worker.postMessage(message, [channel.port2]);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Add a layer config to the service worker.
|
|
145
|
+
* @param {Object} layerConfig
|
|
146
|
+
* @returns {Promise<void>}
|
|
147
|
+
*/
|
|
148
|
+
async addLayerConfig(layerConfig) {
|
|
149
|
+
const serialized = typeof layerConfig.toJSON === "function" ? layerConfig.toJSON() : layerConfig;
|
|
150
|
+
await this.sendMessage({
|
|
151
|
+
type: MessageTypes.ADD_LAYER_CONFIG,
|
|
152
|
+
layerConfig: serialized
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Remove a layer config from the service worker.
|
|
157
|
+
* @param {string} configId
|
|
158
|
+
* @returns {Promise<void>}
|
|
159
|
+
*/
|
|
160
|
+
async removeLayerConfig(configId) {
|
|
161
|
+
await this.sendMessage({
|
|
162
|
+
type: MessageTypes.REMOVE_LAYER_CONFIG,
|
|
163
|
+
configId
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Set the PMTiles URL.
|
|
168
|
+
* @param {string} pmtilesUrl
|
|
169
|
+
* @returns {Promise<void>}
|
|
170
|
+
*/
|
|
171
|
+
async setPmtilesUrl(pmtilesUrl) {
|
|
172
|
+
await this.sendMessage({
|
|
173
|
+
type: MessageTypes.SET_PMTILES_URL,
|
|
174
|
+
pmtilesUrl
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Enable or disable the correction service.
|
|
179
|
+
* @param {boolean} enabled
|
|
180
|
+
* @returns {Promise<void>}
|
|
181
|
+
*/
|
|
182
|
+
async setEnabled(enabled) {
|
|
183
|
+
await this.sendMessage({
|
|
184
|
+
type: MessageTypes.SET_ENABLED,
|
|
185
|
+
enabled
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Clear the tile cache.
|
|
190
|
+
* @returns {Promise<void>}
|
|
191
|
+
*/
|
|
192
|
+
async clearCache() {
|
|
193
|
+
await this.sendMessage({
|
|
194
|
+
type: MessageTypes.CLEAR_CACHE
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get the status of the service worker.
|
|
199
|
+
* @returns {Promise<Object>}
|
|
200
|
+
*/
|
|
201
|
+
async getStatus() {
|
|
202
|
+
return this.sendMessage({
|
|
203
|
+
type: MessageTypes.GET_STATUS
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Reset the service worker configuration to defaults.
|
|
208
|
+
* Resets pmtilesUrl to default and restores default layer configs.
|
|
209
|
+
* @returns {Promise<void>}
|
|
210
|
+
*/
|
|
211
|
+
async resetConfig() {
|
|
212
|
+
await this.sendMessage({
|
|
213
|
+
type: MessageTypes.RESET_CONFIG
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
async function registerCorrectionServiceWorker(workerUrl, options = {}) {
|
|
218
|
+
const sw = new CorrectionServiceWorker(workerUrl, options);
|
|
219
|
+
await sw.register();
|
|
220
|
+
return sw;
|
|
221
|
+
}
|
|
222
|
+
function getWorkerImportSnippet(workerGlobalUrl) {
|
|
223
|
+
return `importScripts('${workerGlobalUrl}');`;
|
|
224
|
+
}
|
|
225
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
226
|
+
0 && (module.exports = {
|
|
227
|
+
CorrectionServiceWorker,
|
|
228
|
+
LayerConfig,
|
|
229
|
+
MessageTypes,
|
|
230
|
+
getPmtilesUrl,
|
|
231
|
+
getWorkerImportSnippet,
|
|
232
|
+
layerConfigs,
|
|
233
|
+
registerCorrectionServiceWorker
|
|
234
|
+
});
|
|
235
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"sourcesContent":["/**\n * Main entry point - exports utilities for registering the service worker\n * from the main thread.\n */\n\nexport { layerConfigs, LayerConfig } from '@india-boundary-corrector/layer-configs';\nexport { getPmtilesUrl } from '@india-boundary-corrector/data';\n\n/**\n * Message types for communication with service worker\n */\nexport const MessageTypes = {\n ADD_LAYER_CONFIG: 'ADD_LAYER_CONFIG',\n REMOVE_LAYER_CONFIG: 'REMOVE_LAYER_CONFIG',\n SET_PMTILES_URL: 'SET_PMTILES_URL',\n SET_ENABLED: 'SET_ENABLED',\n CLEAR_CACHE: 'CLEAR_CACHE',\n GET_STATUS: 'GET_STATUS',\n RESET_CONFIG: 'RESET_CONFIG',\n};\n\n/**\n * Controller for the boundary correction service worker.\n * Use this to register the service worker and communicate with it.\n */\nexport class CorrectionServiceWorker {\n /**\n * @param {string} workerUrl - URL to the service worker script\n * @param {Object} [options]\n * @param {string} [options.scope] - Service worker scope (defaults to workerUrl directory)\n * @param {string} [options.pmtilesUrl] - PMTiles URL to set after registration\n * @param {number} [options.controllerTimeout=3000] - Timeout in ms to wait for SW to take control\n */\n constructor(workerUrl, options = {}) {\n this._workerUrl = workerUrl;\n this._scope = options.scope;\n this._pmtilesUrl = options.pmtilesUrl;\n this._controllerTimeout = options.controllerTimeout ?? 3000;\n this._registration = null;\n }\n\n /**\n * Register the service worker and wait for it to take control.\n * @returns {Promise<CorrectionServiceWorker>} Returns this instance for chaining\n * @throws {Error} If service workers not supported or registration fails\n */\n async register() {\n if (!('serviceWorker' in navigator)) {\n throw new Error('Service workers not supported');\n }\n\n const regOptions = this._scope ? { scope: this._scope } : undefined;\n this._registration = await navigator.serviceWorker.register(\n this._workerUrl,\n regOptions\n );\n\n // Wait for the service worker to be ready\n await navigator.serviceWorker.ready;\n\n // Wait for controller if not already controlling\n if (!navigator.serviceWorker.controller) {\n await this._waitForController();\n }\n\n // Reset config to defaults when connecting to an existing service worker\n await this.resetConfig();\n\n // Set PMTiles URL if provided\n if (this._pmtilesUrl) {\n await this.setPmtilesUrl(this._pmtilesUrl);\n }\n\n return this;\n }\n\n /**\n * Wait for the service worker to take control of the page.\n * @returns {Promise<void>}\n * @private\n */\n async _waitForController() {\n return new Promise((resolve) => {\n const onControllerChange = () => {\n navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);\n resolve();\n };\n navigator.serviceWorker.addEventListener('controllerchange', onControllerChange);\n // Timeout fallback - SW may already be controlling after registration\n setTimeout(resolve, this._controllerTimeout);\n });\n }\n\n /**\n * Check if the service worker is controlling the page.\n * @returns {boolean}\n */\n isControlling() {\n return !!navigator.serviceWorker.controller;\n }\n\n /**\n * Unregister the service worker.\n * @returns {Promise<boolean>}\n */\n async unregister() {\n if (this._registration) {\n return this._registration.unregister();\n }\n return false;\n }\n\n /**\n * Get the active service worker.\n * @returns {ServiceWorker|null}\n */\n getWorker() {\n return this._registration?.active ?? navigator.serviceWorker.controller;\n }\n\n /**\n * Send a message to the service worker.\n * @param {Object} message\n * @returns {Promise<any>}\n */\n async sendMessage(message) {\n const worker = this.getWorker();\n if (!worker) {\n throw new Error('Service worker not active');\n }\n\n return new Promise((resolve, reject) => {\n const channel = new MessageChannel();\n channel.port1.onmessage = (event) => {\n if (event.data.error) {\n reject(new Error(event.data.error));\n } else {\n resolve(event.data);\n }\n };\n worker.postMessage(message, [channel.port2]);\n });\n }\n\n /**\n * Add a layer config to the service worker.\n * @param {Object} layerConfig\n * @returns {Promise<void>}\n */\n async addLayerConfig(layerConfig) {\n // Use toJSON if available to properly serialize the config\n const serialized = typeof layerConfig.toJSON === 'function' \n ? layerConfig.toJSON() \n : layerConfig;\n await this.sendMessage({\n type: MessageTypes.ADD_LAYER_CONFIG,\n layerConfig: serialized,\n });\n }\n\n /**\n * Remove a layer config from the service worker.\n * @param {string} configId\n * @returns {Promise<void>}\n */\n async removeLayerConfig(configId) {\n await this.sendMessage({\n type: MessageTypes.REMOVE_LAYER_CONFIG,\n configId,\n });\n }\n\n /**\n * Set the PMTiles URL.\n * @param {string} pmtilesUrl\n * @returns {Promise<void>}\n */\n async setPmtilesUrl(pmtilesUrl) {\n await this.sendMessage({\n type: MessageTypes.SET_PMTILES_URL,\n pmtilesUrl,\n });\n }\n\n /**\n * Enable or disable the correction service.\n * @param {boolean} enabled\n * @returns {Promise<void>}\n */\n async setEnabled(enabled) {\n await this.sendMessage({\n type: MessageTypes.SET_ENABLED,\n enabled,\n });\n }\n\n /**\n * Clear the tile cache.\n * @returns {Promise<void>}\n */\n async clearCache() {\n await this.sendMessage({\n type: MessageTypes.CLEAR_CACHE,\n });\n }\n\n /**\n * Get the status of the service worker.\n * @returns {Promise<Object>}\n */\n async getStatus() {\n return this.sendMessage({\n type: MessageTypes.GET_STATUS,\n });\n }\n\n /**\n * Reset the service worker configuration to defaults.\n * Resets pmtilesUrl to default and restores default layer configs.\n * @returns {Promise<void>}\n */\n async resetConfig() {\n await this.sendMessage({\n type: MessageTypes.RESET_CONFIG,\n });\n }\n}\n\n/**\n * Register the correction service worker with simplified setup.\n * @param {string} workerUrl - URL to the service worker script\n * @param {Object} [options]\n * @param {string} [options.scope] - Service worker scope\n * @param {string} [options.pmtilesUrl] - PMTiles URL to set\n * @param {number} [options.controllerTimeout] - Timeout in ms to wait for SW control\n * @returns {Promise<CorrectionServiceWorker>}\n */\nexport async function registerCorrectionServiceWorker(workerUrl, options = {}) {\n const sw = new CorrectionServiceWorker(workerUrl, options);\n await sw.register();\n return sw;\n}\n\n/**\n * Get the importScripts snippet for a service worker file.\n * This can be used to create a minimal sw.js file.\n * @param {string} workerGlobalUrl - URL to the worker.global.js file\n * @returns {string} JavaScript code to put in sw.js\n * @example\n * // Create sw.js with:\n * // importScripts('https://unpkg.com/@india-boundary-corrector/service-worker/dist/worker.global.js');\n */\nexport function getWorkerImportSnippet(workerGlobalUrl) {\n return `importScripts('${workerGlobalUrl}');`;\n}\n"],"mappings":"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","names":[]}
|