@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/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@india-boundary-corrector/service-worker",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Service worker for automatic India boundary corrections on map tiles",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "src/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./src/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./src/index.d.ts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./worker": {
|
|
21
|
+
"import": "./dist/worker.global.js",
|
|
22
|
+
"require": "./dist/worker.global.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"src",
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@india-boundary-corrector/data": "^0.0.1",
|
|
34
|
+
"@india-boundary-corrector/layer-configs": "^0.0.1",
|
|
35
|
+
"@india-boundary-corrector/tilefixer": "^0.0.1"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"india",
|
|
39
|
+
"boundary",
|
|
40
|
+
"map",
|
|
41
|
+
"service-worker",
|
|
42
|
+
"tiles"
|
|
43
|
+
],
|
|
44
|
+
"author": "ramSeraph",
|
|
45
|
+
"license": "Unlicense",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/ramSeraph/india_boundary_corrector.git",
|
|
49
|
+
"directory": "packages/service-worker"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/ramSeraph/india_boundary_corrector/issues"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/ramSeraph/india_boundary_corrector#readme"
|
|
55
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { LayerConfig } from '@india-boundary-corrector/layer-configs';
|
|
2
|
+
|
|
3
|
+
export { layerConfigs, LayerConfig } from '@india-boundary-corrector/layer-configs';
|
|
4
|
+
export { getPmtilesUrl } from '@india-boundary-corrector/data';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Message types for communication with service worker
|
|
8
|
+
*/
|
|
9
|
+
export declare const MessageTypes: {
|
|
10
|
+
ADD_LAYER_CONFIG: 'ADD_LAYER_CONFIG';
|
|
11
|
+
REMOVE_LAYER_CONFIG: 'REMOVE_LAYER_CONFIG';
|
|
12
|
+
SET_PMTILES_URL: 'SET_PMTILES_URL';
|
|
13
|
+
SET_ENABLED: 'SET_ENABLED';
|
|
14
|
+
CLEAR_CACHE: 'CLEAR_CACHE';
|
|
15
|
+
GET_STATUS: 'GET_STATUS';
|
|
16
|
+
RESET_CONFIG: 'RESET_CONFIG';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Options for CorrectionServiceWorker
|
|
21
|
+
*/
|
|
22
|
+
export interface CorrectionServiceWorkerOptions {
|
|
23
|
+
/** Service worker scope (defaults to workerUrl directory) */
|
|
24
|
+
scope?: string;
|
|
25
|
+
/** PMTiles URL to set after registration */
|
|
26
|
+
pmtilesUrl?: string;
|
|
27
|
+
/** Timeout in ms to wait for SW to take control (default: 3000) */
|
|
28
|
+
controllerTimeout?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Status returned by getStatus()
|
|
33
|
+
*/
|
|
34
|
+
export interface ServiceWorkerStatus {
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
pmtilesUrl: string;
|
|
37
|
+
configIds: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Controller for the boundary correction service worker.
|
|
42
|
+
*/
|
|
43
|
+
export declare class CorrectionServiceWorker {
|
|
44
|
+
constructor(workerUrl: string, options?: CorrectionServiceWorkerOptions);
|
|
45
|
+
|
|
46
|
+
/** Register the service worker and wait for it to take control */
|
|
47
|
+
register(): Promise<CorrectionServiceWorker>;
|
|
48
|
+
|
|
49
|
+
/** Check if the service worker is controlling the page */
|
|
50
|
+
isControlling(): boolean;
|
|
51
|
+
|
|
52
|
+
/** Unregister the service worker */
|
|
53
|
+
unregister(): Promise<boolean>;
|
|
54
|
+
|
|
55
|
+
/** Get the active service worker */
|
|
56
|
+
getWorker(): ServiceWorker | null;
|
|
57
|
+
|
|
58
|
+
/** Send a message to the service worker */
|
|
59
|
+
sendMessage(message: object): Promise<any>;
|
|
60
|
+
|
|
61
|
+
/** Add a layer config to the service worker */
|
|
62
|
+
addLayerConfig(layerConfig: LayerConfig): Promise<void>;
|
|
63
|
+
|
|
64
|
+
/** Remove a layer config from the service worker */
|
|
65
|
+
removeLayerConfig(configId: string): Promise<void>;
|
|
66
|
+
|
|
67
|
+
/** Set the PMTiles URL */
|
|
68
|
+
setPmtilesUrl(pmtilesUrl: string): Promise<void>;
|
|
69
|
+
|
|
70
|
+
/** Enable or disable the correction service */
|
|
71
|
+
setEnabled(enabled: boolean): Promise<void>;
|
|
72
|
+
|
|
73
|
+
/** Clear the tile cache */
|
|
74
|
+
clearCache(): Promise<void>;
|
|
75
|
+
|
|
76
|
+
/** Get the status of the service worker */
|
|
77
|
+
getStatus(): Promise<ServiceWorkerStatus>;
|
|
78
|
+
|
|
79
|
+
/** Reset configuration to defaults (pmtilesUrl and layer configs) */
|
|
80
|
+
resetConfig(): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Register the correction service worker.
|
|
85
|
+
*/
|
|
86
|
+
export declare function registerCorrectionServiceWorker(
|
|
87
|
+
workerUrl: string,
|
|
88
|
+
options?: CorrectionServiceWorkerOptions
|
|
89
|
+
): Promise<CorrectionServiceWorker>;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get the importScripts snippet for a service worker file.
|
|
93
|
+
*/
|
|
94
|
+
export declare function getWorkerImportSnippet(workerGlobalUrl: string): string;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point - exports utilities for registering the service worker
|
|
3
|
+
* from the main thread.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { layerConfigs, LayerConfig } from '@india-boundary-corrector/layer-configs';
|
|
7
|
+
export { getPmtilesUrl } from '@india-boundary-corrector/data';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Message types for communication with service worker
|
|
11
|
+
*/
|
|
12
|
+
export const MessageTypes = {
|
|
13
|
+
ADD_LAYER_CONFIG: 'ADD_LAYER_CONFIG',
|
|
14
|
+
REMOVE_LAYER_CONFIG: 'REMOVE_LAYER_CONFIG',
|
|
15
|
+
SET_PMTILES_URL: 'SET_PMTILES_URL',
|
|
16
|
+
SET_ENABLED: 'SET_ENABLED',
|
|
17
|
+
CLEAR_CACHE: 'CLEAR_CACHE',
|
|
18
|
+
GET_STATUS: 'GET_STATUS',
|
|
19
|
+
RESET_CONFIG: 'RESET_CONFIG',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Controller for the boundary correction service worker.
|
|
24
|
+
* Use this to register the service worker and communicate with it.
|
|
25
|
+
*/
|
|
26
|
+
export class CorrectionServiceWorker {
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} workerUrl - URL to the service worker script
|
|
29
|
+
* @param {Object} [options]
|
|
30
|
+
* @param {string} [options.scope] - Service worker scope (defaults to workerUrl directory)
|
|
31
|
+
* @param {string} [options.pmtilesUrl] - PMTiles URL to set after registration
|
|
32
|
+
* @param {number} [options.controllerTimeout=3000] - Timeout in ms to wait for SW to take control
|
|
33
|
+
*/
|
|
34
|
+
constructor(workerUrl, options = {}) {
|
|
35
|
+
this._workerUrl = workerUrl;
|
|
36
|
+
this._scope = options.scope;
|
|
37
|
+
this._pmtilesUrl = options.pmtilesUrl;
|
|
38
|
+
this._controllerTimeout = options.controllerTimeout ?? 3000;
|
|
39
|
+
this._registration = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Register the service worker and wait for it to take control.
|
|
44
|
+
* @returns {Promise<CorrectionServiceWorker>} Returns this instance for chaining
|
|
45
|
+
* @throws {Error} If service workers not supported or registration fails
|
|
46
|
+
*/
|
|
47
|
+
async register() {
|
|
48
|
+
if (!('serviceWorker' in navigator)) {
|
|
49
|
+
throw new Error('Service workers not supported');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const regOptions = this._scope ? { scope: this._scope } : undefined;
|
|
53
|
+
this._registration = await navigator.serviceWorker.register(
|
|
54
|
+
this._workerUrl,
|
|
55
|
+
regOptions
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Wait for the service worker to be ready
|
|
59
|
+
await navigator.serviceWorker.ready;
|
|
60
|
+
|
|
61
|
+
// Wait for controller if not already controlling
|
|
62
|
+
if (!navigator.serviceWorker.controller) {
|
|
63
|
+
await this._waitForController();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Reset config to defaults when connecting to an existing service worker
|
|
67
|
+
await this.resetConfig();
|
|
68
|
+
|
|
69
|
+
// Set PMTiles URL if provided
|
|
70
|
+
if (this._pmtilesUrl) {
|
|
71
|
+
await this.setPmtilesUrl(this._pmtilesUrl);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Wait for the service worker to take control of the page.
|
|
79
|
+
* @returns {Promise<void>}
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
async _waitForController() {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
const onControllerChange = () => {
|
|
85
|
+
navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);
|
|
86
|
+
resolve();
|
|
87
|
+
};
|
|
88
|
+
navigator.serviceWorker.addEventListener('controllerchange', onControllerChange);
|
|
89
|
+
// Timeout fallback - SW may already be controlling after registration
|
|
90
|
+
setTimeout(resolve, this._controllerTimeout);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if the service worker is controlling the page.
|
|
96
|
+
* @returns {boolean}
|
|
97
|
+
*/
|
|
98
|
+
isControlling() {
|
|
99
|
+
return !!navigator.serviceWorker.controller;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Unregister the service worker.
|
|
104
|
+
* @returns {Promise<boolean>}
|
|
105
|
+
*/
|
|
106
|
+
async unregister() {
|
|
107
|
+
if (this._registration) {
|
|
108
|
+
return this._registration.unregister();
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get the active service worker.
|
|
115
|
+
* @returns {ServiceWorker|null}
|
|
116
|
+
*/
|
|
117
|
+
getWorker() {
|
|
118
|
+
return this._registration?.active ?? navigator.serviceWorker.controller;
|
|
119
|
+
}
|
|
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
|
+
|
|
132
|
+
return new Promise((resolve, reject) => {
|
|
133
|
+
const channel = new MessageChannel();
|
|
134
|
+
channel.port1.onmessage = (event) => {
|
|
135
|
+
if (event.data.error) {
|
|
136
|
+
reject(new Error(event.data.error));
|
|
137
|
+
} else {
|
|
138
|
+
resolve(event.data);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
worker.postMessage(message, [channel.port2]);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Add a layer config to the service worker.
|
|
147
|
+
* @param {Object} layerConfig
|
|
148
|
+
* @returns {Promise<void>}
|
|
149
|
+
*/
|
|
150
|
+
async addLayerConfig(layerConfig) {
|
|
151
|
+
// Use toJSON if available to properly serialize the config
|
|
152
|
+
const serialized = typeof layerConfig.toJSON === 'function'
|
|
153
|
+
? layerConfig.toJSON()
|
|
154
|
+
: layerConfig;
|
|
155
|
+
await this.sendMessage({
|
|
156
|
+
type: MessageTypes.ADD_LAYER_CONFIG,
|
|
157
|
+
layerConfig: serialized,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Remove a layer config from the service worker.
|
|
163
|
+
* @param {string} configId
|
|
164
|
+
* @returns {Promise<void>}
|
|
165
|
+
*/
|
|
166
|
+
async removeLayerConfig(configId) {
|
|
167
|
+
await this.sendMessage({
|
|
168
|
+
type: MessageTypes.REMOVE_LAYER_CONFIG,
|
|
169
|
+
configId,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Set the PMTiles URL.
|
|
175
|
+
* @param {string} pmtilesUrl
|
|
176
|
+
* @returns {Promise<void>}
|
|
177
|
+
*/
|
|
178
|
+
async setPmtilesUrl(pmtilesUrl) {
|
|
179
|
+
await this.sendMessage({
|
|
180
|
+
type: MessageTypes.SET_PMTILES_URL,
|
|
181
|
+
pmtilesUrl,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Enable or disable the correction service.
|
|
187
|
+
* @param {boolean} enabled
|
|
188
|
+
* @returns {Promise<void>}
|
|
189
|
+
*/
|
|
190
|
+
async setEnabled(enabled) {
|
|
191
|
+
await this.sendMessage({
|
|
192
|
+
type: MessageTypes.SET_ENABLED,
|
|
193
|
+
enabled,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Clear the tile cache.
|
|
199
|
+
* @returns {Promise<void>}
|
|
200
|
+
*/
|
|
201
|
+
async clearCache() {
|
|
202
|
+
await this.sendMessage({
|
|
203
|
+
type: MessageTypes.CLEAR_CACHE,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get the status of the service worker.
|
|
209
|
+
* @returns {Promise<Object>}
|
|
210
|
+
*/
|
|
211
|
+
async getStatus() {
|
|
212
|
+
return this.sendMessage({
|
|
213
|
+
type: MessageTypes.GET_STATUS,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Reset the service worker configuration to defaults.
|
|
219
|
+
* Resets pmtilesUrl to default and restores default layer configs.
|
|
220
|
+
* @returns {Promise<void>}
|
|
221
|
+
*/
|
|
222
|
+
async resetConfig() {
|
|
223
|
+
await this.sendMessage({
|
|
224
|
+
type: MessageTypes.RESET_CONFIG,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Register the correction service worker with simplified setup.
|
|
231
|
+
* @param {string} workerUrl - URL to the service worker script
|
|
232
|
+
* @param {Object} [options]
|
|
233
|
+
* @param {string} [options.scope] - Service worker scope
|
|
234
|
+
* @param {string} [options.pmtilesUrl] - PMTiles URL to set
|
|
235
|
+
* @param {number} [options.controllerTimeout] - Timeout in ms to wait for SW control
|
|
236
|
+
* @returns {Promise<CorrectionServiceWorker>}
|
|
237
|
+
*/
|
|
238
|
+
export async function registerCorrectionServiceWorker(workerUrl, options = {}) {
|
|
239
|
+
const sw = new CorrectionServiceWorker(workerUrl, options);
|
|
240
|
+
await sw.register();
|
|
241
|
+
return sw;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get the importScripts snippet for a service worker file.
|
|
246
|
+
* This can be used to create a minimal sw.js file.
|
|
247
|
+
* @param {string} workerGlobalUrl - URL to the worker.global.js file
|
|
248
|
+
* @returns {string} JavaScript code to put in sw.js
|
|
249
|
+
* @example
|
|
250
|
+
* // Create sw.js with:
|
|
251
|
+
* // importScripts('https://unpkg.com/@india-boundary-corrector/service-worker/dist/worker.global.js');
|
|
252
|
+
*/
|
|
253
|
+
export function getWorkerImportSnippet(workerGlobalUrl) {
|
|
254
|
+
return `importScripts('${workerGlobalUrl}');`;
|
|
255
|
+
}
|
package/src/worker.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Worker script for intercepting tile requests and applying
|
|
3
|
+
* India boundary corrections.
|
|
4
|
+
*
|
|
5
|
+
* This file should be served as the service worker script.
|
|
6
|
+
* It bundles all dependencies for standalone use.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { getPmtilesUrl } from '@india-boundary-corrector/data';
|
|
10
|
+
import { layerConfigs, LayerConfig } from '@india-boundary-corrector/layer-configs';
|
|
11
|
+
import { BoundaryCorrector as TileFixer } from '@india-boundary-corrector/tilefixer';
|
|
12
|
+
|
|
13
|
+
// Message types
|
|
14
|
+
const MessageTypes = {
|
|
15
|
+
ADD_LAYER_CONFIG: 'ADD_LAYER_CONFIG',
|
|
16
|
+
REMOVE_LAYER_CONFIG: 'REMOVE_LAYER_CONFIG',
|
|
17
|
+
SET_PMTILES_URL: 'SET_PMTILES_URL',
|
|
18
|
+
SET_ENABLED: 'SET_ENABLED',
|
|
19
|
+
CLEAR_CACHE: 'CLEAR_CACHE',
|
|
20
|
+
GET_STATUS: 'GET_STATUS',
|
|
21
|
+
RESET_CONFIG: 'RESET_CONFIG',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// State
|
|
25
|
+
let registry = layerConfigs.createMergedRegistry();
|
|
26
|
+
let tileFixer = null;
|
|
27
|
+
let pmtilesUrl = null; // Will be set lazily or via message
|
|
28
|
+
let enabled = true;
|
|
29
|
+
let tileSize = 256;
|
|
30
|
+
|
|
31
|
+
// Reset to default configuration
|
|
32
|
+
function resetConfig() {
|
|
33
|
+
pmtilesUrl = null;
|
|
34
|
+
tileFixer = null;
|
|
35
|
+
enabled = true;
|
|
36
|
+
registry = layerConfigs.createMergedRegistry();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Initialize TileFixer lazily
|
|
40
|
+
function getTileFixer() {
|
|
41
|
+
if (!tileFixer) {
|
|
42
|
+
if (!pmtilesUrl) {
|
|
43
|
+
pmtilesUrl = getPmtilesUrl();
|
|
44
|
+
}
|
|
45
|
+
tileFixer = new TileFixer(pmtilesUrl);
|
|
46
|
+
}
|
|
47
|
+
return tileFixer;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Reinitialize TileFixer with new URL
|
|
51
|
+
function reinitTileFixer() {
|
|
52
|
+
tileFixer = new TileFixer(pmtilesUrl);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if a request is for a map tile that we should intercept.
|
|
57
|
+
* @param {Request} request
|
|
58
|
+
* @returns {{ layerConfig: Object, coords: { z: number, x: number, y: number } } | null}
|
|
59
|
+
*/
|
|
60
|
+
function shouldIntercept(request) {
|
|
61
|
+
if (!enabled) return null;
|
|
62
|
+
if (request.method !== 'GET') return null;
|
|
63
|
+
|
|
64
|
+
return registry.parseTileUrl(request.url);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Fetch and fix a tile for service worker.
|
|
69
|
+
* Extracted for testability.
|
|
70
|
+
* @param {string} tileUrl - URL of the raster tile
|
|
71
|
+
* @param {number} z - Zoom level
|
|
72
|
+
* @param {number} x - Tile X coordinate
|
|
73
|
+
* @param {number} y - Tile Y coordinate
|
|
74
|
+
* @param {TileFixer} tileFixer - TileFixer instance
|
|
75
|
+
* @param {Object} layerConfig - Layer configuration
|
|
76
|
+
* @param {number} tileSize - Tile size in pixels
|
|
77
|
+
* @param {Object} [options] - Fetch options
|
|
78
|
+
* @returns {Promise<Response>}
|
|
79
|
+
*/
|
|
80
|
+
async function fetchAndFixTile(tileUrl, z, x, y, tileFixer, layerConfig, tileSize, options = {}) {
|
|
81
|
+
const { data, wasFixed } = await tileFixer.fetchAndFixTile(
|
|
82
|
+
tileUrl, z, x, y, layerConfig, { tileSize, mode: 'cors', ...options }
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
return new Response(data, {
|
|
86
|
+
status: 200,
|
|
87
|
+
headers: {
|
|
88
|
+
'Content-Type': 'image/png',
|
|
89
|
+
'Cache-Control': 'max-age=3600',
|
|
90
|
+
'X-Boundary-Corrected': wasFixed ? 'true' : 'false',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Apply corrections to a tile.
|
|
97
|
+
* @param {Request} request
|
|
98
|
+
* @param {Object} layerConfig
|
|
99
|
+
* @param {{ z: number, x: number, y: number }} coords
|
|
100
|
+
* @returns {Promise<Response>}
|
|
101
|
+
*/
|
|
102
|
+
async function applyCorrectedTile(request, layerConfig, coords) {
|
|
103
|
+
const { z, x, y } = coords;
|
|
104
|
+
const fixer = getTileFixer();
|
|
105
|
+
|
|
106
|
+
return fetchAndFixTile(request.url, z, x, y, fixer, layerConfig, tileSize);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Install event
|
|
110
|
+
self.addEventListener('install', (event) => {
|
|
111
|
+
self.skipWaiting();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Activate event
|
|
115
|
+
self.addEventListener('activate', (event) => {
|
|
116
|
+
event.waitUntil(self.clients.claim());
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Fetch event - intercept tile requests
|
|
120
|
+
self.addEventListener('fetch', (event) => {
|
|
121
|
+
const intercept = shouldIntercept(event.request);
|
|
122
|
+
|
|
123
|
+
if (intercept) {
|
|
124
|
+
event.respondWith(
|
|
125
|
+
applyCorrectedTile(event.request, intercept.layerConfig, intercept.coords)
|
|
126
|
+
.catch((error) => {
|
|
127
|
+
console.warn('[CorrectionSW] Error applying corrections:', error);
|
|
128
|
+
// Fallback to original request
|
|
129
|
+
return fetch(event.request);
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Message event - handle commands from main thread
|
|
136
|
+
self.addEventListener('message', (event) => {
|
|
137
|
+
const { type, ...data } = event.data;
|
|
138
|
+
const port = event.ports[0];
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
switch (type) {
|
|
142
|
+
case MessageTypes.ADD_LAYER_CONFIG:
|
|
143
|
+
// Reconstruct LayerConfig from plain object
|
|
144
|
+
const config = LayerConfig.fromJSON(data.layerConfig);
|
|
145
|
+
registry.register(config);
|
|
146
|
+
port?.postMessage({ success: true });
|
|
147
|
+
break;
|
|
148
|
+
|
|
149
|
+
case MessageTypes.REMOVE_LAYER_CONFIG:
|
|
150
|
+
const removed = registry.remove(data.configId);
|
|
151
|
+
port?.postMessage({ success: removed });
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
case MessageTypes.SET_PMTILES_URL:
|
|
155
|
+
pmtilesUrl = data.pmtilesUrl;
|
|
156
|
+
reinitTileFixer();
|
|
157
|
+
port?.postMessage({ success: true });
|
|
158
|
+
break;
|
|
159
|
+
|
|
160
|
+
case MessageTypes.SET_ENABLED:
|
|
161
|
+
enabled = data.enabled;
|
|
162
|
+
port?.postMessage({ success: true });
|
|
163
|
+
break;
|
|
164
|
+
|
|
165
|
+
case MessageTypes.CLEAR_CACHE:
|
|
166
|
+
tileFixer?.clearCache();
|
|
167
|
+
port?.postMessage({ success: true });
|
|
168
|
+
break;
|
|
169
|
+
|
|
170
|
+
case MessageTypes.RESET_CONFIG:
|
|
171
|
+
resetConfig();
|
|
172
|
+
port?.postMessage({ success: true });
|
|
173
|
+
break;
|
|
174
|
+
|
|
175
|
+
case MessageTypes.GET_STATUS:
|
|
176
|
+
port?.postMessage({
|
|
177
|
+
enabled,
|
|
178
|
+
pmtilesUrl: pmtilesUrl || getPmtilesUrl(),
|
|
179
|
+
configIds: registry.getAvailableIds(),
|
|
180
|
+
});
|
|
181
|
+
break;
|
|
182
|
+
|
|
183
|
+
default:
|
|
184
|
+
port?.postMessage({ error: `Unknown message type: ${type}` });
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
port?.postMessage({ error: error.message });
|
|
188
|
+
}
|
|
189
|
+
});
|