{"version":3,"sources":["../src/index.js"],"sourcesContent":["import { getPmtilesUrl } from '@india-boundary-corrector/data';\nimport { layerConfigs } from '@india-boundary-corrector/layer-configs';\nimport { 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 * 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 {boolean} [options.fallbackOnCorrectionFailure=true] - Return original tile if corrections fail\n   */\n  constructor(options = {}) {\n    this._pmtilesUrl = options.pmtilesUrl ?? getPmtilesUrl();\n    this._fallbackOnCorrectionFailure = options.fallbackOnCorrectionFailure ?? true;\n    this._tileFixer = TileFixer.getOrCreate(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      // Build fetch options from request parameters\n      // MapLibre's default is same-origin for credentials\n      const fetchOptions = {\n        signal: abortController?.signal,\n        credentials: params.credentials ?? 'same-origin',\n      };\n      // Set mode to cors if credentials are explicitly set to include\n      if (params.credentials === 'include') {\n        fetchOptions.mode = 'cors';\n      }\n      \n      const { data, correctionsFailed, correctionsError } = await self._tileFixer.fetchAndFixTile(\n        tileUrl, z, x, y, layerConfig, fetchOptions, self._fallbackOnCorrectionFailure\n      );\n      \n      if (correctionsFailed && correctionsError?.name !== 'AbortError') {\n        console.warn('[CorrectionProtocol] Corrections fetch failed:', correctionsError);\n        self._emit('correctionerror', { error: correctionsError, coords: { z, x, y }, tileUrl });\n      }\n      \n      return { data };\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 {boolean} [options.fallbackOnCorrectionFailure=true] - Return original tile if corrections fail\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 *         attribution: '© OpenStreetMap contributors'\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 };\n"],"mappings":"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","names":["import_layer_configs","import_data"]}