@india-boundary-corrector/leaflet-layer 0.0.4 → 0.0.5

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 CHANGED
@@ -151,7 +151,166 @@ function templateToTemplateRegex(template) {
151
151
  });
152
152
  return new RegExp("^" + pattern + "(\\?.*)?$", "i");
153
153
  }
154
+ function isValidColor(color) {
155
+ if (typeof color !== "string" || !color.trim()) return false;
156
+ if (typeof CSS !== "undefined" && CSS.supports) {
157
+ return CSS.supports("color", color);
158
+ }
159
+ const trimmed = color.trim().toLowerCase();
160
+ if (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(trimmed)) return true;
161
+ if (/^(rgb|hsl)a?\(/.test(trimmed)) return true;
162
+ if (/^[a-z]+$/.test(trimmed)) return true;
163
+ return false;
164
+ }
165
+ var LineStyle = class _LineStyle {
166
+ /**
167
+ * Validate a LineStyle configuration object.
168
+ * @param {Object} obj - The object to validate
169
+ * @param {number} [index] - Optional index for error messages (when validating in an array)
170
+ * @throws {Error} If validation fails
171
+ */
172
+ static validateJSON(obj, index) {
173
+ const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
174
+ if (!obj || typeof obj !== "object") {
175
+ throw new Error(`${prefix}: must be an object`);
176
+ }
177
+ if (!obj.color || typeof obj.color !== "string") {
178
+ throw new Error(`${prefix}: color must be a non-empty string`);
179
+ }
180
+ if (!isValidColor(obj.color)) {
181
+ throw new Error(`${prefix}: color "${obj.color}" is not a valid CSS color`);
182
+ }
183
+ if (obj.widthFraction !== void 0 && (typeof obj.widthFraction !== "number" || obj.widthFraction <= 0)) {
184
+ throw new Error(`${prefix}: widthFraction must be a positive number`);
185
+ }
186
+ if (obj.dashArray !== void 0 && !Array.isArray(obj.dashArray)) {
187
+ throw new Error(`${prefix}: dashArray must be an array`);
188
+ }
189
+ if (obj.alpha !== void 0 && (typeof obj.alpha !== "number" || obj.alpha < 0 || obj.alpha > 1)) {
190
+ throw new Error(`${prefix}: alpha must be a number between 0 and 1`);
191
+ }
192
+ if (obj.startZoom !== void 0 && (typeof obj.startZoom !== "number" || obj.startZoom < 0)) {
193
+ throw new Error(`${prefix}: startZoom must be a non-negative number`);
194
+ }
195
+ if (obj.endZoom !== void 0 && (typeof obj.endZoom !== "number" || obj.endZoom < 0)) {
196
+ throw new Error(`${prefix}: endZoom must be a non-negative number`);
197
+ }
198
+ }
199
+ /**
200
+ * @param {Object} options
201
+ * @param {string} options.color - CSS color string
202
+ * @param {number} [options.widthFraction=1.0] - Multiplier for base line width
203
+ * @param {number[]} [options.dashArray] - Dash pattern for dashed lines
204
+ * @param {number} [options.alpha=1.0] - Opacity (0-1)
205
+ * @param {number} [options.startZoom] - Minimum zoom level for this style
206
+ * @param {number} [options.endZoom=Infinity] - Maximum zoom level for this style
207
+ */
208
+ constructor({ color, widthFraction = 1, dashArray, alpha = 1, startZoom, endZoom = Infinity }) {
209
+ this.color = color;
210
+ this.widthFraction = widthFraction;
211
+ this.dashArray = dashArray;
212
+ this.alpha = alpha;
213
+ this.startZoom = startZoom;
214
+ this.endZoom = endZoom;
215
+ }
216
+ /**
217
+ * Check if this style is active at the given zoom level.
218
+ * @param {number} z - Zoom level
219
+ * @returns {boolean}
220
+ */
221
+ isActiveAtZoom(z2) {
222
+ return z2 >= this.startZoom && z2 <= this.endZoom;
223
+ }
224
+ /**
225
+ * Serialize to plain object.
226
+ * @returns {Object}
227
+ */
228
+ toJSON() {
229
+ const obj = { color: this.color };
230
+ if (this.widthFraction !== 1) obj.widthFraction = this.widthFraction;
231
+ if (this.dashArray) obj.dashArray = this.dashArray;
232
+ if (this.alpha !== 1) obj.alpha = this.alpha;
233
+ if (this.startZoom !== void 0) obj.startZoom = this.startZoom;
234
+ if (this.endZoom !== Infinity) obj.endZoom = this.endZoom;
235
+ return obj;
236
+ }
237
+ /**
238
+ * Create from plain object with validation.
239
+ * @param {Object} obj
240
+ * @param {number} [defaultStartZoom=0] - Default startZoom if not specified
241
+ * @param {number} [index] - Optional index for error messages
242
+ * @returns {LineStyle}
243
+ */
244
+ static fromJSON(obj, defaultStartZoom = 0, index) {
245
+ _LineStyle.validateJSON(obj, index);
246
+ return new _LineStyle({
247
+ ...obj,
248
+ startZoom: obj.startZoom ?? defaultStartZoom
249
+ });
250
+ }
251
+ };
154
252
  var LayerConfig = class _LayerConfig {
253
+ /**
254
+ * Validate a LayerConfig configuration object.
255
+ * Also validates all lineStyles within the config.
256
+ * @param {Object} obj - The object to validate
257
+ * @throws {Error} If validation fails
258
+ */
259
+ static validateJSON(obj) {
260
+ if (!obj || typeof obj !== "object") {
261
+ throw new Error("LayerConfig: must be an object");
262
+ }
263
+ if (!obj.id || typeof obj.id !== "string") {
264
+ throw new Error("LayerConfig: id must be a non-empty string");
265
+ }
266
+ if (obj.id.includes("/")) {
267
+ throw new Error(`LayerConfig: id cannot contain slashes: "${obj.id}"`);
268
+ }
269
+ const id = obj.id;
270
+ if (obj.startZoom !== void 0 && (typeof obj.startZoom !== "number" || obj.startZoom < 0)) {
271
+ throw new Error(`LayerConfig "${id}": startZoom must be a non-negative number`);
272
+ }
273
+ if (obj.zoomThreshold !== void 0 && (typeof obj.zoomThreshold !== "number" || obj.zoomThreshold < 0)) {
274
+ throw new Error(`LayerConfig "${id}": zoomThreshold must be a non-negative number`);
275
+ }
276
+ const startZoom = obj.startZoom ?? 0;
277
+ const zoomThreshold = obj.zoomThreshold ?? 5;
278
+ if (startZoom > zoomThreshold) {
279
+ throw new Error(`LayerConfig "${id}": startZoom (${startZoom}) must be <= zoomThreshold (${zoomThreshold})`);
280
+ }
281
+ if (obj.lineWidthStops !== void 0) {
282
+ if (!obj.lineWidthStops || typeof obj.lineWidthStops !== "object" || Array.isArray(obj.lineWidthStops)) {
283
+ throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
284
+ }
285
+ const stopKeys = Object.keys(obj.lineWidthStops);
286
+ if (stopKeys.length < 2) {
287
+ throw new Error(`LayerConfig "${id}": lineWidthStops must have at least 2 entries`);
288
+ }
289
+ for (const key of stopKeys) {
290
+ const zoom = Number(key);
291
+ if (!Number.isInteger(zoom) || zoom < 0) {
292
+ throw new Error(`LayerConfig "${id}": lineWidthStops keys must be non-negative integers, got "${key}"`);
293
+ }
294
+ if (typeof obj.lineWidthStops[key] !== "number" || obj.lineWidthStops[key] <= 0) {
295
+ throw new Error(`LayerConfig "${id}": lineWidthStops values must be positive numbers`);
296
+ }
297
+ }
298
+ }
299
+ if (obj.lineStyles !== void 0) {
300
+ if (!Array.isArray(obj.lineStyles) || obj.lineStyles.length === 0) {
301
+ throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
302
+ }
303
+ for (let i2 = 0; i2 < obj.lineStyles.length; i2++) {
304
+ LineStyle.validateJSON(obj.lineStyles[i2], i2);
305
+ }
306
+ }
307
+ if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor <= 0)) {
308
+ throw new Error(`LayerConfig "${id}": delWidthFactor must be a positive number`);
309
+ }
310
+ if (obj.lineExtensionFactor !== void 0 && (typeof obj.lineExtensionFactor !== "number" || obj.lineExtensionFactor < 0)) {
311
+ throw new Error(`LayerConfig "${id}": lineExtensionFactor must be a non-negative number`);
312
+ }
313
+ }
155
314
  constructor({
156
315
  id,
157
316
  startZoom = 0,
@@ -174,66 +333,30 @@ var LayerConfig = class _LayerConfig {
174
333
  // Set to 0 to disable extension
175
334
  lineExtensionFactor = 0.5
176
335
  }) {
177
- if (!id || typeof id !== "string") {
178
- throw new Error("LayerConfig requires a non-empty string id");
179
- }
180
- if (id.includes("/")) {
181
- throw new Error(`LayerConfig id cannot contain slashes: "${id}"`);
182
- }
183
336
  this.id = id;
184
337
  this.startZoom = startZoom;
185
338
  this.zoomThreshold = zoomThreshold;
186
- if (startZoom > zoomThreshold) {
187
- throw new Error(`LayerConfig "${id}": startZoom (${startZoom}) must be <= zoomThreshold (${zoomThreshold})`);
188
- }
189
339
  const templates = Array.isArray(tileUrlTemplates) ? tileUrlTemplates : tileUrlTemplates ? [tileUrlTemplates] : [];
190
340
  this.tileUrlTemplates = templates;
191
341
  this._compiledPatterns = templates.map((t) => templateToRegex(t));
192
342
  this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
193
- if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
194
- throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
195
- }
196
- const stopKeys = Object.keys(lineWidthStops);
197
- if (stopKeys.length < 2) {
198
- throw new Error(`LayerConfig "${id}": lineWidthStops must have at least 2 entries`);
199
- }
200
- for (const key of stopKeys) {
201
- const zoom = Number(key);
202
- if (!Number.isInteger(zoom) || zoom < 0) {
203
- throw new Error(`LayerConfig "${id}": lineWidthStops keys must be non-negative integers, got "${key}"`);
204
- }
205
- if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
206
- throw new Error(`LayerConfig "${id}": lineWidthStops values must be positive numbers`);
207
- }
208
- }
209
343
  this.lineWidthStops = lineWidthStops;
