@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
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var IndiaBoundaryCorrector = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.js
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
CorrectionServiceWorker: () => CorrectionServiceWorker,
|
|
25
|
+
LayerConfig: () => LayerConfig,
|
|
26
|
+
MessageTypes: () => MessageTypes,
|
|
27
|
+
getPmtilesUrl: () => getPmtilesUrl,
|
|
28
|
+
getWorkerImportSnippet: () => getWorkerImportSnippet,
|
|
29
|
+
layerConfigs: () => layerConfigs,
|
|
30
|
+
registerCorrectionServiceWorker: () => registerCorrectionServiceWorker
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// ../layer-configs/dist/index.js
|
|
34
|
+
var configs_default = [
|
|
35
|
+
{
|
|
36
|
+
id: "cartodb-dark",
|
|
37
|
+
zoomThreshold: 5,
|
|
38
|
+
tileUrlTemplates: [
|
|
39
|
+
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
40
|
+
"https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
41
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}{r}.png",
|
|
42
|
+
"https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
|
|
43
|
+
"https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
|
|
44
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png"
|
|
45
|
+
],
|
|
46
|
+
lineWidthStops: { "1": 0.5, "10": 2.5 },
|
|
47
|
+
lineStyles: [
|
|
48
|
+
{ color: "rgb(40, 40, 40)" }
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "cartodb-light",
|
|
53
|
+
startZoom: 0,
|
|
54
|
+
zoomThreshold: 5,
|
|
55
|
+
tileUrlTemplates: [
|
|
56
|
+
"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
57
|
+
"https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
58
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png",
|
|
59
|
+
"https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
|
|
60
|
+
"https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
|
|
61
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}{r}.png",
|
|
62
|
+
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
|
|
63
|
+
"https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
|
|
64
|
+
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
|
|
65
|
+
"https://basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
|
|
66
|
+
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
|
|
67
|
+
"https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
|
|
68
|
+
],
|
|
69
|
+
lineWidthStops: { "1": 0.25, "2": 0.25, "3": 0.5, "4": 0.75, "5": 1 },
|
|
70
|
+
lineStyles: [
|
|
71
|
+
{ color: "rgb(235, 214, 214)", alpha: 0.2, startZoom: 6, widthFraction: 5 },
|
|
72
|
+
{ color: "rgb(235, 214, 214)" }
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "open-topo",
|
|
77
|
+
startZoom: 4,
|
|
78
|
+
zoomThreshold: 4,
|
|
79
|
+
tileUrlTemplates: [
|
|
80
|
+
"https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
|
|
81
|
+
"https://tile.opentopomap.org/{z}/{x}/{y}.png"
|
|
82
|
+
],
|
|
83
|
+
lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
|
|
84
|
+
lineStyles: [
|
|
85
|
+
{ color: "rgb(83, 83, 83)", startZoom: 7, endZoom: 8, alpha: 0.4, widthFraction: 4 },
|
|
86
|
+
{ color: "rgb(83, 83, 83)", endZoom: 8 },
|
|
87
|
+
{ color: "rgb(140, 20, 180)", startZoom: 9, widthFraction: 9, alpha: 0.2 },
|
|
88
|
+
{ color: "rgb(140, 20, 180)", startZoom: 9 }
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: "osm-carto",
|
|
93
|
+
startZoom: 1,
|
|
94
|
+
zoomThreshold: 1,
|
|
95
|
+
tileUrlTemplates: [
|
|
96
|
+
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
97
|
+
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
98
|
+
],
|
|
99
|
+
lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
|
|
100
|
+
lineStyles: [
|
|
101
|
+
{ color: "rgb(200, 180, 200)" },
|
|
102
|
+
{ color: "rgb(160, 120, 160)", widthFraction: 0.333, dashArray: [30, 2, 8, 2] }
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "osm-hot",
|
|
107
|
+
startZoom: 2,
|
|
108
|
+
zoomThreshold: 2,
|
|
109
|
+
tileUrlTemplates: [
|
|
110
|
+
"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
|
|
111
|
+
],
|
|
112
|
+
lineWidthStops: { "2": 3, "3": 3, "7": 3, "8": 3.5, "9": 3.5 },
|
|
113
|
+
lineStyles: [
|
|
114
|
+
{ color: "rgb(149, 175, 180)" },
|
|
115
|
+
{ color: "rgb(89, 117, 123)", widthFraction: 0.33 }
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
];
|
|
119
|
+
function templateToRegex(template) {
|
|
120
|
+
const groups = [];
|
|
121
|
+
let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
|
|
122
|
+
if (char === "{" || char === "}") return char;
|
|
123
|
+
return "\\" + char;
|
|
124
|
+
}).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{[a-z0-9]-[a-z0-9]\}/gi, () => {
|
|
125
|
+
groups.push("s");
|
|
126
|
+
return "([a-z0-9]+)";
|
|
127
|
+
}).replace(/\{(z|x|y|s|r)\}/gi, (_, name) => {
|
|
128
|
+
const lowerName = name.toLowerCase();
|
|
129
|
+
groups.push(lowerName);
|
|
130
|
+
if (lowerName === "s") {
|
|
131
|
+
return "([a-z0-9]+)";
|
|
132
|
+
}
|
|
133
|
+
if (lowerName === "r") {
|
|
134
|
+
return "(@\\d+x)?";
|
|
135
|
+
}
|
|
136
|
+
return "(\\d+)";
|
|
137
|
+
});
|
|
138
|
+
return { pattern: new RegExp("^" + pattern + "(\\?.*)?$", "i"), groups };
|
|
139
|
+
}
|
|
140
|
+
function templateToTemplateRegex(template) {
|
|
141
|
+
let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
|
|
142
|
+
if (char === "{" || char === "}") return char;
|
|
143
|
+
return "\\" + char;
|
|
144
|
+
}).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{([a-z0-9])-([a-z0-9])\}/gi, (_, start, end) => `(\\{${start}-${end}\\}|[a-z0-9]+)`).replace(/\{(z|x|y|s|r)\}/gi, (_, name) => {
|
|
145
|
+
const lowerName = name.toLowerCase();
|
|
146
|
+
if (lowerName === "s") {
|
|
147
|
+
return "(\\{s\\}|[a-z0-9]+)";
|
|
148
|
+
}
|
|
149
|
+
if (lowerName === "r") {
|
|
150
|
+
return "(\\{r\\}|@\\d+x)?";
|
|
151
|
+
}
|
|
152
|
+
return `\\{${lowerName}\\}`;
|
|
153
|
+
});
|
|
154
|
+
return new RegExp("^" + pattern + "(\\?.*)?$", "i");
|
|
155
|
+
}
|
|
156
|
+
var LayerConfig = class _LayerConfig {
|
|
157
|
+
constructor({
|
|
158
|
+
id,
|
|
159
|
+
startZoom = 0,
|
|
160
|
+
zoomThreshold = 5,
|
|
161
|
+
// Tile URL templates for matching (e.g., "https://{s}.tile.example.com/{z}/{x}/{y}.png")
|
|
162
|
+
tileUrlTemplates = [],
|
|
163
|
+
// Line width stops: map of zoom level to line width (at least 2 entries)
|
|
164
|
+
lineWidthStops = { 1: 0.5, 10: 2.5 },
|
|
165
|
+
// Line styles array - each element describes a line to draw
|
|
166
|
+
// { color: string, widthFraction?: number, dashArray?: number[], startZoom?: number, endZoom?: number }
|
|
167
|
+
// Lines are drawn in array order. startZoom defaults to layerConfig startZoom, endZoom defaults to Infinity
|
|
168
|
+
lineStyles = [{ color: "green", widthFraction: 1 }],
|
|
169
|
+
// Factor to multiply line width for deletion blur (default 1.5)
|
|
170
|
+
// Higher values leave gaps where wiped lines meet existing lines
|
|
171
|
+
// Lower values mean wiped lines show through
|
|
172
|
+
delWidthFactor = 1.5,
|
|
173
|
+
// Factor to extend add lines by (multiplied by deletion line width)
|
|
174
|
+
// Helps cover gaps where deleted lines meet the new boundary
|
|
175
|
+
// Set to 0 to disable extension
|
|
176
|
+
lineExtensionFactor = 0.5
|
|
177
|
+
}) {
|
|
178
|
+
if (!id || typeof id !== "string") {
|
|
179
|
+
throw new Error("LayerConfig requires a non-empty string id");
|
|
180
|
+
}
|
|
181
|
+
this.id = id;
|
|
182
|
+
this.startZoom = startZoom;
|
|
183
|
+
this.zoomThreshold = zoomThreshold;
|
|
184
|
+
if (startZoom > zoomThreshold) {
|
|
185
|
+
throw new Error(`LayerConfig "${id}": startZoom (${startZoom}) must be <= zoomThreshold (${zoomThreshold})`);
|
|
186
|
+
}
|
|
187
|
+
const templates = Array.isArray(tileUrlTemplates) ? tileUrlTemplates : tileUrlTemplates ? [tileUrlTemplates] : [];
|
|
188
|
+
this.tileUrlTemplates = templates;
|
|
189
|
+
this._compiledPatterns = templates.map((t) => templateToRegex(t));
|
|
190
|
+
this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
|
|
191
|
+
if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
|
|
192
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
|
|
193
|
+
}
|
|
194
|
+
const stopKeys = Object.keys(lineWidthStops);
|
|
195
|
+
if (stopKeys.length < 2) {
|
|
196
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops must have at least 2 entries`);
|
|
197
|
+
}
|
|
198
|
+
for (const key of stopKeys) {
|
|
199
|
+
const zoom = Number(key);
|
|
200
|
+
if (!Number.isInteger(zoom) || zoom < 0) {
|
|
201
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops keys must be non-negative integers, got "${key}"`);
|
|
202
|
+
}
|
|
203
|
+
if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
|
|
204
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops values must be positive numbers`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
this.lineWidthStops = lineWidthStops;
|
|
208
|
+
if (!Array.isArray(lineStyles) || lineStyles.length === 0) {
|
|
209
|
+
throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
|
|
210
|
+
}
|
|
211
|
+
for (let i = 0; i < lineStyles.length; i++) {
|
|
212
|
+
const style = lineStyles[i];
|
|
213
|
+
if (!style || typeof style !== "object") {
|
|
214
|
+
throw new Error(`LayerConfig "${id}": lineStyles[${i}] must be an object`);
|
|
215
|
+
}
|
|
216
|
+
if (!style.color || typeof style.color !== "string") {
|
|
217
|
+
throw new Error(`LayerConfig "${id}": lineStyles[${i}].color must be a non-empty string`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
this.lineStyles = lineStyles.map((style) => ({
|
|
221
|
+
...style,
|
|
222
|
+
startZoom: style.startZoom ?? startZoom,
|
|
223
|
+
endZoom: style.endZoom ?? Infinity
|
|
224
|
+
}));
|
|
225
|
+
this.delWidthFactor = delWidthFactor;
|
|
226
|
+
this.lineExtensionFactor = lineExtensionFactor;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get line styles active at a given zoom level
|
|
230
|
+
* @param {number} z - Zoom level
|
|
231
|
+
* @returns {Array<{color: string, widthFraction?: number, dashArray?: number[]}>}
|
|
232
|
+
*/
|
|
233
|
+
getLineStylesForZoom(z) {
|
|
234
|
+
return this.lineStyles.filter((style) => z >= style.startZoom && z <= style.endZoom);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
|
|
238
|
+
* @param {string | string[]} templates - Single template URL or array of template URLs
|
|
239
|
+
* @returns {boolean}
|
|
240
|
+
*/
|
|
241
|
+
matchTemplate(templates) {
|
|
242
|
+
if (this._templatePatterns.length === 0) return false;
|
|
243
|
+
const urls = Array.isArray(templates) ? templates : [templates];
|
|
244
|
+
if (urls.length === 0) return false;
|
|
245
|
+
return urls.some(
|
|
246
|
+
(url) => this._templatePatterns.some((pattern) => pattern.test(url))
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Check if this config matches the given tile URLs (with actual coordinates)
|
|
251
|
+
* @param {string | string[]} tiles - Single tile URL or array of tile URLs
|
|
252
|
+
* @returns {boolean}
|
|
253
|
+
*/
|
|
254
|
+
matchTileUrl(tiles) {
|
|
255
|
+
if (this._compiledPatterns.length === 0) return false;
|
|
256
|
+
const urls = Array.isArray(tiles) ? tiles : [tiles];
|
|
257
|
+
if (urls.length === 0) return false;
|
|
258
|
+
return urls.some(
|
|
259
|
+
(url) => this._compiledPatterns.some(({ pattern }) => pattern.test(url))
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Extract tile coordinates (z, x, y) from a URL using this config's templates
|
|
264
|
+
* @param {string} url - Tile URL to extract coordinates from
|
|
265
|
+
* @returns {{ z: number, x: number, y: number } | null}
|
|
266
|
+
*/
|
|
267
|
+
extractCoords(url) {
|
|
268
|
+
for (const { pattern, groups } of this._compiledPatterns) {
|
|
269
|
+
const match = url.match(pattern);
|
|
270
|
+
if (match) {
|
|
271
|
+
const result = {};
|
|
272
|
+
for (let i = 0; i < groups.length; i++) {
|
|
273
|
+
const name = groups[i];
|
|
274
|
+
const value = match[i + 1];
|
|
275
|
+
if (name === "z" || name === "x" || name === "y") {
|
|
276
|
+
result[name] = parseInt(value, 10);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if ("z" in result && "x" in result && "y" in result) {
|
|
280
|
+
return { z: result.z, x: result.x, y: result.y };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Serialize the config to a plain object for postMessage
|
|
288
|
+
* @returns {Object}
|
|
289
|
+
*/
|
|
290
|
+
toJSON() {
|
|
291
|
+
return {
|
|
292
|
+
id: this.id,
|
|
293
|
+
startZoom: this.startZoom,
|
|
294
|
+
zoomThreshold: this.zoomThreshold,
|
|
295
|
+
tileUrlTemplates: this.tileUrlTemplates,
|
|
296
|
+
lineWidthStops: this.lineWidthStops,
|
|
297
|
+
lineStyles: this.lineStyles,
|
|
298
|
+
delWidthFactor: this.delWidthFactor,
|
|
299
|
+
lineExtensionFactor: this.lineExtensionFactor
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Create a LayerConfig from a plain object (e.g., from postMessage)
|
|
304
|
+
* @param {Object} obj
|
|
305
|
+
* @returns {LayerConfig}
|
|
306
|
+
*/
|
|
307
|
+
static fromJSON(obj) {
|
|
308
|
+
return new _LayerConfig(obj);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
var LayerConfigRegistry = class _LayerConfigRegistry {
|
|
312
|
+
constructor() {
|
|
313
|
+
this.registry = {};
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get a layer config by id
|
|
317
|
+
*/
|
|
318
|
+
get(id) {
|
|
319
|
+
return this.registry[id];
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Register a new layer config
|
|
323
|
+
*/
|
|
324
|
+
register(config) {
|
|
325
|
+
this.registry[config.id] = config;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Remove a layer config by id
|
|
329
|
+
*/
|
|
330
|
+
remove(id) {
|
|
331
|
+
if (!this.registry[id]) return false;
|
|
332
|
+
delete this.registry[id];
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Detect layer config from tile URL templates (with {z}/{x}/{y} placeholders)
|
|
337
|
+
* @param {string | string[]} templates - Single template URL or array of template URLs
|
|
338
|
+
*/
|
|
339
|
+
detectFromTemplates(templates) {
|
|
340
|
+
if (!templates || Array.isArray(templates) && templates.length === 0) return void 0;
|
|
341
|
+
for (const config of Object.values(this.registry)) {
|
|
342
|
+
if (config.matchTemplate(templates)) {
|
|
343
|
+
return config;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return void 0;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Detect layer config from actual tile URLs (with numeric coordinates)
|
|
350
|
+
* @param {string | string[]} urls - Single tile URL or array of tile URLs
|
|
351
|
+
*/
|
|
352
|
+
detectFromTileUrls(urls) {
|
|
353
|
+
if (!urls || Array.isArray(urls) && urls.length === 0) return void 0;
|
|
354
|
+
for (const config of Object.values(this.registry)) {
|
|
355
|
+
if (config.matchTileUrl(urls)) {
|
|
356
|
+
return config;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return void 0;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Get all available layer config ids
|
|
363
|
+
*/
|
|
364
|
+
getAvailableIds() {
|
|
365
|
+
return Object.keys(this.registry);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Create a new registry with all configs from this registry plus extra configs.
|
|
369
|
+
* @param {LayerConfig[]} extraLayerConfigs - Additional configs to add
|
|
370
|
+
* @returns {LayerConfigRegistry} A new registry with merged configs
|
|
371
|
+
*/
|
|
372
|
+
createMergedRegistry(extraLayerConfigs) {
|
|
373
|
+
const registry = new _LayerConfigRegistry();
|
|
374
|
+
for (const id of this.getAvailableIds()) {
|
|
375
|
+
registry.register(this.get(id));
|
|
376
|
+
}
|
|
377
|
+
if (extraLayerConfigs && extraLayerConfigs.length > 0) {
|
|
378
|
+
for (const config of extraLayerConfigs) {
|
|
379
|
+
registry.register(config);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return registry;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Parse a tile URL into its components: layer config and coordinates
|
|
386
|
+
* @param {string} url - Tile URL to parse
|
|
387
|
+
* @returns {{ layerConfig: LayerConfig, coords: { z: number, x: number, y: number } } | null}
|
|
388
|
+
*/
|
|
389
|
+
parseTileUrl(url) {
|
|
390
|
+
const layerConfig = this.detectFromTileUrls([url]);
|
|
391
|
+
if (!layerConfig) return null;
|
|
392
|
+
const coords = layerConfig.extractCoords(url);
|
|
393
|
+
if (!coords) return null;
|
|
394
|
+
return { layerConfig, coords };
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
var layerConfigs = new LayerConfigRegistry();
|
|
398
|
+
for (const configData of configs_default) {
|
|
399
|
+
layerConfigs.register(new LayerConfig(configData));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// ../data/version.js
|
|
403
|
+
var packageVersion = "0.0.1";
|
|
404
|
+
|
|
405
|
+
// ../data/index.js
|
|
406
|
+
var import_meta = {};
|
|
407
|
+
var PACKAGE_NAME = "@india-boundary-corrector/data";
|
|
408
|
+
var PMTILES_FILENAME = "india_boundary_corrections.pmtiles";
|
|
409
|
+
var DEFAULT_CDN_URL = `https://unpkg.com/${PACKAGE_NAME}@${packageVersion}/${PMTILES_FILENAME}`;
|
|
410
|
+
function detectPmtilesUrl() {
|
|
411
|
+
try {
|
|
412
|
+
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
413
|
+
const moduleUrl = new URL(".", import_meta.url);
|
|
414
|
+
return new URL(PMTILES_FILENAME, moduleUrl).href;
|
|
415
|
+
}
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
return DEFAULT_CDN_URL;
|
|
419
|
+
}
|
|
420
|
+
var cachedPmtilesUrl = null;
|
|
421
|
+
function getPmtilesUrl() {
|
|
422
|
+
if (cachedPmtilesUrl === null) {
|
|
423
|
+
cachedPmtilesUrl = detectPmtilesUrl();
|
|
424
|
+
}
|
|
425
|
+
return cachedPmtilesUrl;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// src/index.js
|
|
429
|
+
var MessageTypes = {
|
|
430
|
+
ADD_LAYER_CONFIG: "ADD_LAYER_CONFIG",
|
|
431
|
+
REMOVE_LAYER_CONFIG: "REMOVE_LAYER_CONFIG",
|
|
432
|
+
SET_PMTILES_URL: "SET_PMTILES_URL",
|
|
433
|
+
SET_ENABLED: "SET_ENABLED",
|
|
434
|
+
CLEAR_CACHE: "CLEAR_CACHE",
|
|
435
|
+
GET_STATUS: "GET_STATUS",
|
|
436
|
+
RESET_CONFIG: "RESET_CONFIG"
|
|
437
|
+
};
|
|
438
|
+
var CorrectionServiceWorker = class {
|
|
439
|
+
/**
|
|
440
|
+
* @param {string} workerUrl - URL to the service worker script
|
|
441
|
+
* @param {Object} [options]
|
|
442
|
+
* @param {string} [options.scope] - Service worker scope (defaults to workerUrl directory)
|
|
443
|
+
* @param {string} [options.pmtilesUrl] - PMTiles URL to set after registration
|
|
444
|
+
* @param {number} [options.controllerTimeout=3000] - Timeout in ms to wait for SW to take control
|
|
445
|
+
*/
|
|
446
|
+
constructor(workerUrl, options = {}) {
|
|
447
|
+
this._workerUrl = workerUrl;
|
|
448
|
+
this._scope = options.scope;
|
|
449
|
+
this._pmtilesUrl = options.pmtilesUrl;
|
|
450
|
+
this._controllerTimeout = options.controllerTimeout ?? 3e3;
|
|
451
|
+
this._registration = null;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Register the service worker and wait for it to take control.
|
|
455
|
+
* @returns {Promise<CorrectionServiceWorker>} Returns this instance for chaining
|
|
456
|
+
* @throws {Error} If service workers not supported or registration fails
|
|
457
|
+
*/
|
|
458
|
+
async register() {
|
|
459
|
+
if (!("serviceWorker" in navigator)) {
|
|
460
|
+
throw new Error("Service workers not supported");
|
|
461
|
+
}
|
|
462
|
+
const regOptions = this._scope ? { scope: this._scope } : void 0;
|
|
463
|
+
this._registration = await navigator.serviceWorker.register(
|
|
464
|
+
this._workerUrl,
|
|
465
|
+
regOptions
|
|
466
|
+
);
|
|
467
|
+
await navigator.serviceWorker.ready;
|
|
468
|
+
if (!navigator.serviceWorker.controller) {
|
|
469
|
+
await this._waitForController();
|
|
470
|
+
}
|
|
471
|
+
await this.resetConfig();
|
|
472
|
+
if (this._pmtilesUrl) {
|
|
473
|
+
await this.setPmtilesUrl(this._pmtilesUrl);
|
|
474
|
+
}
|
|
475
|
+
return this;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Wait for the service worker to take control of the page.
|
|
479
|
+
* @returns {Promise<void>}
|
|
480
|
+
* @private
|
|
481
|
+
*/
|
|
482
|
+
async _waitForController() {
|
|
483
|
+
return new Promise((resolve) => {
|
|
484
|
+
const onControllerChange = () => {
|
|
485
|
+
navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange);
|
|
486
|
+
resolve();
|
|
487
|
+
};
|
|
488
|
+
navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
|
|
489
|
+
setTimeout(resolve, this._controllerTimeout);
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Check if the service worker is controlling the page.
|
|
494
|
+
* @returns {boolean}
|
|
495
|
+
*/
|
|
496
|
+
isControlling() {
|
|
497
|
+
return !!navigator.serviceWorker.controller;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Unregister the service worker.
|
|
501
|
+
* @returns {Promise<boolean>}
|
|
502
|
+
*/
|
|
503
|
+
async unregister() {
|
|
504
|
+
if (this._registration) {
|
|
505
|
+
return this._registration.unregister();
|
|
506
|
+
}
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Get the active service worker.
|
|
511
|
+
* @returns {ServiceWorker|null}
|
|
512
|
+
*/
|
|
513
|
+
getWorker() {
|
|
514
|
+
return this._registration?.active ?? navigator.serviceWorker.controller;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Send a message to the service worker.
|
|
518
|
+
* @param {Object} message
|
|
519
|
+
* @returns {Promise<any>}
|
|
520
|
+
*/
|
|
521
|
+
async sendMessage(message) {
|
|
522
|
+
const worker = this.getWorker();
|
|
523
|
+
if (!worker) {
|
|
524
|
+
throw new Error("Service worker not active");
|
|
525
|
+
}
|
|
526
|
+
return new Promise((resolve, reject) => {
|
|
527
|
+
const channel = new MessageChannel();
|
|
528
|
+
channel.port1.onmessage = (event) => {
|
|
529
|
+
if (event.data.error) {
|
|
530
|
+
reject(new Error(event.data.error));
|
|
531
|
+
} else {
|
|
532
|
+
resolve(event.data);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
worker.postMessage(message, [channel.port2]);
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Add a layer config to the service worker.
|
|
540
|
+
* @param {Object} layerConfig
|
|
541
|
+
* @returns {Promise<void>}
|
|
542
|
+
*/
|
|
543
|
+
async addLayerConfig(layerConfig) {
|
|
544
|
+
const serialized = typeof layerConfig.toJSON === "function" ? layerConfig.toJSON() : layerConfig;
|
|
545
|
+
await this.sendMessage({
|
|
546
|
+
type: MessageTypes.ADD_LAYER_CONFIG,
|
|
547
|
+
layerConfig: serialized
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Remove a layer config from the service worker.
|
|
552
|
+
* @param {string} configId
|
|
553
|
+
* @returns {Promise<void>}
|
|
554
|
+
*/
|
|
555
|
+
async removeLayerConfig(configId) {
|
|
556
|
+
await this.sendMessage({
|
|
557
|
+
type: MessageTypes.REMOVE_LAYER_CONFIG,
|
|
558
|
+
configId
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Set the PMTiles URL.
|
|
563
|
+
* @param {string} pmtilesUrl
|
|
564
|
+
* @returns {Promise<void>}
|
|
565
|
+
*/
|
|
566
|
+
async setPmtilesUrl(pmtilesUrl) {
|
|
567
|
+
await this.sendMessage({
|
|
568
|
+
type: MessageTypes.SET_PMTILES_URL,
|
|
569
|
+
pmtilesUrl
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Enable or disable the correction service.
|
|
574
|
+
* @param {boolean} enabled
|
|
575
|
+
* @returns {Promise<void>}
|
|
576
|
+
*/
|
|
577
|
+
async setEnabled(enabled) {
|
|
578
|
+
await this.sendMessage({
|
|
579
|
+
type: MessageTypes.SET_ENABLED,
|
|
580
|
+
enabled
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Clear the tile cache.
|
|
585
|
+
* @returns {Promise<void>}
|
|
586
|
+
*/
|
|
587
|
+
async clearCache() {
|
|
588
|
+
await this.sendMessage({
|
|
589
|
+
type: MessageTypes.CLEAR_CACHE
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Get the status of the service worker.
|
|
594
|
+
* @returns {Promise<Object>}
|
|
595
|
+
*/
|
|
596
|
+
async getStatus() {
|
|
597
|
+
return this.sendMessage({
|
|
598
|
+
type: MessageTypes.GET_STATUS
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Reset the service worker configuration to defaults.
|
|
603
|
+
* Resets pmtilesUrl to default and restores default layer configs.
|
|
604
|
+
* @returns {Promise<void>}
|
|
605
|
+
*/
|
|
606
|
+
async resetConfig() {
|
|
607
|
+
await this.sendMessage({
|
|
608
|
+
type: MessageTypes.RESET_CONFIG
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
async function registerCorrectionServiceWorker(workerUrl, options = {}) {
|
|
613
|
+
const sw = new CorrectionServiceWorker(workerUrl, options);
|
|
614
|
+
await sw.register();
|
|
615
|
+
return sw;
|
|
616
|
+
}
|
|
617
|
+
function getWorkerImportSnippet(workerGlobalUrl) {
|
|
618
|
+
return `importScripts('${workerGlobalUrl}');`;
|
|
619
|
+
}
|
|
620
|
+
return __toCommonJS(index_exports);
|
|
621
|
+
})();
|
|
622
|
+
//# sourceMappingURL=index.global.js.map
|