@india-boundary-corrector/tilefixer 0.0.3 → 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/README.md CHANGED
@@ -13,12 +13,12 @@ npm install @india-boundary-corrector/tilefixer
13
13
  ## Usage
14
14
 
15
15
  ```javascript
16
- import { BoundaryCorrector } from '@india-boundary-corrector/tilefixer';
16
+ import { TileFixer } from '@india-boundary-corrector/tilefixer';
17
17
  import { getPmtilesUrl } from '@india-boundary-corrector/data';
18
18
  import { layerConfigs } from '@india-boundary-corrector/layer-configs';
19
19
 
20
20
  // Create a boundary corrector
21
- const corrector = new BoundaryCorrector(getPmtilesUrl());
21
+ const corrector = new TileFixer(getPmtilesUrl());
22
22
 
23
23
  // Get corrections for a tile
24
24
  const corrections = await corrector.getCorrections(z, x, y);
@@ -30,32 +30,38 @@ const fixedTileData = await corrector.fixTile(
30
30
  corrections,
31
31
  originalTileArrayBuffer,
32
32
  layerConfig,
33
- z, // zoom level
34
- 256 // tile size (optional, defaults to 256)
33
+ z // zoom level (tile size is derived from image)
35
34
  );
36
35
  ```
37
36
 
38
37
  ## API
39
38
 
40
- ### `BoundaryCorrector`
39
+ ### `TileFixer`
40
+
41
+ #### Static Methods
42
+
43
+ | Method | Returns | Description |
44
+ |--------|---------|-------------|
45
+ | `TileFixer.getOrCreate(pmtilesUrl)` | `TileFixer` | Get or create a TileFixer for a URL (reuses existing instances) |
46
+ | `TileFixer.setDefaultCacheMaxFeatures(count)` | `void` | Set default max features to cache for new instances (default: 25000) |
41
47
 
42
48
  #### Constructor
43
49
 
44
50
  ```javascript
45
- new BoundaryCorrector(pmtilesUrl, options?)
51
+ new TileFixer(pmtilesUrl, options?)
46
52
  ```
47
53
 
48
54
  | Parameter | Type | Description |
49
55
  |-----------|------|-------------|
50
56
  | `pmtilesUrl` | string | URL to the PMTiles file |
51
- | `options.cacheSize` | number | Maximum tiles to cache (default: 64) |
57
+ | `options.cacheMaxFeatures` | number | Maximum features to cache |
52
58
 
53
59
  #### Methods
54
60
 
55
61
  | Method | Returns | Description |
56
62
  |--------|---------|-------------|
57
63
  | `getCorrections(z, x, y)` | `Promise<Object>` | Get correction features for a tile. Supports overzoom beyond zoom 14. |
58
- | `fixTile(corrections, rasterTile, layerConfig, zoom, tileSize?)` | `Promise<ArrayBuffer>` | Apply corrections to a raster tile and return corrected PNG. |
64
+ | `fixTile(corrections, rasterTile, layerConfig, zoom)` | `Promise<ArrayBuffer>` | Apply corrections to a raster tile and return corrected PNG. Tile size is derived from the image. |
59
65
  | `fetchAndFixTile(tileUrl, z, x, y, layerConfig, options?)` | `Promise<Object>` | Fetch a tile, apply corrections, and return result. See below. |
60
66
  | `getSource()` | `PMTiles` | Get the underlying PMTiles source object |
61
67
  | `clearCache()` | `void` | Clear the tile cache |
@@ -64,7 +70,6 @@ new BoundaryCorrector(pmtilesUrl, options?)
64
70
 