210
- if (!Array.isArray(lineStyles) || lineStyles.length === 0) {
211
- throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
212
- }
213
- for (let i2 = 0; i2 < lineStyles.length; i2++) {
214
- const style = lineStyles[i2];
215
- if (!style || typeof style !== "object") {
216
- throw new Error(`LayerConfig "${id}": lineStyles[${i2}] must be an object`);
217
- }
218
- if (!style.color || typeof style.color !== "string") {
219
- throw new Error(`LayerConfig "${id}": lineStyles[${i2}].color must be a non-empty string`);
220
- }
221
- }
222
- this.lineStyles = lineStyles.map((style) => ({
223
- ...style,
224
- startZoom: style.startZoom ?? startZoom,
225
- endZoom: style.endZoom ?? Infinity
226
- }));
344
+ this.lineStyles = lineStyles.map(
345
+ (style) => style instanceof LineStyle ? style : new LineStyle({
346
+ ...style,
347
+ startZoom: style.startZoom ?? startZoom
348
+ })
349
+ );
227
350
  this.delWidthFactor = delWidthFactor;
228
351
  this.lineExtensionFactor = lineExtensionFactor;
229
352
  }
230
353
  /**
231
354
  * Get line styles active at a given zoom level
232
355
  * @param {number} z - Zoom level
233
- * @returns {Array<{color: string, widthFraction?: number, dashArray?: number[]}>}
356
+ * @returns {LineStyle[]}
234
357
  */
