map-gl-offline 0.5.5 โ†’ 0.6.0

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
@@ -4,93 +4,35 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-100%25-blue.svg)](https://www.typescriptlang.org/)
6
6
 
7
- **[Documentation](https://map-gl-offline.netlify.app)** | **[Live Demo](https://map-gl-offline-demo.netlify.app)**
7
+ **[๐Ÿ“– Documentation](https://map-gl-offline.netlify.app)** ยท **[๐ŸŽฎ Live Demo](https://map-gl-offline-demo.netlify.app)** ยท **[๐Ÿ› Issues](https://github.com/muimsd/map-gl-offline/issues)**
8
8
 
9
- A comprehensive **TypeScript** library for **MapLibre GL JS** and **Mapbox GL JS** that enables complete offline map functionality with vector/raster tiles, styles, fonts, sprites, and glyphs stored in IndexedDB. Features include Mapbox Standard style support, advanced analytics, intelligent cleanup, i18n (English & Arabic with RTL), and a modern glassmorphic UI control.
10
-
11
- ## ๐ŸŽฌ Demo
9
+ TypeScript offline-map library for **MapLibre GL JS** and **Mapbox GL JS**. Download styles, tiles, sprites, glyphs, and fonts to IndexedDB; load them back with zero network. Ships with a glassmorphic UI control and a complete programmatic API.
12
10
 
13
11
  ![Map GL Offline Demo](assets/map-gl-offline-demo.gif)
14
12
 
15
- *Download regions, load offline styles, and navigate maps without an internet connection.*
16
-
17
- ## โœจ Features
18
-
19
- ### ๐ŸŽฏ Core Offline Capabilities
20
-
21
- - ๐Ÿ—บ๏ธ **Complete Offline Maps**: Download and store entire map regions with polygon-based selection
22
- - ๐ŸŽฏ **Smart Tile Management**: Efficient vector/raster tile downloading, caching, and retrieval with zoom-level optimization
23
- - ๐Ÿงฉ **Extra Tile Sources**: Save additional vector (MVT/PBF) and raster tile layers alongside the style's own sources
24
- - ๐Ÿ”ค **Font & Glyph Support**: Comprehensive font and glyph management with Unicode range support
25
- - ๐ŸŽจ **Sprite Management**: Handle map sprites and icons offline with multi-resolution support (@1x, @2x)
26
- - ๐Ÿ“Š **Real-time Analytics**: Detailed storage analytics, performance metrics, and optimization recommendations
27
-
28
- ### ๐ŸŒ Mapbox GL JS Support
29
-
30
- - ๐Ÿ”— **mapbox:// Protocol Resolution**: Automatic resolution of `mapbox://` style, source, sprite, and glyph URLs
31
- - ๐Ÿ™๏ธ **Mapbox Standard Style**: Full support including 3D models, raster-dem terrain, and import-based style resolution
32
- - ๐ŸŒ… **Day/Night Light Presets**: Toggle between day and night lighting in Mapbox Standard style
33
- - ๐ŸŒง๏ธ **Weather Controls**: Rain and snow effects for Mapbox Standard style
34
- - ๐Ÿ” **Auto-detection**: Automatically detects whether a style is Mapbox or MapLibre and applies the correct handling
35
-
36
- ### ๐ŸŽจ Modern UI Control
37
-
38
- - ๐Ÿ–ผ๏ธ **Glassmorphic Design**: Beautiful modern interface with glassmorphism effects and smooth animations
39
- - ๐ŸŒ“ **Dark/Light Theme**: Automatic theme switching with system preference detection
40
- - ๐Ÿ“ **Polygon Drawing**: Interactive polygon tool for precise region selection
41
- - ๐Ÿ“Š **Live Progress**: Real-time download progress with detailed statistics
42
- - ๐ŸŽฏ **Region Management**: Easy-to-use interface for managing multiple offline regions
43
- - โšก **Responsive**: Mobile-friendly design that adapts to all screen sizes
44
- - ๐ŸŒ **Internationalization**: English and Arabic language support with full RTL layout
13
+ ## Features
45
14
 
46
- ### ๐Ÿ› ๏ธ Technical Excellence
15
+ - ๐Ÿ—บ๏ธ **Offline regions** โ€” polygon selection, smart tile management, extra vector/raster overlays
16
+ - ๐ŸŽจ **Full resource capture** โ€” styles, sprites, fonts, glyphs with Unicode ranges
17
+ - ๐Ÿ”— **Mapbox GL + MapLibre GL** โ€” auto-detection, `mapbox://` URL resolution, Standard style with 3D/terrain
18
+ - ๐Ÿ“Š **Analytics & cleanup** โ€” storage reports, auto-cleanup, quota-aware downloads
19
+ - ๐ŸŽจ **UI control** โ€” glassmorphic panel, dark/light themes, English/Arabic (RTL), polygon drawing
20
+ - ๐Ÿ› ๏ธ **Programmatic API** โ€” `downloadRegion` with per-phase progress, full TypeScript types
47
21
 
48
- - ๐Ÿ’พ **IndexedDB Storage**: Efficient browser storage with quota management and transaction safety
49
- - ๐Ÿ”ง **Full TypeScript**: Complete type definitions, interfaces, and compile-time safety
50
- - โšก **Performance Optimized**: Concurrent downloads, async/await patterns, and memory-efficient operations
51
- - ๐Ÿงน **Intelligent Cleanup**: Smart cleanup of expired data with customizable policies
52
- - ๐Ÿ”„ **Robust Error Handling**: Comprehensive error recovery, retry mechanisms, and graceful degradation
53
- - ๐Ÿ” **Enhanced Logging**: Detailed debugging with zoom-level specific logging (Z12 tracking)
54
-
55
- ## ๐Ÿ“ฆ Installation
22
+ ## Install
56
23
 
57
24
  ```bash
58
25
  npm install map-gl-offline
59
- # or
60
- yarn add map-gl-offline
61
- # or
62
- pnpm add map-gl-offline
63
26
  ```
64
27
 
65
- ### CDN (UMD)
66
-
67
- For use via `<script>` tag, the library is available as the `mapgloffline` global (similar to `mapboxgl` and `maplibregl`):
28
+ Or via CDN as the `mapgloffline` global:
68
29
 
69
30
  ```html
70
31
  <script src="https://unpkg.com/map-gl-offline/dist/index.umd.js"></script>
71
32
  <link rel="stylesheet" href="https://unpkg.com/map-gl-offline/style.css" />
72
- <script>
73
- const manager = new mapgloffline.OfflineMapManager();
74
- const control = new mapgloffline.OfflineManagerControl(manager, {
75
- styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
76
- });
77
- map.addControl(control, 'top-right');
78
- </script>
79
- ```
80
-
81
- ## ๐Ÿ”‘ Environment Setup
82
-
83
- For development or when using Maptiler styles, create a `.env` file:
84
-
85
- ```env
86
- VITE_MAPTILER_API_KEY=your_api_key_here
87
33
  ```
88
34
 
89
- Get a free API key from [Maptiler](https://www.maptiler.com/).
90
-
91
- For Mapbox styles, you will also need a Mapbox access token from [Mapbox](https://www.mapbox.com/).
92
-
93
- ## ๐Ÿš€ Quick Start
35
+ ## Quick Start
94
36
 
95
37
  ### MapLibre GL JS
96
38
 
@@ -100,11 +42,9 @@ import { OfflineMapManager, OfflineManagerControl } from 'map-gl-offline';
100
42
  import 'maplibre-gl/dist/maplibre-gl.css';
101
43
  import 'map-gl-offline/style.css';
102
44
 
103
- const styleUrl = 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_API_KEY';
104
-
105
45
  const map = new maplibregl.Map({
106
46
  container: 'map',
107
- style: styleUrl,
47
+ style: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
108
48
  center: [-74.006, 40.7128],
109
49
  zoom: 12,
110
50
  });
@@ -112,48 +52,33 @@ const map = new maplibregl.Map({
112
52
  const offlineManager = new OfflineMapManager();
113
53
 
114
54
  map.on('load', () => {
115
- const control = new OfflineManagerControl(offlineManager, {
116
- styleUrl,
117
- theme: 'dark',
118
- showBbox: true,
119
- mapLib: maplibregl, // enables idb:// protocol in web workers
120
- });
121
- map.addControl(control, 'top-right');
55
+ map.addControl(
56
+ new OfflineManagerControl(offlineManager, {
57
+ styleUrl: map.getStyle().sprite,
58
+ mapLib: maplibregl, // enables idb:// protocol
59
+ }),
60
+ 'top-right',
61
+ );
122
62
  });
123
63
  ```
124
64
 
125
65
  ### Mapbox GL JS
126
66
 
127
- Mapbox GL JS v3 does not support `addProtocol`, so offline tile serving uses a **Service Worker** fallback. You need to copy `idb-offline-sw.js` to your project's public directory so it is served at the root (`/idb-offline-sw.js`).
128
-
129
- **Option 1: CLI (recommended)**
67
+ Mapbox GL JS v3 lacks `addProtocol`, so the library uses a Service Worker. Run **one** of:
130
68
 
131
69
  ```bash
132
- npx map-gl-offline init
133
- ```
134
-
135
- **Option 2: Vite plugin**
136
-
137
- ```js
138
- // vite.config.js
139
- import { offlineSwPlugin } from 'map-gl-offline/vite-plugin';
140
-
141
- export default defineConfig({
142
- plugins: [offlineSwPlugin()],
143
- });
70
+ npx map-gl-offline init # CLI (recommended)
71
+ # or add to vite.config.js:
72
+ # import { offlineSwPlugin } from 'map-gl-offline/vite-plugin';
73
+ # plugins: [offlineSwPlugin()]
74
+ # or manually: cp node_modules/map-gl-offline/dist/idb-offline-sw.js public/
144
75
  ```
145
76
 
146
- **Option 3: Manual copy**
147
-
148
- ```bash
149
- cp node_modules/map-gl-offline/dist/idb-offline-sw.js public/idb-offline-sw.js
150
- ```
77
+ Then:
151
78
 
152
79
  ```typescript
153
80
  import mapboxgl from 'mapbox-gl';
154
81
  import { OfflineMapManager, OfflineManagerControl } from 'map-gl-offline';
155
- import 'mapbox-gl/dist/mapbox-gl.css';
156
- import 'map-gl-offline/style.css';
157
82
 
158
83
  mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
159
84
 
@@ -165,381 +90,103 @@ const map = new mapboxgl.Map({
165
90
  });
166
91
 
167
92
  const offlineManager = new OfflineMapManager();
168
-
169
- map.on('load', () => {
170
- const control = new OfflineManagerControl(offlineManager, {
171
- styleUrl: 'mapbox://styles/mapbox/standard',
172
- theme: 'dark',
173
- showBbox: true,
174
- accessToken: mapboxgl.accessToken,
175
- // No mapLib needed - Mapbox GL JS v3 lacks addProtocol,
176
- // so the library auto-registers a Service Worker fallback
177
- });
178
- map.addControl(control, 'top-right');
179
- });
93
+ map.on('load', () =>
94
+ map.addControl(
95
+ new OfflineManagerControl(offlineManager, {
96
+ styleUrl: 'mapbox://styles/mapbox/standard',
97
+ accessToken: mapboxgl.accessToken,
98
+ }),
99
+ 'top-right',
100
+ ),
101
+ );
180
102
  ```
181
103
 
182
- > **Note:** MapLibre GL JS has built-in `addProtocol` support, so it does not need the Service Worker. Only Mapbox GL JS requires this extra step.
183
-
184
- The UI control provides:
185
-
186
- - ๐Ÿ“ **Polygon drawing** for region selection
187
- - ๐Ÿ“Š **Download progress** tracking
188
- - ๐Ÿ—‚๏ธ **Region management** (view, delete)
189
- - ๐ŸŒ“ **Theme toggle** (dark/light mode)
190
- - ๐Ÿ“ˆ **Storage analytics**
191
- - ๐ŸŒ **Language switcher** (English / Arabic with RTL)
104
+ ## Programmatic Usage
192
105
 
193
- ### Programmatic Usage
106
+ `downloadRegion` runs the full pipeline (**style โ†’ sprites โ†’ glyphs โ†’ tiles โ†’ metadata**) with per-phase progress. `addRegion` alone only stores metadata โ€” use `downloadRegion` to actually fetch assets.
194
107
 
195
108
  ```typescript
196
109
  import { OfflineMapManager } from 'map-gl-offline';
197
110
 
198
- // Initialize the offline manager
199
111
  const offlineManager = new OfflineMapManager();
200
112
 
201
- // Download a map region for offline use
202
- await offlineManager.addRegion({
203
- id: 'downtown',
204
- name: 'Downtown Area',
205
- bounds: [
206
- [-74.0559, 40.7128], // Southwest [lng, lat]
207
- [-74.0059, 40.7628], // Northeast [lng, lat]
208
- ],
209
- minZoom: 10,
210
- maxZoom: 16,
211
- styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
212
- onProgress: progress => {
213
- console.log(`Progress: ${progress.percentage}%`);
214
- console.log(`Current: ${progress.message}`);
113
+ await offlineManager.downloadRegion(
114
+ {
115
+ id: 'downtown',
116
+ name: 'Downtown',
117
+ bounds: [[-74.0559, 40.7128], [-74.0059, 40.7628]],
118
+ minZoom: 10,
119
+ maxZoom: 16,
120
+ styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
215
121
  },
216
- });
217
-
218
- // Retrieve a stored region
219
- const region = await offlineManager.getStoredRegion('downtown');
220
- if (region) {
221
- console.log(`Region: ${region.name}, created: ${new Date(region.created).toLocaleDateString()}`);
222
- }
223
-
224
- // List all regions
225
- const regions = await offlineManager.listStoredRegions();
226
- console.log(`Stored regions:`, regions);
122
+ {
123
+ onProgress: ({ phase, percentage, message }) => {
124
+ console.log(`[${phase}] ${percentage.toFixed(1)}% ${message ?? ''}`);
125
+ },
126
+ },
127
+ );
227
128
 
228
- // Delete a region
129
+ // Manage
130
+ await offlineManager.listStoredRegions();
131
+ await offlineManager.getStoredRegion('downtown');
229
132
  await offlineManager.deleteRegion('downtown');
230
- ```
231
-
232
- ### Analytics & Monitoring
233
-
234
- ```typescript
235
- // Get comprehensive storage analytics
236
- const analytics = await offlineManager.getComprehensiveStorageAnalytics();
237
- console.log(`Total storage: ${analytics.totalStorageSize} bytes`);
238
- console.log(`Tiles: ${analytics.tiles.count} (${analytics.tiles.totalSize} bytes)`);
239
- console.log(`Fonts: ${analytics.fonts.count} (${analytics.fonts.totalSize} bytes)`);
240
- console.log(`Sprites: ${analytics.sprites.count} (${analytics.sprites.totalSize} bytes)`);
241
- console.log(`Recommendations:`, analytics.recommendations);
242
- ```
243
-
244
- ### Cleanup & Maintenance
245
-
246
- ```typescript
247
- // Clean up expired regions
248
- const deletedCount = await offlineManager.cleanupExpiredRegions();
249
- console.log(`Cleaned ${deletedCount} expired regions`);
250
-
251
- // Verify and repair fonts
252
- const verification = await offlineManager.verifyAndRepairFonts('style_123', { removeCorrupted: true });
253
- console.log(`Verified: ${verification.verified}, Repaired: ${verification.repaired}, Removed: ${verification.removed}`);
254
-
255
- // Set up automatic cleanup (runs every 24 hours)
256
- const cleanupId = await offlineManager.setupAutoCleanup({
257
- intervalHours: 24,
258
- maxAge: 30, // days
259
- });
260
- ```
261
-
262
- ## ๐Ÿ“š API Reference
263
-
264
- ### OfflineMapManager
265
-
266
- Main class for managing offline maps.
267
-
268
- **Constructor:**
269
-
270
- ```typescript
271
- const manager = new OfflineMapManager(overrides?: OfflineManagerServiceOverrides);
272
- ```
273
133
 
274
- The constructor accepts optional service overrides for dependency injection (advanced usage). For most cases, use the default: `new OfflineMapManager()`.
275
-
276
- **Core Methods:**
277
-
278
- - `addRegion(options: OfflineRegionOptions)` - Download and store a map region
279
- - `getStoredRegion(id: string)` - Retrieve a stored region by ID
280
- - `deleteRegion(id: string)` - Delete a specific region and its resources
281
- - `listStoredRegions()` - List all stored regions with metadata
282
- - `listRegions()` - List all region options
283
-
284
- **Analytics Methods:**
285
-
286
- - `getComprehensiveStorageAnalytics()` - Get detailed storage statistics
287
- - `getRegionAnalytics()` - Get aggregate analytics across all regions
288
- - `getTileStatistics(styleId: string)` - Get tile-specific statistics
289
- - `getFontStatistics(styleId: string)` - Get font statistics
290
- - `getSpriteStatistics(styleId: string)` - Get sprite statistics
291
-
292
- **Cleanup & Maintenance Methods:**
293
-
294
- - `cleanupExpiredRegions()` - Remove regions past expiration date
295
- - `performSmartCleanup(options)` - Intelligent cleanup with configurable criteria
296
- - `cleanupOldFonts(styleId?, options?)` - Remove old font data
297
- - `cleanupOldSprites(styleId?, options?)` - Remove old sprite data
298
- - `cleanupOldGlyphs(styleId?, options?)` - Remove old glyph data
299
- - `verifyAndRepairFonts(styleId, options?)` - Verify font integrity
300
- - `verifyAndRepairSprites(styleId, options?)` - Verify sprite integrity
301
- - `verifyAndRepairGlyphs(styleId, options?)` - Verify glyph integrity
302
- - `setupAutoCleanup(options)` - Enable automatic periodic cleanup
303
- - `stopAutoCleanup(cleanupId?)` - Disable a specific auto-cleanup
304
- - `stopAllAutoCleanup()` - Disable all auto-cleanups
305
- - `performCompleteMaintenance(options?)` - Run comprehensive maintenance
306
-
307
- ### OfflineManagerControl
308
-
309
- UI control for MapLibre GL JS and Mapbox GL JS with glassmorphic design.
310
-
311
- **Constructor:**
312
-
313
- ```typescript
314
- const offlineManager = new OfflineMapManager();
315
-
316
- const control = new OfflineManagerControl(offlineManager, {
317
- styleUrl: 'https://example.com/style.json', // Map style URL (required)
318
- theme?: 'light' | 'dark', // UI theme (default: 'dark')
319
- showBbox?: boolean, // Show region bounding boxes (default: false)
320
- accessToken?: string, // Mapbox access token (for mapbox:// URLs)
321
- mapLib?: MapLibProtocol, // Map library module (e.g. maplibregl) for idb:// protocol
322
- });
134
+ // Analytics & cleanup
135
+ await offlineManager.getComprehensiveStorageAnalytics();
136
+ await offlineManager.cleanupExpiredRegions();
137
+ await offlineManager.setupAutoCleanup({ intervalHours: 24, maxAge: 30 });
323
138
  ```
324
139
 
325
- **Features:**
140
+ ### Sparse-source detection
326
141
 
327
- - Interactive polygon drawing for region selection
328
- - Real-time download progress tracking
329
- - Region management (view, delete)
330
- - Theme toggle (dark/light mode)
331
- - Storage analytics display
332
- - Language switcher (English / Arabic with RTL support)
333
- - Responsive mobile-friendly design
142
+ For composite styles (e.g. Mapbox Standard) that reference sparse tilesets like `indoor-v3` or `landmark-pois-v1`, the tile downloader probes start/middle/end tiles per source and drops any that return majority-404. Disable with `tileOptions: { probeSourcesBeforeDownload: false }`.
334
143
 
335
- ## ๐Ÿ”ง Configuration Options
144
+ ### Recovering from an incompatible DB
336
145
 
337
- ### OfflineRegionOptions
146
+ If another app on the same origin has created `offline-map-db` at a newer version, `dbPromise` throws a typed error. Offer a reset UX:
338
147
 
339
148
  ```typescript
340
- interface OfflineRegionOptions {
341
- id: string; // Unique region identifier
342
- name: string; // Human-readable name (required)
343
- bounds: [[number, number], [number, number]]; // [[lng, lat], [lng, lat]]
344
- minZoom: number; // Minimum zoom level (e.g., 10)
345
- maxZoom: number; // Maximum zoom level (e.g., 16)
346
- styleUrl?: string; // Map style URL
347
- expiry?: number; // Expiration timestamp (ms since epoch)
348
- deleteOnExpiry?: boolean; // Auto-delete on expiration
349
- multipleRegions?: boolean; // Part of a multi-region download
350
- tileExtension?: string; // Tile extension (pbf, mvt, png, etc.)
351
- extraSources?: ExtraSource[]; // Additional tile sources to download alongside the style
352
- }
353
-
354
- interface ExtraSource {
355
- id: string; // Unique source identifier
356
- type?: 'vector' | 'raster' | 'raster-dem'; // Defaults to 'vector'
357
- tiles: string[]; // Tile URL templates with {z}/{x}/{y}
358
- minzoom?: number;
359
- maxzoom?: number;
360
- attribution?: string;
361
- }
362
- ```
363
-
364
- ### Extra Tile Sources
365
-
366
- Save additional vector or raster layers (e.g. custom overlays) alongside the style's own sources:
367
-
368
- ```typescript
369
- await manager.addRegion({
370
- id: 'downtown',
371
- name: 'Downtown',
372
- bounds: [[-74.05, 40.71], [-74.00, 40.76]],
373
- minZoom: 10,
374
- maxZoom: 16,
375
- styleUrl: 'https://example.com/style.json',
376
- extraSources: [
377
- {
378
- id: 'buildings',
379
- type: 'vector',
380
- tiles: ['https://tiles.example.com/buildings/{z}/{x}/{y}.pbf'],
381
- minzoom: 13,
382
- maxzoom: 16,
383
- },
384
- ],
385
- });
386
- ```
387
-
388
- When using the `OfflineManagerControl`, the region download form auto-discovers tile sources on the live map and shows them as checkboxes โ€” users pick which extra layers to include.
389
-
390
- ## ๐ŸŽฏ Use Cases
391
-
392
- - ๐Ÿ”๏ธ **Outdoor & Recreation Apps**: Hiking, camping, and adventure apps with offline trail maps
393
- - ๐Ÿ“ฑ **Field Data Collection**: Survey and data collection in remote areas
394
- - ๐Ÿšจ **Emergency Response**: Critical map access during network outages
395
- - โœˆ๏ธ **Travel Apps**: Tourist apps with offline city maps
396
- - ๐Ÿš— **Fleet Management**: Vehicle tracking with offline map fallback
397
- - ๐Ÿ“Š **Asset Management**: Field service apps with offline capability
398
- - ๐ŸŽ“ **Educational Apps**: Geography and learning apps with downloadable maps
399
- - ๐Ÿ—๏ธ **Construction & Engineering**: Site management with offline blueprints
400
- - ๐Ÿ’พ **Bandwidth Optimization**: Reduce data costs by pre-downloading maps
401
-
402
- ## ๐Ÿ’ก Best Practices
149
+ import { dbPromise, OfflineMapDBVersionError, resetOfflineMapDB } from 'map-gl-offline';
403
150
 
404
- ### Performance Optimization
405
-
406
- ```typescript
407
- // Balance quality vs storage with appropriate zoom levels
408
- const region = {
409
- minZoom: 10, // Don't go too low (tile count grows exponentially)
410
- maxZoom: 16, // Don't go too high (diminishing returns)
411
- bounds: [
412
- /* ... */
413
- ],
414
- };
415
-
416
- // Monitor storage usage
417
- const analytics = await manager.getComprehensiveStorageAnalytics();
418
- if (analytics.totalStorageSize > 500 * 1024 * 1024) {
419
- console.warn('High storage usage detected');
420
- await manager.performSmartCleanup({ maxStorageSize: 500 * 1024 * 1024 });
421
- }
422
-
423
- // Use progressive loading for better UX
424
- const progressiveDownload = {
425
- priorityZoomLevels: [12, 13, 11, 14, 10, 15, 16],
426
- onProgress: p => updateUI(p),
427
- };
428
- ```
429
-
430
- ### Error Handling
431
-
432
- ```typescript
433
151
  try {
434
- await manager.addRegion(regionOptions);
435
- } catch (error) {
436
- if (error.message.includes('quota')) {
437
- console.error('Storage quota exceeded');
438
- await manager.cleanupExpiredRegions();
439
- } else if (error.message.includes('network')) {
440
- console.error('Network error. Retrying...');
441
- } else {
442
- console.error('Unexpected error:', error);
152
+ await dbPromise;
153
+ } catch (err) {
154
+ if (err instanceof OfflineMapDBVersionError) {
155
+ if (confirm('Offline storage is incompatible. Clear it?')) {
156
+ await resetOfflineMapDB(); // destructive
157
+ location.reload();
158
+ }
443
159
  }
444
160
  }
445
161
  ```
446
162
 
447
- ## ๐ŸŒ Browser Compatibility
448
-
449
- | Browser | Version | Support |
450
- | ------- | ------- | ------- |
451
- | Chrome | 51+ | โœ… |
452
- | Firefox | 45+ | โœ… |
453
- | Safari | 10+ | โœ… |
454
- | Edge | 79+ | โœ… |
455
- | Mobile | Modern | โœ… |
163
+ ## API at a glance
456
164
 
457
- **Requirements:**
165
+ - **Regions** โ€” `downloadRegion`, `loadRegion`, `addRegion`, `getStoredRegion`, `listStoredRegions`, `listRegions`, `deleteRegion`
166
+ - **Analytics** โ€” `getComprehensiveStorageAnalytics`, `getRegionAnalytics`, `getTileStats`, `getFontStats`, `getSpriteStats`, `getGlyphStats`
167
+ - **Cleanup** โ€” `cleanupExpiredRegions`, `performSmartCleanup`, `cleanupOld{Fonts,Sprites,Glyphs}`, `verifyAndRepair{Fonts,Sprites,Glyphs}`, `setupAutoCleanup`, `performCompleteMaintenance`
168
+ - **Import / Export** โ€” `exportRegionAsJSON`, `exportRegionAsPMTiles`, `exportRegionAsMBTiles`, `importRegion`
169
+ - **Storage utilities** โ€” `dbPromise`, `OfflineMapDBVersionError`, `resetOfflineMapDB`, `loadAllStoredRegions`, `resourceKeyBelongsToStyle`
458
170
 
459
- - IndexedDB support
460
- - ES2015+ JavaScript
461
- - Async/await support
462
- - Web Workers (optional, for background tasks)
171
+ See the **[full API reference](https://map-gl-offline.netlify.app/docs/api-reference)** and **[examples](https://map-gl-offline.netlify.app/docs/examples)** for every option and pattern.
463
172
 
464
- ## ๐Ÿค Contributing
173
+ ## Browser compatibility
465
174
 
466
- Contributions are welcome!
175
+ Chrome 51+ ยท Firefox 45+ ยท Safari 10+ ยท Edge 79+ ยท modern mobile browsers. Requires IndexedDB and ES2015+.
467
176
 
468
- ### Development Setup
177
+ ## Contributing
469
178
 
470
179
  ```bash
471
- # Clone repository
472
180
  git clone https://github.com/muimsd/map-gl-offline.git
473
- cd map-gl-offline
474
-
475
- # Install dependencies
476
- npm install
477
-
478
- # Run development server
479
- npm run dev
480
-
481
- # Run tests
482
- npm test
483
-
484
- # Build library
485
- npm run build
486
-
487
- # Run MapLibre example app
488
- cd examples/maplibre
489
- npm install
490
- npm run dev
181
+ cd map-gl-offline && npm install
182
+ npm run dev # dev harness
183
+ npm test # unit tests
184
+ npm run build # library
491
185
  ```
492
186
 
493
- ### Project Structure
187
+ Issues and PRs welcome. See [CHANGELOG.md](CHANGELOG.md) for release notes.
494
188
 
495
- ```
496
- map-gl-offline/
497
- โ”œโ”€โ”€ src/
498
- โ”‚ โ”œโ”€โ”€ managers/ # Core offline manager
499
- โ”‚ โ”œโ”€โ”€ services/ # Tile, font, sprite services
500
- โ”‚ โ”œโ”€โ”€ storage/ # IndexedDB management
501
- โ”‚ โ”œโ”€โ”€ ui/ # UI components & controls
502
- โ”‚ โ”‚ โ””โ”€โ”€ translations/ # i18n (English, Arabic)
503
- โ”‚ โ”œโ”€โ”€ utils/ # Utilities & helpers
504
- โ”‚ โ””โ”€โ”€ types/ # TypeScript definitions
505
- โ”œโ”€โ”€ bin/ # CLI (map-gl-offline init) & Vite plugin
506
- โ”œโ”€โ”€ examples/
507
- โ”‚ โ”œโ”€โ”€ maplibre/ # MapLibre GL JS example app
508
- โ”‚ โ””โ”€โ”€ mapbox-gl/ # Mapbox GL JS example app
509
- โ”œโ”€โ”€ docs/ # Docusaurus documentation site
510
- โ””โ”€โ”€ tests/ # Test suites
511
- ```
512
-
513
- ## ๐Ÿ“ž Support & Links
514
-
515
- - ๐Ÿ“š [Documentation](https://map-gl-offline.netlify.app)
516
- - ๐ŸŽฎ [Live Demo](https://map-gl-offline-demo.netlify.app)
517
- - ๐Ÿ› [Report Issues](https://github.com/muimsd/map-gl-offline/issues)
518
- - ๐Ÿ’ฌ [Discussions](https://github.com/muimsd/map-gl-offline/discussions)
519
- - โญ [Feature Requests](https://github.com/muimsd/map-gl-offline/issues/new)
520
- - ๐ŸŒŸ [Star on GitHub](https://github.com/muimsd/map-gl-offline)
521
-
522
- ## ๐Ÿ”„ Recent Updates
523
-
524
- See [CHANGELOG.md](CHANGELOG.md) for complete version history.
525
-
526
- **v0.5.5 (Latest):** Extra tile source selection for offline regions โ€” pick additional vector/raster layers to download alongside the style's own sources.
527
-
528
- **v0.5.3:** 28% bundle size reduction (783 KB to 565 KB), 20+ bug fixes, XSS prevention, import atomicity, `@/` path alias for all imports.
529
-
530
- **v0.5.2:** CLI command (`npx map-gl-offline init`), Vite plugin for Service Worker, Mapbox GL example app.
531
-
532
- **v0.5.0:** Mapbox GL JS support, Standard style with 3D/terrain, day/night presets, rain/snow, i18n (English & Arabic with RTL).
533
-
534
- ## ๐Ÿ™ Acknowledgments
535
-
536
- - [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js) - Open-source map rendering engine
537
- - [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) - Commercial map rendering engine
538
- - [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) - Browser storage API
539
- - [Tilebelt](https://github.com/mapbox/tilebelt) - Tile coordinate utilities
540
- - [Tailwind CSS](https://tailwindcss.com/) - Utility-first CSS framework
541
-
542
- ## ๐Ÿ“„ License
189
+ ## License
543
190
 
544
191
  MIT ยฉ [Muhammad Imran Siddique](https://github.com/muimsd)
545
192
 
@@ -547,10 +194,8 @@ MIT ยฉ [Muhammad Imran Siddique](https://github.com/muimsd)
547
194
 
548
195
  <div align="center">
549
196
 
550
- **Made with โค๏ธ for the mapping community**
551
-
552
- [๐Ÿ“– Documentation](https://map-gl-offline.netlify.app) โ€ข [๐ŸŽฎ Live Demo](https://map-gl-offline-demo.netlify.app) โ€ข [โญ Star on GitHub](https://github.com/muimsd/map-gl-offline)
197
+ [๐Ÿ“– Docs](https://map-gl-offline.netlify.app) ยท [๐ŸŽฎ Demo](https://map-gl-offline-demo.netlify.app) ยท [โญ GitHub](https://github.com/muimsd/map-gl-offline)
553
198
 
554
- <a href="https://www.buymeacoffee.com/muimsd" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
199
+ <a href="https://www.buymeacoffee.com/muimsd" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 45px;"></a>
555
200
 
556
201
  </div>
package/dist/index.d.ts CHANGED
@@ -34,14 +34,23 @@
34
34
  * ```typescript
35
35
  * const offlineManager = new OfflineMapManager();
36
36
  *
37
- * await offlineManager.addRegion({
38
- * id: 'sf',
39
- * name: 'San Francisco',
40
- * bounds: [[-122.5, 37.7], [-122.3, 37.9]],
41
- * minZoom: 10,
42
- * maxZoom: 14,
43
- * styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY'
44
- * });
37
+ * // downloadRegion runs the full pipeline: style (if missing) โ†’ sprites โ†’ glyphs โ†’ tiles โ†’ metadata.
38
+ * // addRegion on its own only stores metadata; use downloadRegion to actually fetch assets.
39
+ * await offlineManager.downloadRegion(
40
+ * {
41
+ * id: 'sf',
42
+ * name: 'San Francisco',
43
+ * bounds: [[-122.5, 37.7], [-122.3, 37.9]],
44
+ * minZoom: 10,
45
+ * maxZoom: 14,
46
+ * styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
47
+ * },
48
+ * {
49
+ * onProgress: ({ phase, completed, total, percentage }) => {
50
+ * console.log(`[${phase}] ${completed}/${total} (${percentage.toFixed(1)}%)`);
51
+ * },
52
+ * }
53
+ * );
45
54
  * ```
46
55
  */
47
56
  export { OfflineMapManager } from './managers/offlineMapManager';