65
71
  ```javascript
66
72
  const result = await corrector.fetchAndFixTile(tileUrl, z, x, y, layerConfig, {
67
- tileSize: 256, // Tile size in pixels (default: 256)
68
73
  signal: abortSignal, // AbortSignal for cancellation
69
74
  mode: 'cors', // Fetch mode
70
75
  });
package/dist/index.cjs CHANGED
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
7
  var __export = (target, all) => {
7
8
  for (var name in all)
8
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,12 +17,15 @@ var __copyProps = (to, from, except, desc) => {
16
17
  return to;
17
18
  };
18
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
19
21
 
20
22
  // src/index.js
21
23
  var index_exports = {};
22
24
  __export(index_exports, {
23
- BoundaryCorrector: () => BoundaryCorrector,
24
25
  MIN_LINE_WIDTH: () => MIN_LINE_WIDTH,
26
+ TileFetchError: () => TileFetchError,
27
+ TileFixer: () => TileFixer,
28
+ buildFetchOptions: () => buildFetchOptions,
25
29
  getLineWidth: () => getLineWidth
26
30
  });
27
31
  module.exports = __toCommonJS(index_exports);
@@ -2052,10 +2056,16 @@ function writeUtf8(buf, str, pos) {
2052
2056
  }
2053
2057
 
2054
2058
  // src/corrections.js
2055
- var DEFAULT_CACHE_SIZE = 64;
2056
2059
  function toIndex(z2, x2, y) {
2057
2060
  return `${x2}:${y}:${z2}`;
2058
2061
  }
2062
+ function countFeatures(corrections) {
2063
+ let count = 0;
2064
+ for (const features of Object.values(corrections)) {
2065
+ count += features.length;
2066
+ }
2067
+ return count;
2068
+ }
2059
2069
  function parseTile(buffer) {
2060
2070
  const tile = new VectorTile(new Pbf(buffer));
2061
2071
  const result = {};
@@ -2104,16 +2114,19 @@ var CorrectionsSource = class {
2104
2114
  /**
2105
2115
  * @param {string} pmtilesUrl - URL to the PMTiles file
2106
2116
  * @param {Object} [options] - Options
2107
- * @param {number} [options.cacheSize=64] - Maximum number of tiles to cache
2117
+ * @param {number} [options.cacheMaxFeatures=10000] - Maximum number of features to cache
2108
2118
  * @param {number} [options.maxDataZoom] - Maximum zoom level in PMTiles (auto-detected if not provided)
2109
2119
  */
2110
2120
  constructor(pmtilesUrl, options = {}) {
2111
2121
  this.pmtilesUrl = pmtilesUrl;
2112
2122
  this.pmtiles = new x(pmtilesUrl);
2113
- this.cacheSize = options.cacheSize ?? DEFAULT_CACHE_SIZE;
2123
+ this.cacheMaxFeatures = options.cacheMaxFeatures;
2114
2124
  this.maxDataZoom = options.maxDataZoom;
2115
2125
  this.cache = /* @__PURE__ */ new Map();
2116
2126
  this.inflight = /* @__PURE__ */ new Map();
2127
+ this.cachedFeatureCount = 0;
2128
+ this.emptyKeys = /* @__PURE__ */ new Set();
2129
+ this.nonEmptyKeys = /* @__PURE__ */ new Set();
2117
2130
  }
2118
2131
  /**
2119
2132
  * Get the PMTiles source object.
@@ -2128,6 +2141,35 @@ var CorrectionsSource = class {
2128
2141
  clearCache() {
2129
2142
  this.cache.clear();
2130
2143
  this.inflight.clear();
2144
+ this.cachedFeatureCount = 0;
2145
+ this.emptyKeys.clear();
2146
+ this.nonEmptyKeys.clear();
2147
+ }
2148
+ /**
2149
+ * Evict cache entries to stay under the feature limit.
2150
+ * Empty entries are evicted first (cheap to re-fetch from PMTiles directory cache).
2151
+ * Within each category, evicts LRU (least recently used) entries.
2152
+ * @private
2153
+ */
2154
+ _evictIfNeeded() {
2155
+ while (this.cachedFeatureCount > this.cacheMaxFeatures && this.cache.size > 1) {
2156
+ const targetSet = this.emptyKeys.size > 0 ? this.emptyKeys : this.nonEmptyKeys;
2157
+ if (targetSet.size === 0) break;
2158
+ let evictKey = void 0;
2159
+ let minUsed = Infinity;
2160
+ for (const key of targetSet) {
2161
+ const entry = this.cache.get(key);
2162
+ if (entry && entry.used < minUsed) {
2163
+ minUsed = entry.used;
2164
+ evictKey = key;
2165
+ }
2166
+ }
2167
+ if (!evictKey) break;
2168
+ const evicted = this.cache.get(evictKey);
2169
+ this.cachedFeatureCount -= evicted.featureCount;
2170
+ targetSet.delete(evictKey);
2171
+ this.cache.delete(evictKey);
2172
+ }
2131
2173
  }
2132
2174
  /**
2133
2175
  * Auto-detect max zoom from PMTiles metadata.
@@ -2148,10 +2190,11 @@ var CorrectionsSource = class {
2148
2190
  * @param {number} z
2149
2191
  * @param {number} x
2150
2192
  * @param {number} y
2193
+ * @param {AbortSignal} [signal] - Optional abort signal
2151
2194
  * @returns {Promise<Object<string, Array>>}
2152
2195
  * @private
2153
2196
  */
2154
- async _fetchTile(z2, x2, y) {
2197
+ async _fetchTile(z2, x2, y, signal) {
2155
2198
  const idx = toIndex(z2, x2, y);
2156
2199
  return new Promise((resolve, reject) => {
2157
2200
  const entry = this.cache.get(idx);
@@ -2166,14 +2209,18 @@ var CorrectionsSource = class {
2166
2209
  return;
2167
2210
  }
2168
2211
  this.inflight.set(idx, []);
2169
- this.pmtiles.getZxy(z2, x2, y).then((result) => {
2212
+ this.pmtiles.getZxy(z2, x2, y, signal).then((result) => {
2170
2213
  let data;
2171
2214
  if (result) {
2172
2215
  data = parseTile(result.data);
2173
2216
  } else {
2174
2217
  data = {};
2175
2218
  }
2176
- this.cache.set(idx, { used: performance.now(), data });
2219
+ const featureCount = countFeatures(data);
2220
+ const empty = featureCount === 0;
2221
+ this.cache.set(idx, { used: performance.now(), data, featureCount, empty });
2222
+ this.cachedFeatureCount += featureCount;
2223
+ (empty ? this.emptyKeys : this.nonEmptyKeys).add(idx);
2177
2224
  const ifentry2 = this.inflight.get(idx);
2178
2225
  if (ifentry2) {
2179
2226
  for (const waiter of ifentry2) {
@@ -2182,19 +2229,7 @@ var CorrectionsSource = class {
2182
2229
  }
2183
2230
  this.inflight.delete(idx);
2184
2231
  resolve(data);
2185
- if (this.cache.size > this.cacheSize) {
2186
- let minUsed = Infinity;
2187
- let minKey = void 0;
2188
- this.cache.forEach((value, key) => {
2189
- if (value.used < minUsed) {
2190
- minUsed = value.used;
2191
- minKey = key;
2192
- }
2193
- });
2194
- if (minKey) {
2195
- this.cache.delete(minKey);
2196
- }
2197
- }
2232
+ this._evictIfNeeded();
2198
2233
  }).catch((e) => {
2199
2234
  const ifentry2 = this.inflight.get(idx);
2200
2235
  if (ifentry2) {
@@ -2213,9 +2248,10 @@ var CorrectionsSource = class {
2213
2248
  * @param {number} z - Zoom level
2214
2249
  * @param {number} x - Tile X coordinate
2215
2250
  * @param {number} y - Tile Y coordinate
2251
+ * @param {AbortSignal} [signal] - Optional abort signal
2216
2252
  * @returns {Promise<Object<string, Array>>} Map of layer name to array of features
2217
2253
  */
2218
- async get(z2, x2, y) {
2254
+ async get(z2, x2, y, signal) {
2219
2255
  const maxDataZoom = await this._getMaxDataZoom();
2220
2256
  if (z2 > maxDataZoom) {
2221
2257
  const zoomDiff = z2 - maxDataZoom;
@@ -2224,18 +2260,64 @@ var CorrectionsSource = class {
2224
2260
  const parentY = Math.floor(y / scale);
2225
2261
  const offsetX = x2 % scale;
2226
2262
  const offsetY = y % scale;
2227
- const corrections = await this._fetchTile(maxDataZoom, parentX, parentY);
2263
+ const corrections = await this._fetchTile(maxDataZoom, parentX, parentY, signal);
2228
2264
  if (Object.keys(corrections).length > 0) {
2229
2265
  return transformForOverzoom(corrections, scale, offsetX, offsetY);
2230
2266
  }
2231
2267
  return {};
2232
2268
  }
2233
- return await this._fetchTile(z2, x2, y);
2269
+ return await this._fetchTile(z2, x2, y, signal);
2234
2270
  }
2235
2271
  };
2236
2272
 
2237
2273
  // src/index.js
2274
+ var TileFetchError = class _TileFetchError extends Error {
2275
+ /**
2276
+ * @param {number} status - HTTP status code
2277
+ * @param {string} [url] - The URL that failed
2278
+ * @param {string} [body] - Response body text
2279
+ */
2280
+ constructor(status, url, body) {
2281
+ super(`Tile fetch failed: ${status}`);
2282
+ this.name = "TileFetchError";
2283
+ this.status = status;
2284
+ this.url = url;
2285
+ this.body = body;
2286
+ }
2287
+ /**
2288
+ * Create a TileFetchError from a failed Response.
2289
+ * @param {Response} response - The failed fetch response
2290
+ * @returns {Promise<TileFetchError>}
2291
+ */
2292
+ static async fromResponse(response) {
2293
+ let body;
2294
+ try {
2295
+ body = await response.text();
2296
+ } catch {
2297
+ }
2298
+ return new _TileFetchError(response.status, response.url, body);
2299
+ }
2300
+ };
2238
2301
  var MIN_LINE_WIDTH = 0.5;
2302
+ var DEFAULT_TILE_EXTENT = 4096;
2303
+ var DEFAULT_LINE_WIDTH = 1;
2304
+ function buildFetchOptions(crossOrigin, referrerPolicy) {
2305
+ const options = {};
2306
+ if (crossOrigin === "use-credentials") {
2307
+ options.mode = "cors";
2308
+ options.credentials = "include";
2309
+ } else if (crossOrigin === "anonymous" || crossOrigin === "" || crossOrigin === true) {
2310
+ options.mode = "cors";
2311
+ options.credentials = "omit";
2312
+ } else {
2313
+ options.mode = "cors";
2314
+ options.credentials = "same-origin";
2315
+ }
2316
+ if (referrerPolicy) {
2317
+ options.referrerPolicy = referrerPolicy;
2318
+ }
2319
+ return options;
2320
+ }
2239
2321
  function getLineWidth(zoom, lineWidthStops) {
2240
2322
  const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
2241
2323
  if (lineWidthStops[zoom] !== void 0) {
@@ -2267,7 +2349,7 @@ function getLineWidth(zoom, lineWidthStops) {
2267
2349
  return w1 + t * (w2 - w1);
2268
2350
  }
2269
2351
  }
2270
- return 1;
2352
+ return DEFAULT_LINE_WIDTH;
2271
2353
  }
2272
2354
  function getFeaturesBoundingBox(features, tileSize, padding = 0) {
2273
2355
  let minX = Infinity, minY = Infinity;
@@ -2421,6 +2503,14 @@ function extendFeaturesEnds(features, extensionLength) {
2421
2503
  return { ...feature, geometry: newGeometry };
2422
2504
  });
2423
2505
  }
2506
+ function extendFeaturesByFactor(features, extensionFactor, delLineWidth, tileSize) {
2507
+ if (!features || features.length === 0 || extensionFactor <= 0) {
2508
+ return features;
2509
+ }
2510
+ const extent = features[0]?.extent || DEFAULT_TILE_EXTENT;
2511
+ const extensionLength = delLineWidth * extensionFactor / tileSize * extent;
2512
+ return extendFeaturesEnds(features, extensionLength);
2513
+ }
2424
2514
  function drawFeatures(ctx, features, color, lineWidth, tileSize, dashArray, alpha) {
2425
2515
  const prevAlpha = ctx.globalAlpha;
2426
2516
  if (alpha !== void 0) {
@@ -2452,15 +2542,39 @@ function drawFeatures(ctx, features, color, lineWidth, tileSize, dashArray, alph
2452
2542
  ctx.globalAlpha = prevAlpha;
2453
2543
  }
2454
2544
  }
2455
- var BoundaryCorrector = class {
2545
+ var _TileFixer = class _TileFixer {
2546
+ /**
2547
+ * Set the default maximum features to cache for new TileFixer instances.
2548
+ * @param {number} maxFeatures - Maximum features to cache
2549
+ */
2550
+ static setDefaultCacheMaxFeatures(maxFeatures) {
2551
+ _TileFixer._defaultCacheMaxFeatures = maxFeatures;
2552
+ }
2553
+ /**
2554
+ * Get or create a TileFixer instance for a given PMTiles URL.
2555
+ * Reuses existing instances for the same URL.
2556
+ * @param {string} pmtilesUrl - URL to the PMTiles file
2557
+ * @returns {TileFixer}
2558
+ */
2559
+ static getOrCreate(pmtilesUrl) {
2560
+ let instance = _TileFixer._instances.get(pmtilesUrl);
2561
+ if (!instance) {
2562
+ instance = new _TileFixer(pmtilesUrl, {
2563
+ cacheMaxFeatures: _TileFixer._defaultCacheMaxFeatures
2564
+ });
2565
+ _TileFixer._instances.set(pmtilesUrl, instance);
2566
+ }
2567
+ return instance;
2568
+ }
2456
2569
  /**
2457
2570
  * @param {string} pmtilesUrl - URL to the PMTiles file
2458
2571
  * @param {Object} [options] - Options
2459
- * @param {number} [options.cacheSize=64] - Maximum number of tiles to cache
2572
+ * @param {number} [options.cacheMaxFeatures] - Maximum number of features to cache
2460
2573
  * @param {number} [options.maxDataZoom] - Maximum zoom level in PMTiles (auto-detected if not provided)
2461
2574
  */
2462
2575
  constructor(pmtilesUrl, options = {}) {
2463
2576
  this.correctionsSource = new CorrectionsSource(pmtilesUrl, options);
2577
+ this._canvas = null;
2464
2578
  this._maskCanvas = null;
2465
2579
  }
2466
2580
  /**
@@ -2482,10 +2596,11 @@ var BoundaryCorrector = class {
2482
2596
  * @param {number} z - Zoom level
2483
2597
  * @param {number} x - Tile X coordinate
2484
2598
  * @param {number} y - Tile Y coordinate
2599
+ * @param {AbortSignal} [signal] - Optional abort signal
2485
2600
  * @returns {Promise<Object<string, Array>>} Map of layer name to array of features
2486
2601
  */
2487
- async getCorrections(z2, x2, y) {
2488
- return await this.correctionsSource.get(z2, x2, y);
2602
+ async getCorrections(z2, x2, y, signal) {
2603
+ return await this.correctionsSource.get(z2, x2, y, signal);
2489
2604
  }
2490
2605
  /**
2491
2606
  * Apply corrections to a raster tile.
@@ -2493,10 +2608,9 @@ var BoundaryCorrector = class {
2493
2608
  * @param {ArrayBuffer} rasterTile - The original raster tile as ArrayBuffer
2494
2609
  * @param {Object} layerConfig - Layer configuration with colors and styles
2495
2610
  * @param {number} zoom - Current zoom level
2496
- * @param {number} [tileSize=256] - Size of the tile in pixels
2497
2611
  * @returns {Promise<ArrayBuffer>} The corrected tile as ArrayBuffer (PNG)
2498
2612
  */
2499
- async fixTile(corrections, rasterTile, layerConfig, zoom, tileSize = 256) {
2613
+ async fixTile(corrections, rasterTile, layerConfig, zoom) {
2500
2614
  const {
2501
2615
  startZoom = 0,
2502
2616
  zoomThreshold,
@@ -2520,16 +2634,17 @@ var BoundaryCorrector = class {
2520
2634
  const useOsm = zoom >= zoomThreshold;
2521
2635
  const addLayerName = useOsm ? "to-add-osm" : "to-add-ne";
2522
2636
  const delLayerName = useOsm ? "to-del-osm" : "to-del-ne";
2637
+ const blob = new Blob([rasterTile]);
2638
+ const imageBitmap = await createImageBitmap(blob);
2639
+ const tileSize = imageBitmap.width;
2523
2640
  if (!this._canvas || this._canvas.width !== tileSize) {
2524
2641
  this._canvas = new OffscreenCanvas(tileSize, tileSize);
2525
2642
  }
2526
2643
  const canvas = this._canvas;
2527
2644
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
2528
- const blob = new Blob([rasterTile]);
2529
- const imageBitmap = await createImageBitmap(blob);
2530
2645
  ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
2531
2646
  const baseLineWidth = getLineWidth(zoom, lineWidthStops);
2532
- const maxWidthFraction = activeLineStyles.length > 0 ? Math.max(...activeLineStyles.map((s) => s.widthFraction ?? 1)) : 1;
2647
+ const maxWidthFraction = activeLineStyles.length > 0 ? Math.max(...activeLineStyles.map((s) => s.widthFraction)) : 1;
2533
2648
  const delLineWidth = baseLineWidth * maxWidthFraction * delWidthFactor;
2534
2649
  const delFeatures = corrections[delLayerName] || [];
2535
2650
  if (delFeatures.length > 0) {
@@ -2540,14 +2655,11 @@ var BoundaryCorrector = class {
2540
2655
  }
2541
2656
  let addFeatures = corrections[addLayerName] || [];
2542
2657
  if (addFeatures.length > 0 && activeLineStyles.length > 0) {
2543
- const extensionFactor = layerConfig.lineExtensionFactor ?? 0.5;
2544
- if (extensionFactor > 0 && delFeatures.length > 0) {
2545
- const extent = addFeatures[0]?.extent || 4096;
2546
- const extensionLength = delLineWidth * extensionFactor / tileSize * extent;
2547
- addFeatures = extendFeaturesEnds(addFeatures, extensionLength);
2658
+ if (delFeatures.length > 0) {
2659
+ addFeatures = extendFeaturesByFactor(addFeatures, layerConfig.lineExtensionFactor, delLineWidth, tileSize);
2548
2660
  }
2549
2661
  for (const style of activeLineStyles) {
2550
- const { color, widthFraction = 1, dashArray, alpha = 1 } = style;
2662
+ const { color, widthFraction, dashArray, alpha } = style;
2551
2663
  const lineWidth = baseLineWidth * widthFraction;
2552
2664
  drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
2553
2665
  }
@@ -2562,45 +2674,51 @@ var BoundaryCorrector = class {
2562
2674
  * @param {number} x - Tile X coordinate
2563
2675
  * @param {number} y - Tile Y coordinate
2564
2676
  * @param {Object} layerConfig - Layer configuration with colors and styles
2565
- * @param {Object} [options] - Fetch options
2566
- * @param {number} [options.tileSize=256] - Tile size in pixels
2567
- * @param {AbortSignal} [options.signal] - Abort signal for fetch
2568
- * @param {RequestMode} [options.mode] - Fetch mode (e.g., 'cors')
2677
+ * @param {Object} [fetchOptions] - Fetch options passed to fetch()
2678
+ * @param {AbortSignal} [fetchOptions.signal] - Abort signal for fetch
2679
+ * @param {RequestMode} [fetchOptions.mode] - Fetch mode (e.g., 'cors')
2680
+ * @param {RequestCredentials} [fetchOptions.credentials] - Fetch credentials (e.g., 'omit', 'include')
2681
+ * @param {string} [fetchOptions.referrer] - Referrer URL or empty string for none
2682
+ * @param {ReferrerPolicy} [fetchOptions.referrerPolicy] - Referrer policy (e.g., 'no-referrer', 'origin')
2683
+ * @param {boolean} [fallbackOnCorrectionFailure=true] - Return original tile if corrections fail
2569
2684
  * @returns {Promise<{data: ArrayBuffer, wasFixed: boolean}>}
2570
2685
  */
2571
- async fetchAndFixTile(tileUrl, z2, x2, y, layerConfig, options = {}) {
2572
- const { tileSize = 256, signal, mode } = options;
2573
- const fetchOptions = {};
2574
- if (signal) fetchOptions.signal = signal;
2575
- if (mode) fetchOptions.mode = mode;
2686
+ async fetchAndFixTile(tileUrl, z2, x2, y, layerConfig, fetchOptions = {}, fallbackOnCorrectionFailure = true) {
2687
+ const { signal } = fetchOptions;
2576
2688
  if (!layerConfig) {
2577
2689
  const response = await fetch(tileUrl, fetchOptions);
2578
- if (!response.ok) throw new Error(`Tile fetch failed: ${response.status}`);
2690
+ if (!response.ok) throw await TileFetchError.fromResponse(response);
2579
2691
  return { data: await response.arrayBuffer(), wasFixed: false };
2580
2692
  }
2581
2693
  const [tileResult, correctionsResult] = await Promise.allSettled([
2582
- fetch(tileUrl, fetchOptions).then((r) => {
2583
- if (!r.ok) throw new Error(`Tile fetch failed: ${r.status}`);
2694
+ fetch(tileUrl, fetchOptions).then(async (r) => {
2695
+ if (!r.ok) throw await TileFetchError.fromResponse(r);
2584
2696
  return r.arrayBuffer();
2585
2697
  }),
2586
- this.getCorrections(z2, x2, y)
2698
+ this.getCorrections(z2, x2, y, signal)
2587
2699
  ]);
2588
- if (signal?.aborted) {
2589
- throw new DOMException("Aborted", "AbortError");
2590
- }
2700
+ signal?.throwIfAborted();
2591
2701
  if (tileResult.status === "rejected") {
2592
2702
  throw tileResult.reason;
2593
2703
  }
2594
2704
  const tileData = tileResult.value;
2595
2705
  const correctionsFailed = correctionsResult.status === "rejected";
2596
2706
  const correctionsError = correctionsFailed ? correctionsResult.reason : null;
2707
+ if (correctionsFailed && !fallbackOnCorrectionFailure) {
2708
+ throw correctionsError;
2709
+ }
2597
2710
  const corrections = correctionsResult.status === "fulfilled" ? correctionsResult.value : {};
2598
2711
  const hasCorrections = Object.values(corrections).some((arr) => arr && arr.length > 0);
2599
2712
  if (!hasCorrections) {
2600
2713
  return { data: tileData, wasFixed: false, correctionsFailed, correctionsError };
2601
2714
  }
2602
- const fixedData = await this.fixTile(corrections, tileData, layerConfig, z2, tileSize);
2715
+ const fixedData = await this.fixTile(corrections, tileData, layerConfig, z2);
2603
2716
  return { data: fixedData, wasFixed: true, correctionsFailed: false, correctionsError: null };
2604
2717
  }
2605
2718
  };
2719
+ /** @type {Map<string, TileFixer>} */
2720
+ __publicField(_TileFixer, "_instances", /* @__PURE__ */ new Map());
2721
+ /** @type {number} */
2722
+ __publicField(_TileFixer, "_defaultCacheMaxFeatures", 25e3);
2723
+ var TileFixer = _TileFixer;
2606
2724
  //# sourceMappingURL=index.cjs.map