235
358
  getLineStylesForZoom(z2) {
236
- return this.lineStyles.filter((style) => z2 >= style.startZoom && z2 <= style.endZoom);
359
+ return this.lineStyles.filter((style) => style.isActiveAtZoom(z2));
237
360
  }
238
361
  /**
239
362
  * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
@@ -296,17 +419,19 @@ var LayerConfig = class _LayerConfig {
296
419
  zoomThreshold: this.zoomThreshold,
297
420
  tileUrlTemplates: this.tileUrlTemplates,
298
421
  lineWidthStops: this.lineWidthStops,
299
- lineStyles: this.lineStyles,
422
+ lineStyles: this.lineStyles.map((s) => s.toJSON()),
300
423
  delWidthFactor: this.delWidthFactor,
301
424
  lineExtensionFactor: this.lineExtensionFactor
302
425
  };
303
426
  }
304
427
  /**
305
- * Create a LayerConfig from a plain object (e.g., from postMessage)
428
+ * Create a LayerConfig from a plain object with validation.
306
429
  * @param {Object} obj
307
430
  * @returns {LayerConfig}
431
+ * @throws {Error} If validation fails
308
432
  */
309
433
  static fromJSON(obj) {
434
+ _LayerConfig.validateJSON(obj);
310
435
  return new _LayerConfig(obj);
311
436
  }
