@india-boundary-corrector/maplibre-protocol 0.0.2 → 0.0.3
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/dist/index.cjs +37 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +43 -20
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +37 -17
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
- package/src/index.js +55 -23
package/dist/index.cjs
CHANGED
|
@@ -35,30 +35,50 @@ var import_tilefixer = require("@india-boundary-corrector/tilefixer");
|
|
|
35
35
|
var import_layer_configs2 = require("@india-boundary-corrector/layer-configs");
|
|
36
36
|
var import_data2 = require("@india-boundary-corrector/data");
|
|
37
37
|
var PROTOCOL_PREFIX = "ibc";
|
|
38
|
-
function
|
|
38
|
+
function extractTileCoordsFromUrl(url) {
|
|
39
|
+
try {
|
|
40
|
+
const urlObj = new URL(url);
|
|
41
|
+
const pathParts = urlObj.pathname.split("/").filter((p) => p.length > 0);
|
|
42
|
+
for (let i = pathParts.length - 1; i >= 2; i--) {
|
|
43
|
+
const yPart = pathParts[i].replace(/(@\d+x)?\.[^.]+$/, "");
|
|
44
|
+
const xPart = pathParts[i - 1];
|
|
45
|
+
const zPart = pathParts[i - 2];
|
|
46
|
+
if (/^\d+$/.test(zPart) && /^\d+$/.test(xPart) && /^\d+$/.test(yPart)) {
|
|
47
|
+
return {
|
|
48
|
+
z: parseInt(zPart, 10),
|
|
49
|
+
x: parseInt(xPart, 10),
|
|
50
|
+
y: parseInt(yPart, 10)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
function parseCorrectionsUrl(url, registry) {
|
|
39
59
|
const withoutProtocol = url.replace(`${PROTOCOL_PREFIX}://`, "");
|
|
40
60
|
let configId = null;
|
|
41
61
|
let tileUrl = withoutProtocol;
|
|
42
62
|
const atIndex = withoutProtocol.indexOf("@");
|
|
43
|
-
|
|
63
|
+
const slashIndex = withoutProtocol.indexOf("/");
|
|
64
|
+
if (atIndex > 0 && (slashIndex === -1 || atIndex < slashIndex)) {
|
|
44
65
|
configId = withoutProtocol.substring(0, atIndex);
|
|
45
66
|
tileUrl = withoutProtocol.substring(atIndex + 1);
|
|
46
67
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
const zPart = pathParts[i - 2];
|
|
54
|
-
if (/^\d+$/.test(zPart) && /^\d+$/.test(xPart) && /^\d+$/.test(yPart)) {
|
|
55
|
-
z = parseInt(zPart, 10);
|
|
56
|
-
x = parseInt(xPart, 10);
|
|
57
|
-
y = parseInt(yPart, 10);
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
68
|
+
let coords = null;
|
|
69
|
+
if (configId) {
|
|
70
|
+
coords = extractTileCoordsFromUrl(tileUrl);
|
|
71
|
+
} else {
|
|
72
|
+
const parsed = registry.parseTileUrl(tileUrl);
|
|
73
|
+
coords = parsed?.coords ?? null;
|
|
60
74
|
}
|
|
61
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
configId,
|
|
77
|
+
tileUrl,
|
|
78
|
+
z: coords?.z,
|
|
79
|
+
x: coords?.x,
|
|
80
|
+
y: coords?.y
|
|
81
|
+
};
|
|
62
82
|
}
|
|
63
83
|
async function fetchAndFixTile(tileUrl, z, x, y, tileFixer, layerConfig, tileSize, options = {}) {
|
|
64
84
|
const { data, correctionsFailed, correctionsError } = await tileFixer.fetchAndFixTile(
|
|
@@ -166,7 +186,7 @@ var CorrectionProtocol = class {
|
|
|
166
186
|
_createLoadFunction() {
|
|
167
187
|
const self = this;
|
|
168
188
|
return async (params, abortController) => {
|
|
169
|
-
const { configId, tileUrl, z, x, y } = parseCorrectionsUrl(params.url);
|
|
189
|
+
const { configId, tileUrl, z, x, y } = parseCorrectionsUrl(params.url, self._registry);
|
|
170
190
|
if (z === void 0 || x === void 0 || y === void 0) {
|
|
171
191
|
console.warn(`[CorrectionProtocol] Could not parse tile coordinates from URL: ${params.url}, falling back to original`);
|
|
172
192
|
const response = await fetch(tileUrl, { signal: abortController?.signal });
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"sourcesContent":["import { getPmtilesUrl } from '@india-boundary-corrector/data';\nimport { layerConfigs } from '@india-boundary-corrector/layer-configs';\nimport { BoundaryCorrector as TileFixer } from '@india-boundary-corrector/tilefixer';\n\n// Re-export for convenience\nexport { layerConfigs, LayerConfig } from '@india-boundary-corrector/layer-configs';\nexport { getPmtilesUrl } from '@india-boundary-corrector/data';\n\nconst PROTOCOL_PREFIX = 'ibc';\n\n/**\n * Parse an ibc:// URL.\n * Format: ibc://[configId@]originalUrl\n * Examples:\n * ibc://https://tile.openstreetmap.org/{z}/{x}/{y}.png\n * ibc://osm-carto@https://tile.openstreetmap.org/{z}/{x}/{y}.png\n * \n * @param {string} url - The full URL with ibc:// prefix\n * @returns {{ configId: string|null, tileUrl: string, z: number, x: number, y: number }}\n */\nfunction parseCorrectionsUrl(url) {\n // Remove protocol prefix\n const withoutProtocol = url.replace(`${PROTOCOL_PREFIX}://`, '');\n \n // Check for configId@url format\n let configId = null;\n let tileUrl = withoutProtocol;\n \n const atIndex = withoutProtocol.indexOf('@');\n if (atIndex > 0 && atIndex < withoutProtocol.indexOf('/')) {\n // Has configId prefix\n configId = withoutProtocol.substring(0, atIndex);\n tileUrl = withoutProtocol.substring(atIndex + 1);\n }\n \n // Extract z, x, y from the URL (assuming standard {z}/{x}/{y} pattern in the path)\n // The URL has already been templated by MapLibre, so we need to parse actual numbers\n const urlObj = new URL(tileUrl);\n const pathParts = urlObj.pathname.split('/').filter(p => p.length > 0);\n \n // Find z/x/y pattern - typically last 3 numeric segments\n let z, x, y;\n for (let i = pathParts.length - 1; i >= 2; i--) {\n const yPart = pathParts[i].replace(/\\.[^.]+$/, ''); // Remove extension\n const xPart = pathParts[i - 1];\n const zPart = pathParts[i - 2];\n \n if (/^\\d+$/.test(zPart) && /^\\d+$/.test(xPart) && /^\\d+$/.test(yPart)) {\n z = parseInt(zPart, 10);\n x = parseInt(xPart, 10);\n y = parseInt(yPart, 10);\n break;\n }\n }\n \n return { configId, tileUrl, z, x, y };\n}\n\n/**\n * Fetch and fix a tile for MapLibre protocol.\n * Extracted for testability.\n * @param {string} tileUrl - URL of the raster tile\n * @param {number} z - Zoom level\n * @param {number} x - Tile X coordinate\n * @param {number} y - Tile Y coordinate\n * @param {TileFixer} tileFixer - TileFixer instance\n * @param {Object} layerConfig - Layer configuration (can be null)\n * @param {number} tileSize - Tile size in pixels\n * @param {Object} [options] - Fetch options\n * @param {AbortSignal} [options.signal] - Abort signal\n * @returns {Promise<{data: ArrayBuffer, correctionsFailed: boolean, correctionsError: Error|null}>}\n */\nasync function fetchAndFixTile(tileUrl, z, x, y, tileFixer, layerConfig, tileSize, options = {}) {\n const { data, correctionsFailed, correctionsError } = await tileFixer.fetchAndFixTile(\n tileUrl, z, x, y, layerConfig, { tileSize, signal: options.signal }\n );\n return { data, correctionsFailed, correctionsError };\n}\n\n/**\n * India boundary corrections protocol for MapLibre GL.\n * \n * Usage:\n * const protocol = new CorrectionProtocol();\n * protocol.register(maplibregl);\n * \n * // In your style:\n * tiles: ['ibc://https://tile.openstreetmap.org/{z}/{x}/{y}.png']\n * // Or with explicit config:\n * tiles: ['ibc://osm-carto@https://tile.openstreetmap.org/{z}/{x}/{y}.png']\n */\nexport class CorrectionProtocol {\n /**\n * @param {Object} [options]\n * @param {string} [options.pmtilesUrl] - URL to PMTiles file (defaults to CDN)\n * @param {number} [options.tileSize=256] - Tile size in pixels\n */\n constructor(options = {}) {\n this._pmtilesUrl = options.pmtilesUrl ?? getPmtilesUrl();\n this._tileSize = options.tileSize ?? 256;\n this._tileFixer = new TileFixer(this._pmtilesUrl);\n this._registry = layerConfigs.createMergedRegistry();\n /** @type {Map<string, Set<Function>>} */\n this._listeners = new Map();\n \n this._loadFn = this._createLoadFunction();\n }\n\n /**\n * Add a listener for an event.\n * @param {'correctionerror'} event - Event name\n * @param {Function} listener - Callback function receiving event data\n * @returns {this}\n */\n on(event, listener) {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event).add(listener);\n return this;\n }\n\n /**\n * Remove an event listener.\n * @param {'correctionerror'} event - Event name\n * @param {Function} listener - Callback to remove\n * @returns {this}\n */\n off(event, listener) {\n this._listeners.get(event)?.delete(listener);\n return this;\n }\n\n /**\n * Emit an event to all listeners.\n * @param {string} event - Event name\n * @param {Object} data - Event data\n * @private\n */\n _emit(event, data) {\n this._listeners.get(event)?.forEach(fn => fn(data));\n }\n\n /**\n * Add a custom layer config to the registry.\n * @param {Object} layerConfig - LayerConfig to add\n * @returns {this}\n */\n addLayerConfig(layerConfig) {\n this._registry.register(layerConfig);\n return this;\n }\n\n /**\n * Get the registry.\n * @returns {LayerConfigRegistry}\n */\n getRegistry() {\n return this._registry;\n }\n\n /**\n * Get the TileFixer instance.\n * @returns {TileFixer}\n */\n getTileFixer() {\n return this._tileFixer;\n }\n\n /**\n * Register the protocol with MapLibre GL.\n * @param {typeof import('maplibre-gl')} maplibregl - MapLibre GL namespace\n * @returns {this}\n */\n register(maplibregl) {\n maplibregl.addProtocol(PROTOCOL_PREFIX, this._loadFn);\n return this;\n }\n\n /**\n * Unregister the protocol from MapLibre GL.\n * @param {typeof import('maplibre-gl')} maplibregl - MapLibre GL namespace\n * @returns {this}\n */\n unregister(maplibregl) {\n maplibregl.removeProtocol(PROTOCOL_PREFIX);\n return this;\n }\n\n /**\n * Create the protocol load function.\n * @returns {Function}\n * @private\n */\n _createLoadFunction() {\n const self = this;\n \n return async (params, abortController) => {\n const { configId, tileUrl, z, x, y } = parseCorrectionsUrl(params.url);\n \n // Validate parsed coordinates\n if (z === undefined || x === undefined || y === undefined) {\n console.warn(`[CorrectionProtocol] Could not parse tile coordinates from URL: ${params.url}, falling back to original`);\n const response = await fetch(tileUrl, { signal: abortController?.signal });\n return { data: await response.arrayBuffer() };\n }\n \n // Resolve layer config\n let layerConfig;\n if (configId) {\n layerConfig = self._registry.get(configId);\n } else {\n layerConfig = self._registry.detectFromTileUrls([tileUrl]);\n }\n \n try {\n const result = await fetchAndFixTile(\n tileUrl,\n z, \n x,\n y,\n self._tileFixer,\n layerConfig,\n self._tileSize,\n { signal: abortController?.signal }\n );\n \n if (result.correctionsFailed && result.correctionsError?.name !== 'AbortError') {\n console.warn('[CorrectionProtocol] Corrections fetch failed:', result.correctionsError);\n self._emit('correctionerror', { error: result.correctionsError, coords: { z, x, y }, tileUrl });\n }\n \n return { data: result.data };\n } catch (err) {\n // Don't catch AbortError - let it propagate\n if (err.name === 'AbortError') {\n throw err;\n }\n // Re-throw other errors (tile fetch failures, processing errors)\n // correctionerror is only for PMTiles/correction failures (handled via correctionsFailed)\n throw err;\n }\n };\n }\n}\n\n/**\n * Create and register a correction protocol with MapLibre GL.\n * \n * @param {typeof import('maplibre-gl')} maplibregl - MapLibre GL namespace\n * @param {Object} [options] - Protocol options\n * @param {string} [options.pmtilesUrl] - URL to PMTiles file\n * @param {number} [options.tileSize=256] - Tile size in pixels\n * @returns {CorrectionProtocol}\n * \n * @example\n * import maplibregl from 'maplibre-gl';\n * import { registerCorrectionProtocol } from '@india-boundary-corrector/maplibre-protocol';\n * \n * const protocol = registerCorrectionProtocol(maplibregl);\n * \n * // Use in style:\n * const map = new maplibregl.Map({\n * container: 'map',\n * style: {\n * sources: {\n * osm: {\n * type: 'raster',\n * tiles: ['ibc://https://tile.openstreetmap.org/{z}/{x}/{y}.png'],\n * tileSize: 256\n * }\n * },\n * layers: [{ id: 'osm', type: 'raster', source: 'osm' }]\n * }\n * });\n */\nexport function registerCorrectionProtocol(maplibregl, options = {}) {\n const protocol = new CorrectionProtocol(options);\n return protocol.register(maplibregl);\n}\n\n// Export for testing\nexport { parseCorrectionsUrl, fetchAndFixTile };\n"],"mappings":"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","names":["import_layer_configs","import_data","TileFixer"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"sourcesContent":["import { getPmtilesUrl } from '@india-boundary-corrector/data';\nimport { layerConfigs } from '@india-boundary-corrector/layer-configs';\nimport { BoundaryCorrector as TileFixer } from '@india-boundary-corrector/tilefixer';\n\n// Re-export for convenience\nexport { layerConfigs, LayerConfig } from '@india-boundary-corrector/layer-configs';\nexport { getPmtilesUrl } from '@india-boundary-corrector/data';\n\nconst PROTOCOL_PREFIX = 'ibc';\n\n/**\n * Extract tile coordinates from a URL using generic z/x/y pattern matching.\n * Handles standard tile URL patterns including retina suffixes (@2x, @3x, etc.).\n * \n * @param {string} url - The tile URL to parse\n * @returns {{ z: number, x: number, y: number } | null} Parsed coordinates or null if not found\n */\nfunction extractTileCoordsFromUrl(url) {\n try {\n const urlObj = new URL(url);\n const pathParts = urlObj.pathname.split('/').filter(p => p.length > 0);\n \n // Find z/x/y pattern - typically last 3 numeric segments\n for (let i = pathParts.length - 1; i >= 2; i--) {\n // Remove extension and retina suffix (e.g., \"5@2x.png\" -> \"5\")\n const yPart = pathParts[i].replace(/(@\\d+x)?\\.[^.]+$/, '');\n const xPart = pathParts[i - 1];\n const zPart = pathParts[i - 2];\n \n if (/^\\d+$/.test(zPart) && /^\\d+$/.test(xPart) && /^\\d+$/.test(yPart)) {\n return {\n z: parseInt(zPart, 10),\n x: parseInt(xPart, 10),\n y: parseInt(yPart, 10)\n };\n }\n }\n } catch {\n // Invalid URL\n }\n return null;\n}\n\n/**\n * Parse an ibc:// URL.\n * Format: ibc://[configId@]originalUrl\n * Examples:\n * ibc://https://tile.openstreetmap.org/{z}/{x}/{y}.png\n * ibc://osm-carto@https://tile.openstreetmap.org/{z}/{x}/{y}.png\n * \n * @param {string} url - The full URL with ibc:// prefix\n * @param {import('@india-boundary-corrector/layer-configs').LayerConfigRegistry} registry - Registry to use for parsing\n * @returns {{ configId: string|null, tileUrl: string, z: number|undefined, x: number|undefined, y: number|undefined }}\n */\nfunction parseCorrectionsUrl(url, registry) {\n // Remove protocol prefix\n const withoutProtocol = url.replace(`${PROTOCOL_PREFIX}://`, '');\n \n // Check for configId@url format\n let configId = null;\n let tileUrl = withoutProtocol;\n \n const atIndex = withoutProtocol.indexOf('@');\n const slashIndex = withoutProtocol.indexOf('/');\n // Config ID exists if @ comes before first / (or if there's no /)\n if (atIndex > 0 && (slashIndex === -1 || atIndex < slashIndex)) {\n // Has configId prefix\n configId = withoutProtocol.substring(0, atIndex);\n tileUrl = withoutProtocol.substring(atIndex + 1);\n }\n \n // If configId is explicit, use generic parsing (URL may not match config's patterns)\n // Otherwise, use registry detection only (unregistered URLs won't get corrections)\n let coords = null;\n if (configId) {\n coords = extractTileCoordsFromUrl(tileUrl);\n } else {\n const parsed = registry.parseTileUrl(tileUrl);\n coords = parsed?.coords ?? null;\n }\n \n return { \n configId, \n tileUrl, \n z: coords?.z, \n x: coords?.x, \n y: coords?.y \n };\n}\n\n/**\n * Fetch and fix a tile for MapLibre protocol.\n * Extracted for testability.\n * @param {string} tileUrl - URL of the raster tile\n * @param {number} z - Zoom level\n * @param {number} x - Tile X coordinate\n * @param {number} y - Tile Y coordinate\n * @param {TileFixer} tileFixer - TileFixer instance\n * @param {Object} layerConfig - Layer configuration (can be null)\n * @param {number} tileSize - Tile size in pixels\n * @param {Object} [options] - Fetch options\n * @param {AbortSignal} [options.signal] - Abort signal\n * @returns {Promise<{data: ArrayBuffer, correctionsFailed: boolean, correctionsError: Error|null}>}\n */\nasync function fetchAndFixTile(tileUrl, z, x, y, tileFixer, layerConfig, tileSize, options = {}) {\n const { data, correctionsFailed, correctionsError } = await tileFixer.fetchAndFixTile(\n tileUrl, z, x, y, layerConfig, { tileSize, signal: options.signal }\n );\n return { data, correctionsFailed, correctionsError };\n}\n\n/**\n * India boundary corrections protocol for MapLibre GL.\n * \n * Usage:\n * const protocol = new CorrectionProtocol();\n * protocol.register(maplibregl);\n * \n * // In your style:\n * tiles: ['ibc://https://tile.openstreetmap.org/{z}/{x}/{y}.png']\n * // Or with explicit config:\n * tiles: ['ibc://osm-carto@https://tile.openstreetmap.org/{z}/{x}/{y}.png']\n */\nexport class CorrectionProtocol {\n /**\n * @param {Object} [options]\n * @param {string} [options.pmtilesUrl] - URL to PMTiles file (defaults to CDN)\n * @param {number} [options.tileSize=256] - Tile size in pixels\n */\n constructor(options = {}) {\n this._pmtilesUrl = options.pmtilesUrl ?? getPmtilesUrl();\n this._tileSize = options.tileSize ?? 256;\n this._tileFixer = new TileFixer(this._pmtilesUrl);\n this._registry = layerConfigs.createMergedRegistry();\n /** @type {Map<string, Set<Function>>} */\n this._listeners = new Map();\n \n this._loadFn = this._createLoadFunction();\n }\n\n /**\n * Add a listener for an event.\n * @param {'correctionerror'} event - Event name\n * @param {Function} listener - Callback function receiving event data\n * @returns {this}\n */\n on(event, listener) {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event).add(listener);\n return this;\n }\n\n /**\n * Remove an event listener.\n * @param {'correctionerror'} event - Event name\n * @param {Function} listener - Callback to remove\n * @returns {this}\n */\n off(event, listener) {\n this._listeners.get(event)?.delete(listener);\n return this;\n }\n\n /**\n * Emit an event to all listeners.\n * @param {string} event - Event name\n * @param {Object} data - Event data\n * @private\n */\n _emit(event, data) {\n this._listeners.get(event)?.forEach(fn => fn(data));\n }\n\n /**\n * Add a custom layer config to the registry.\n * @param {Object} layerConfig - LayerConfig to add\n * @returns {this}\n */\n addLayerConfig(layerConfig) {\n this._registry.register(layerConfig);\n return this;\n }\n\n /**\n * Get the registry.\n * @returns {LayerConfigRegistry}\n */\n getRegistry() {\n return this._registry;\n }\n\n /**\n * Get the TileFixer instance.\n * @returns {TileFixer}\n */\n getTileFixer() {\n return this._tileFixer;\n }\n\n /**\n * Register the protocol with MapLibre GL.\n * @param {typeof import('maplibre-gl')} maplibregl - MapLibre GL namespace\n * @returns {this}\n */\n register(maplibregl) {\n maplibregl.addProtocol(PROTOCOL_PREFIX, this._loadFn);\n return this;\n }\n\n /**\n * Unregister the protocol from MapLibre GL.\n * @param {typeof import('maplibre-gl')} maplibregl - MapLibre GL namespace\n * @returns {this}\n */\n unregister(maplibregl) {\n maplibregl.removeProtocol(PROTOCOL_PREFIX);\n return this;\n }\n\n /**\n * Create the protocol load function.\n * @returns {Function}\n * @private\n */\n _createLoadFunction() {\n const self = this;\n \n return async (params, abortController) => {\n const { configId, tileUrl, z, x, y } = parseCorrectionsUrl(params.url, self._registry);\n \n // Validate parsed coordinates\n if (z === undefined || x === undefined || y === undefined) {\n console.warn(`[CorrectionProtocol] Could not parse tile coordinates from URL: ${params.url}, falling back to original`);\n const response = await fetch(tileUrl, { signal: abortController?.signal });\n return { data: await response.arrayBuffer() };\n }\n \n // Resolve layer config\n let layerConfig;\n if (configId) {\n layerConfig = self._registry.get(configId);\n } else {\n layerConfig = self._registry.detectFromTileUrls([tileUrl]);\n }\n \n try {\n const result = await fetchAndFixTile(\n tileUrl,\n z, \n x,\n y,\n self._tileFixer,\n layerConfig,\n self._tileSize,\n { signal: abortController?.signal }\n );\n \n if (result.correctionsFailed && result.correctionsError?.name !== 'AbortError') {\n console.warn('[CorrectionProtocol] Corrections fetch failed:', result.correctionsError);\n self._emit('correctionerror', { error: result.correctionsError, coords: { z, x, y }, tileUrl });\n }\n \n return { data: result.data };\n } catch (err) {\n // Don't catch AbortError - let it propagate\n if (err.name === 'AbortError') {\n throw err;\n }\n // Re-throw other errors (tile fetch failures, processing errors)\n // correctionerror is only for PMTiles/correction failures (handled via correctionsFailed)\n throw err;\n }\n };\n }\n}\n\n/**\n * Create and register a correction protocol with MapLibre GL.\n * \n * @param {typeof import('maplibre-gl')} maplibregl - MapLibre GL namespace\n * @param {Object} [options] - Protocol options\n * @param {string} [options.pmtilesUrl] - URL to PMTiles file\n * @param {number} [options.tileSize=256] - Tile size in pixels\n * @returns {CorrectionProtocol}\n * \n * @example\n * import maplibregl from 'maplibre-gl';\n * import { registerCorrectionProtocol } from '@india-boundary-corrector/maplibre-protocol';\n * \n * const protocol = registerCorrectionProtocol(maplibregl);\n * \n * // Use in style:\n * const map = new maplibregl.Map({\n * container: 'map',\n * style: {\n * sources: {\n * osm: {\n * type: 'raster',\n * tiles: ['ibc://https://tile.openstreetmap.org/{z}/{x}/{y}.png'],\n * tileSize: 256\n * }\n * },\n * layers: [{ id: 'osm', type: 'raster', source: 'osm' }]\n * }\n * });\n */\nexport function registerCorrectionProtocol(maplibregl, options = {}) {\n const protocol = new CorrectionProtocol(options);\n return protocol.register(maplibregl);\n}\n\n// Export for testing\nexport { parseCorrectionsUrl, fetchAndFixTile };\n"],"mappings":"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","names":["import_layer_configs","import_data","TileFixer"]}
|
package/dist/index.global.js
CHANGED
|
@@ -31,7 +31,7 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
// ../data/version.js
|
|
34
|
-
var packageVersion = "0.0.
|
|
34
|
+
var packageVersion = "0.0.3";
|
|
35
35
|
|
|
36
36
|
// ../data/index.js
|
|
37
37
|
var import_meta = {};
|
|
@@ -173,10 +173,10 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
173
173
|
let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
|
|
174
174
|
if (char === "{" || char === "}") return char;
|
|
175
175
|
return "\\" + char;
|
|
176
|
-
}).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{([a-z0-9])-([a-z0-9])\}/gi, (_2, start, end) => `(\\{${start}-${end}\\}|[a-z0-9]+)`).replace(/\{(z|x|y|s|r)\}/gi, (_2, name) => {
|
|
176
|
+
}).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{([a-z0-9])-([a-z0-9])\}/gi, (_2, start, end) => `(\\{${start}-${end}\\}|\\{s\\}|[a-z0-9]+)`).replace(/\{(z|x|y|s|r)\}/gi, (_2, name) => {
|
|
177
177
|
const lowerName = name.toLowerCase();
|
|
178
178
|
if (lowerName === "s") {
|
|
179
|
-
return "(\\{s\\}|[a-z0-9]+)";
|
|
179
|
+
return "(\\{s\\}|\\{[a-z0-9]-[a-z0-9]\\}|[a-z0-9]+)";
|
|
180
180
|
}
|
|
181
181
|
if (lowerName === "r") {
|
|
182
182
|
return "(\\{r\\}|@\\d+x)?";
|
|
@@ -210,6 +210,9 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
210
210
|
if (!id || typeof id !== "string") {
|
|
211
211
|
throw new Error("LayerConfig requires a non-empty string id");
|
|
212
212
|
}
|
|
213
|
+
if (id.includes("/")) {
|
|
214
|
+
throw new Error(`LayerConfig id cannot contain slashes: "${id}"`);
|
|
215
|
+
}
|
|
213
216
|
this.id = id;
|
|
214
217
|
this.startZoom = startZoom;
|
|
215
218
|
this.zoomThreshold = zoomThreshold;
|
|
@@ -2999,30 +3002,50 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
2999
3002
|
|
|
3000
3003
|
// src/index.js
|
|
3001
3004
|
var PROTOCOL_PREFIX = "ibc";
|
|
3002
|
-
function
|
|
3005
|
+
function extractTileCoordsFromUrl(url) {
|
|
3006
|
+
try {
|
|
3007
|
+
const urlObj = new URL(url);
|
|
3008
|
+
const pathParts = urlObj.pathname.split("/").filter((p) => p.length > 0);
|
|
3009
|
+
for (let i2 = pathParts.length - 1; i2 >= 2; i2--) {
|
|
3010
|
+
const yPart = pathParts[i2].replace(/(@\d+x)?\.[^.]+$/, "");
|
|
3011
|
+
const xPart = pathParts[i2 - 1];
|
|
3012
|
+
const zPart = pathParts[i2 - 2];
|
|
3013
|
+
if (/^\d+$/.test(zPart) && /^\d+$/.test(xPart) && /^\d+$/.test(yPart)) {
|
|
3014
|
+
return {
|
|
3015
|
+
z: parseInt(zPart, 10),
|
|
3016
|
+
x: parseInt(xPart, 10),
|
|
3017
|
+
y: parseInt(yPart, 10)
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
} catch {
|
|
3022
|
+
}
|
|
3023
|
+
return null;
|
|
3024
|
+
}
|
|
3025
|
+
function parseCorrectionsUrl(url, registry) {
|
|
3003
3026
|
const withoutProtocol = url.replace(`${PROTOCOL_PREFIX}://`, "");
|
|
3004
3027
|
let configId = null;
|
|
3005
3028
|
let tileUrl = withoutProtocol;
|
|
3006
3029
|
const atIndex = withoutProtocol.indexOf("@");
|
|
3007
|
-
|
|
3030
|
+
const slashIndex = withoutProtocol.indexOf("/");
|
|
3031
|
+
if (atIndex > 0 && (slashIndex === -1 || atIndex < slashIndex)) {
|
|
3008
3032
|
configId = withoutProtocol.substring(0, atIndex);
|
|
3009
3033
|
tileUrl = withoutProtocol.substring(atIndex + 1);
|
|
3010
3034
|
}
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
const
|
|
3016
|
-
|
|
3017
|
-
const zPart = pathParts[i2 - 2];
|
|
3018
|
-
if (/^\d+$/.test(zPart) && /^\d+$/.test(xPart) && /^\d+$/.test(yPart)) {
|
|
3019
|
-
z2 = parseInt(zPart, 10);
|
|
3020
|
-
x3 = parseInt(xPart, 10);
|
|
3021
|
-
y = parseInt(yPart, 10);
|
|
3022
|
-
break;
|
|
3023
|
-
}
|
|
3035
|
+
let coords = null;
|
|
3036
|
+
if (configId) {
|
|
3037
|
+
coords = extractTileCoordsFromUrl(tileUrl);
|
|
3038
|
+
} else {
|
|
3039
|
+
const parsed = registry.parseTileUrl(tileUrl);
|
|
3040
|
+
coords = parsed?.coords ?? null;
|
|
3024
3041
|
}
|
|
3025
|
-
return {
|
|
3042
|
+
return {
|
|
3043
|
+
configId,
|
|
3044
|
+
tileUrl,
|
|
3045
|
+
z: coords?.z,
|
|
3046
|
+
x: coords?.x,
|
|
3047
|
+
y: coords?.y
|
|
3048
|
+
};
|
|
3026
3049
|
}
|
|
3027
3050
|
async function fetchAndFixTile(tileUrl, z2, x3, y, tileFixer, layerConfig, tileSize, options = {}) {
|
|
3028
3051
|
const { data, correctionsFailed, correctionsError } = await tileFixer.fetchAndFixTile(
|
|
@@ -3130,7 +3153,7 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
3130
3153
|
_createLoadFunction() {
|
|
3131
3154
|
const self = this;
|
|
3132
3155
|
return async (params, abortController) => {
|
|
3133
|
-
const { configId, tileUrl, z: z2, x: x3, y } = parseCorrectionsUrl(params.url);
|
|
3156
|
+
const { configId, tileUrl, z: z2, x: x3, y } = parseCorrectionsUrl(params.url, self._registry);
|
|
3134
3157
|
if (z2 === void 0 || x3 === void 0 || y === void 0) {
|
|
3135
3158
|
console.warn(`[CorrectionProtocol] Could not parse tile coordinates from URL: ${params.url}, falling back to original`);
|
|
3136
3159
|
const response = await fetch(tileUrl, { signal: abortController?.signal });
|