312
437
  };
@@ -2554,10 +2679,11 @@ var CorrectionsSource = class {
2554
2679
  * @param {number} z
2555
2680
  * @param {number} x
2556
2681
  * @param {number} y
2682
+ * @param {AbortSignal} [signal] - Optional abort signal
2557
2683
  * @returns {Promise<Object<string, Array>>}
2558
2684
  * @private
2559
2685
  */
2560
- async _fetchTile(z2, x22, y) {
2686
+ async _fetchTile(z2, x22, y, signal) {
2561
2687
  const idx = toIndex(z2, x22, y);
2562
2688
  return new Promise((resolve, reject) => {
2563
2689
  const entry = this.cache.get(idx);
@@ -2572,7 +2698,7 @@ var CorrectionsSource = class {
2572
2698
  return;
2573
2699
  }
2574
2700
  this.inflight.set(idx, []);
2575
- this.pmtiles.getZxy(z2, x22, y).then((result) => {
2701
+ this.pmtiles.getZxy(z2, x22, y, signal).then((result) => {
2576
2702
  let data;
2577
2703
  if (result) {
2578
2704
  data = parseTile(result.data);
@@ -2611,9 +2737,10 @@ var CorrectionsSource = class {
2611
2737
  * @param {number} z - Zoom level
2612
2738
  * @param {number} x - Tile X coordinate
2613
2739
  * @param {number} y - Tile Y coordinate
2740
+ * @param {AbortSignal} [signal] - Optional abort signal
2614
2741
  * @returns {Promise<Object<string, Array>>} Map of layer name to array of features
2615
2742
  */
2616
- async get(z2, x22, y) {
2743
+ async get(z2, x22, y, signal) {
2617
2744
  const maxDataZoom = await this._getMaxDataZoom();
2618
2745
  if (z2 > maxDataZoom) {
2619
2746
  const zoomDiff = z2 - maxDataZoom;
@@ -2622,13 +2749,13 @@ var CorrectionsSource = class {
2622
2749
  const parentY = Math.floor(y / scale);
2623
2750
  const offsetX = x22 % scale;
2624
2751
  const offsetY = y % scale;
2625
- const corrections = await this._fetchTile(maxDataZoom, parentX, parentY);
2752
+ const corrections = await this._fetchTile(maxDataZoom, parentX, parentY, signal);
2626
2753
  if (Object.keys(corrections).length > 0) {
2627
2754
  return transformForOverzoom(corrections, scale, offsetX, offsetY);
2628
2755
  }
2629
2756
  return {};
2630
2757
  }
2631
- return await this._fetchTile(z2, x22, y);
2758
+ return await this._fetchTile(z2, x22, y, signal);
2632
2759
  }
2633
2760
  };
2634
2761
  var TileFetchError = class _TileFetchError extends Error {
@@ -2659,6 +2786,25 @@ var TileFetchError = class _TileFetchError extends Error {
2659
2786
  }
2660
2787
  };
2661
2788
  var MIN_LINE_WIDTH = 0.5;
2789
+ var DEFAULT_TILE_EXTENT = 4096;
2790
+ var DEFAULT_LINE_WIDTH = 1;
2791
+ function buildFetchOptions(crossOrigin, referrerPolicy) {
2792
+ const options = {};
2793
+ if (crossOrigin === "use-credentials") {
2794
+ options.mode = "cors";
2795
+ options.credentials = "include";
2796
+ } else if (crossOrigin === "anonymous" || crossOrigin === "" || crossOrigin === true) {
2797
+ options.mode = "cors";
2798
+ options.credentials = "omit";
2799
+ } else {
2800
+ options.mode = "cors";
2801
+ options.credentials = "same-origin";
2802
+ }
2803
+ if (referrerPolicy) {
2804
+ options.referrerPolicy = referrerPolicy;
2805
+ }
2806
+ return options;
2807
+ }
2662
2808
  function getLineWidth(zoom, lineWidthStops) {
2663
2809
  const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
2664
2810
  if (lineWidthStops[zoom] !== void 0) {
@@ -2690,7 +2836,7 @@ function getLineWidth(zoom, lineWidthStops) {
2690
2836
  return w1 + t * (w2 - w1);
2691
2837
  }
2692
2838
  }
2693
- return 1;
2839
+ return DEFAULT_LINE_WIDTH;
2694
2840
  }
2695
2841
  function getFeaturesBoundingBox(features, tileSize, padding = 0) {
2696
2842
  let minX = Infinity, minY = Infinity;
@@ -2844,6 +2990,14 @@ function extendFeaturesEnds(features, extensionLength) {
2844
2990
  return { ...feature, geometry: newGeometry };
2845
2991
  });
2846
2992
  }
2993
+ function extendFeaturesByFactor(features, extensionFactor, delLineWidth, tileSize) {
2994
+ if (!features || features.length === 0 || extensionFactor <= 0) {
2995
+ return features;
2996
+ }
2997
+ const extent = features[0]?.extent || DEFAULT_TILE_EXTENT;
2998
+ const extensionLength = delLineWidth * extensionFactor / tileSize * extent;
2999
+ return extendFeaturesEnds(features, extensionLength);
3000
+ }
2847
3001
  function drawFeatures(ctx, features, color, lineWidth, tileSize, dashArray, alpha) {
2848
3002
  const prevAlpha = ctx.globalAlpha;
2849
3003
  if (alpha !== void 0) {
@@ -2907,6 +3061,7 @@ var _TileFixer = class _TileFixer2 {
2907
3061
  */
2908
3062
  constructor(pmtilesUrl, options = {}) {
2909
3063
  this.correctionsSource = new CorrectionsSource(pmtilesUrl, options);
3064
+ this._canvas = null;
2910
3065
  this._maskCanvas = null;
2911
3066
  }
2912
3067
  /**
@@ -2928,10 +3083,11 @@ var _TileFixer = class _TileFixer2 {
2928
3083
  * @param {number} z - Zoom level
2929
3084
  * @param {number} x - Tile X coordinate
2930
3085
  * @param {number} y - Tile Y coordinate
3086
+ * @param {AbortSignal} [signal] - Optional abort signal
2931
3087
  * @returns {Promise<Object<string, Array>>} Map of layer name to array of features
2932
3088
  */
2933
- async getCorrections(z2, x22, y) {
2934
- return await this.correctionsSource.get(z2, x22, y);
3089
+ async getCorrections(z2, x22, y, signal) {
3090
+ return await this.correctionsSource.get(z2, x22, y, signal);
2935
3091
  }
2936
3092
  /**
2937
3093
  * Apply corrections to a raster tile.
@@ -2975,7 +3131,7 @@ var _TileFixer = class _TileFixer2 {
2975
3131
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
2976
3132
  ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
2977
3133
  const baseLineWidth = getLineWidth(zoom, lineWidthStops);
2978
- const maxWidthFraction = activeLineStyles.length > 0 ? Math.max(...activeLineStyles.map((s) => s.widthFraction ?? 1)) : 1;
3134
+ const maxWidthFraction = activeLineStyles.length > 0 ? Math.max(...activeLineStyles.map((s) => s.widthFraction)) : 1;
2979
3135
  const delLineWidth = baseLineWidth * maxWidthFraction * delWidthFactor;
2980
3136
  const delFeatures = corrections[delLayerName] || [];
2981
3137
  if (delFeatures.length > 0) {
@@ -2986,14 +3142,11 @@ var _TileFixer = class _TileFixer2 {
2986
3142
  }
2987
3143
  let addFeatures = corrections[addLayerName] || [];
2988
3144
  if (addFeatures.length > 0 && activeLineStyles.length > 0) {
2989
- const extensionFactor = layerConfig.lineExtensionFactor ?? 0.5;
2990
- if (extensionFactor > 0 && delFeatures.length > 0) {
2991
- const extent = addFeatures[0]?.extent || 4096;
2992
- const extensionLength = delLineWidth * extensionFactor / tileSize * extent;
2993
- addFeatures = extendFeaturesEnds(addFeatures, extensionLength);
3145
+ if (delFeatures.length > 0) {
3146
+ addFeatures = extendFeaturesByFactor(addFeatures, layerConfig.lineExtensionFactor, delLineWidth, tileSize);
2994
3147
  }
2995
3148
  for (const style of activeLineStyles) {
2996
- const { color, widthFraction = 1, dashArray, alpha = 1 } = style;
3149
+ const { color, widthFraction, dashArray, alpha } = style;
2997
3150
  const lineWidth = baseLineWidth * widthFraction;
2998
3151
  drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
2999
3152
  }
@@ -3008,17 +3161,17 @@ var _TileFixer = class _TileFixer2 {
3008
3161
  * @param {number} x - Tile X coordinate
3009
3162
  * @param {number} y - Tile Y coordinate
3010
3163
  * @param {Object} layerConfig - Layer configuration with colors and styles
3011
- * @param {Object} [options] - Fetch options
3012
- * @param {AbortSignal} [options.signal] - Abort signal for fetch
3013
- * @param {RequestMode} [options.mode] - Fetch mode (e.g., 'cors')
3014
- * @param {boolean} [options.fallbackOnCorrectionFailure=true] - Return original tile if corrections fail
3164
+ * @param {Object} [fetchOptions] - Fetch options passed to fetch()
3165
+ * @param {AbortSignal} [fetchOptions.signal] - Abort signal for fetch
3166
+ * @param {RequestMode} [fetchOptions.mode] - Fetch mode (e.g., 'cors')
3167
+ * @param {RequestCredentials} [fetchOptions.credentials] - Fetch credentials (e.g., 'omit', 'include')
3168
+ * @param {string} [fetchOptions.referrer] - Referrer URL or empty string for none
3169
+ * @param {ReferrerPolicy} [fetchOptions.referrerPolicy] - Referrer policy (e.g., 'no-referrer', 'origin')
3170
+ * @param {boolean} [fallbackOnCorrectionFailure=true] - Return original tile if corrections fail
3015
3171
  * @returns {Promise<{data: ArrayBuffer, wasFixed: boolean}>}
3016
3172
  */
3017
- async fetchAndFixTile(tileUrl, z2, x22, y, layerConfig, options = {}) {
3018
- const { signal, mode, fallbackOnCorrectionFailure = true } = options;
3019
- const fetchOptions = {};
3020
- if (signal) fetchOptions.signal = signal;
3021
- if (mode) fetchOptions.mode = mode;
3173
+ async fetchAndFixTile(tileUrl, z2, x22, y, layerConfig, fetchOptions = {}, fallbackOnCorrectionFailure = true) {
3174
+ const { signal } = fetchOptions;
3022
3175
  if (!layerConfig) {
3023
3176
  const response = await fetch(tileUrl, fetchOptions);
3024
3177
  if (!response.ok) throw await TileFetchError.fromResponse(response);
@@ -3029,11 +3182,9 @@ var _TileFixer = class _TileFixer2 {
3029
3182
  if (!r.ok) throw await TileFetchError.fromResponse(r);
3030
3183
  return r.arrayBuffer();
3031
3184
  }),
3032
- this.getCorrections(z2, x22, y)
3185
+ this.getCorrections(z2, x22, y, signal)
3033
3186
  ]);
3034
- if (signal?.aborted) {
3035
- throw new DOMException("Aborted", "AbortError");
3036
- }
3187
+ signal?.throwIfAborted();
3037
3188
  if (tileResult.status === "rejected") {
3038
3189
  throw tileResult.reason;
3039
3190
  }
@@ -3087,6 +3238,9 @@ function extendLeaflet(L2) {
3087
3238
  },
3088
3239
  createTile: function(coords, done) {
3089
3240
  const tile = document.createElement("img");
3241
+ const controller = new AbortController();
3242
+ const signal = controller.signal;
3243
+ tile.cancel = () => controller.abort();
3090
3244
  tile.alt = "";
3091
3245
  if (this.options.crossOrigin || this.options.crossOrigin === "") {
3092
3246
  tile.crossOrigin = this.options.crossOrigin === true ? "" : this.options.crossOrigin;
@@ -3105,13 +3259,16 @@ function extendLeaflet(L2) {
3105
3259
  const x3 = coords.x;
3106
3260
  const y = coords.y;
3107
3261
  const fallbackOnCorrectionFailure = this.options.fallbackOnCorrectionFailure;
3108
- this._tileFixer.fetchAndFixTile(tileUrl, z2, x3, y, this._layerConfig, { fallbackOnCorrectionFailure }).then(({ data, correctionsFailed, correctionsError }) => {
3262
+ const fetchOptions = buildFetchOptions(this.options.crossOrigin, this.options.referrerPolicy);
3263
+ fetchOptions.signal = signal;
3264
+ this._tileFixer.fetchAndFixTile(tileUrl, z2, x3, y, this._layerConfig, fetchOptions, fallbackOnCorrectionFailure).then(({ data, correctionsFailed, correctionsError }) => {
3109
3265
  if (correctionsFailed) {
3110
3266
  console.warn("[L.TileLayer.IndiaBoundaryCorrected] Corrections fetch failed:", correctionsError);
3111
3267
  this.fire("correctionerror", { error: correctionsError, coords: { z: z2, x: x3, y }, tileUrl });
3112
3268
  }
3113
3269
  const blob = new Blob([data]);
3114
3270
  tile.src = URL.createObjectURL(blob);
3271
+ tile.cancel = void 0;
3115
3272
  tile.onload = () => {
3116
3273
  URL.revokeObjectURL(tile.src);
3117
3274
  done(null, tile);
@@ -3121,11 +3278,19 @@ function extendLeaflet(L2) {
3121
3278
  done(e, tile);
3122
3279
  };
3123
3280
  }).catch((err2) => {
3124
- console.warn("[L.TileLayer.IndiaBoundaryCorrected] Tile fetch failed:", err2);
3125
- done(err2, tile);
3281
+ if (err2.name !== "AbortError") {
3282
+ console.warn("[L.TileLayer.IndiaBoundaryCorrected] Tile fetch failed:", err2);
3283
+ done(err2, tile);
3284
+ }
3126
3285
  });
3127
3286
  return tile;
3128
3287
  },
3288
+ _removeTile: function(key) {
3289
+ const tile = this._tiles[key];
3290
+ if (!tile) return;
3291
+ if (tile.el.cancel) tile.el.cancel();
3292
+ L2.TileLayer.prototype._removeTile.call(this, key);
3293
+ },
3129
3294
  getTileFixer: function() {
3130
3295
  return this._tileFixer;
3131
3296
  },