@versatiles/container 1.2.8 → 1.3.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/dist/index.d.ts CHANGED
@@ -34,7 +34,7 @@
34
34
  * ```
35
35
  */
36
36
  import type { Block, Header, OpenOptions, Reader, TileIndex } from './lib/interfaces.js';
37
- export type { Block, Compression, Format, Header, OpenOptions, Reader, TileIndex } from './lib/interfaces.js';
37
+ export type { Block, Compression, Format, Header, OpenOptions, Reader, TileIndex, } from './lib/interfaces.js';
38
38
  /**
39
39
  * The `VersaTiles` class is a wrapper around a `.versatiles` container file. It provides methods
40
40
  * to access tile data, metadata, and other properties within the container.
package/dist/index.js CHANGED
@@ -37,26 +37,77 @@ import HttpReader from './lib/reader_http.js';
37
37
  import FileReader from './lib/reader_file.js';
38
38
  import { decompress } from './lib/decompress.js';
39
39
  const FORMATS = {
40
- 'c01': ['png', 'jpg', 'webp', null, null, null, null, null, null, null, null, null, null, null, null, null, 'pbf'],
41
- 'v01': ['png', 'jpg', 'webp', 'pbf'],
42
- 'v02': [
43
- 'bin', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
44
- 'png', 'jpg', 'webp', 'avif', 'svg', null, null, null, null, null, null, null, null, null, null, null,
45
- 'pbf', 'geojson', 'topojson', 'json',
40
+ c01: [
41
+ 'png',
42
+ 'jpg',
43
+ 'webp',
44
+ null,
45
+ null,
46
+ null,
47
+ null,
48
+ null,
49
+ null,
50
+ null,
51
+ null,
52
+ null,
53
+ null,
54
+ null,
55
+ null,
56
+ null,
57
+ 'pbf',
58
+ ],
59
+ v01: ['png', 'jpg', 'webp', 'pbf'],
60
+ v02: [
61
+ 'bin',
62
+ null,
63
+ null,
64
+ null,
65
+ null,
66
+ null,
67
+ null,
68
+ null,
69
+ null,
70
+ null,
71
+ null,
72
+ null,
73
+ null,
74
+ null,
75
+ null,
76
+ null,
77
+ 'png',
78
+ 'jpg',
79
+ 'webp',
80
+ 'avif',
81
+ 'svg',
82
+ null,
83
+ null,
84
+ null,
85
+ null,
86
+ null,
87
+ null,
88
+ null,
89
+ null,
90
+ null,
91
+ null,
92
+ null,
93
+ 'pbf',
94
+ 'geojson',
95
+ 'topojson',
96
+ 'json',
46
97
  ],
47
98
  };
48
99
  const COMPRESSIONS = ['raw', 'gzip', 'br'];
49
100
  const MIMETYPES = {
50
- 'avif': 'image/avif',
51
- 'bin': 'application/octet-stream',
52
- 'geojson': 'application/geo+json; charset=utf-8',
53
- 'jpg': 'image/jpeg',
54
- 'json': 'application/json; charset=utf-8',
55
- 'pbf': 'application/x-protobuf',
56
- 'png': 'image/png',
57
- 'svg': 'image/svg+xml; charset=utf-8',
58
- 'topojson': 'application/topo+json; charset=utf-8',
59
- 'webp': 'image/webp',
101
+ avif: 'image/avif',
102
+ bin: 'application/octet-stream',
103
+ geojson: 'application/geo+json; charset=utf-8',
104
+ jpg: 'image/jpeg',
105
+ json: 'application/json; charset=utf-8',
106
+ pbf: 'application/x-protobuf',
107
+ png: 'image/png',
108
+ svg: 'image/svg+xml; charset=utf-8',
109
+ topojson: 'application/topo+json; charset=utf-8',
110
+ webp: 'image/webp',
60
111
  };
61
112
  /**
62
113
  * The `VersaTiles` class is a wrapper around a `.versatiles` container file. It provides methods
@@ -125,15 +176,38 @@ export class Container {
125
176
  const blockIndexLength = Number(data.readBigUInt64BE(58));
126
177
  switch (version) {
127
178
  case 'v01':
128
- bbox = [data.readFloatBE(18), data.readFloatBE(22), data.readFloatBE(26), data.readFloatBE(30)];
179
+ bbox = [
180
+ data.readFloatBE(18),
181
+ data.readFloatBE(22),
182
+ data.readFloatBE(26),
183
+ data.readFloatBE(30),
184
+ ];
129
185
  break;
130
186
  case 'v02':
131
- bbox = [data.readInt32BE(18) / 1e7, data.readInt32BE(22) / 1e7, data.readInt32BE(26) / 1e7, data.readInt32BE(30) / 1e7];
187
+ bbox = [
188
+ data.readInt32BE(18) / 1e7,
189
+ data.readInt32BE(22) / 1e7,
190
+ data.readInt32BE(26) / 1e7,
191
+ data.readInt32BE(30) / 1e7,
192
+ ];
132
193
  break;
133
194
  default:
134
195
  throw new Error('Invalid Container');
135
196
  }
136
- this.#header = { magic, version, tileFormat, tileMime, tileCompression, zoomMin, zoomMax, bbox, metaOffset, metaLength, blockIndexOffset, blockIndexLength };
197
+ this.#header = {
198
+ magic,
199
+ version,
200
+ tileFormat,
201
+ tileMime,
202
+ tileCompression,
203
+ zoomMin,
204
+ zoomMax,
205
+ bbox,
206
+ metaOffset,
207
+ metaLength,
208
+ blockIndexOffset,
209
+ blockIndexLength,
210
+ };
137
211
  return this.#header;
138
212
  }
139
213
  /**
@@ -178,8 +252,8 @@ export class Container {
178
252
  const bx = x >> 8;
179
253
  const by = y >> 8;
180
254
  // tile xy (within block)
181
- const tx = x & 0xFF;
182
- const ty = y & 0xFF;
255
+ const tx = x & 0xff;
256
+ const ty = y & 0xff;
183
257
  // check if block containing tile is within bounds
184
258
  const blockKey = `${z},${bx},${by}`;
185
259
  const block = blockIndex.get(blockKey);
@@ -237,7 +311,7 @@ export class Container {
237
311
  switch (header.version) {
238
312
  case 'c01':
239
313
  case 'v01':
240
- // check blog index length
314
+ // check block index length
241
315
  if (data.length % 29 !== 0)
242
316
  throw new Error('invalid block index');
243
317
  for (let i = 0; i < data.length; i += 29) {
@@ -246,7 +320,7 @@ export class Container {
246
320
  }
247
321
  break;
248
322
  case 'v02':
249
- // check blog index length
323
+ // check block index length
250
324
  if (data.length % 33 !== 0)
251
325
  throw new Error('invalid block index');
252
326
  for (let i = 0; i < data.length; i += 33) {
@@ -257,7 +331,7 @@ export class Container {
257
331
  break;
258
332
  }
259
333
  // build map
260
- this.#blockIndex = new Map(blocks.map(b => [`${b.level},${b.column},${b.row}`, b]));
334
+ this.#blockIndex = new Map(blocks.map((b) => [`${b.level},${b.column},${b.row}`, b]));
261
335
  return this.#blockIndex;
262
336
  function addBlock(buffer, blockOffset, tileIndexOffset, tileIndexLength) {
263
337
  const block = {
@@ -34,7 +34,7 @@ export async function decompress(buffer, compression) {
34
34
  */
35
35
  function handle(error, result) {
36
36
  if (error) {
37
- reject(`Can not decompress buffer (length=${buffer.length}) with "${compression}"`);
37
+ reject(new Error(`Can not decompress buffer (length=${buffer.length}) with "${compression}": ${error.message}`));
38
38
  return;
39
39
  }
40
40
  else {
@@ -17,6 +17,10 @@ const clients = {
17
17
  * @returns A `Reader` function that asynchronously reads a specified chunk of data from the URL.
18
18
  */
19
19
  export default function getHTTPReader(url) {
20
+ const protocol = new URL(url).protocol.slice(0, -1);
21
+ if (!(protocol in clients)) {
22
+ throw new Error(`Unsupported protocol: ${protocol}`);
23
+ }
20
24
  /**
21
25
  * Asynchronously reads a data chunk from the provided URL based on the specified range.
22
26
  *
@@ -35,37 +39,39 @@ export default function getHTTPReader(url) {
35
39
  }
36
40
  const headers = {
37
41
  'user-agent': 'Mozilla/5.0 (compatible; versatiles; +https://www.npmjs.com/package/versatiles)',
38
- 'range': `bytes=${position}-${position + length - 1}`,
42
+ range: `bytes=${position}-${position + length - 1}`,
39
43
  };
40
- const protocol = new URL(url).protocol.slice(0, -1);
41
- if (!(protocol in clients)) {
42
- throw new Error(`Unsupported protocol: ${protocol}`);
43
- }
44
44
  /**
45
45
  * Performs the HTTP request and retrieves the response.
46
46
  * @type {IncomingMessage}
47
47
  */
48
48
  const message = await new Promise((resolve, reject) => {
49
49
  const watchdog = setTimeout(() => {
50
+ req.destroy();
50
51
  reject(new Error('Request timed out'));
51
52
  }, DEFAULT_TIMEOUT);
52
- clients[protocol].client
53
+ const req = clients[protocol].client
53
54
  .request(url, {
54
55
  method: 'GET',
55
56
  agent: clients[protocol].agent,
56
57
  headers,
57
58
  timeout: DEFAULT_TIMEOUT,
58
59
  })
59
- .on('response', response => {
60
+ .on('response', (response) => {
60
61
  clearTimeout(watchdog);
61
62
  resolve(response);
62
63
  })
63
- .on('error', err => {
64
+ .on('error', (err) => {
64
65
  clearTimeout(watchdog);
66
+ req.destroy();
65
67
  reject(err);
66
68
  })
67
69
  .end();
68
70
  });
71
+ if (message.statusCode == null || Math.floor(message.statusCode / 100) !== 2) {
72
+ message.destroy();
73
+ throw new Error(`Server responded with status code: ${message.statusCode} `);
74
+ }
69
75
  const contentRange = message.headers['content-range'];
70
76
  if (contentRange == null)
71
77
  throw Error('The response header does not contain "content-range"');
@@ -73,7 +79,7 @@ export default function getHTTPReader(url) {
73
79
  if (parts == null)
74
80
  throw Error('"content-range" in response header is malformed');
75
81
  if (position !== parseInt(parts[1], 10))
76
- throw Error(`requestet position (${position}) and returned offset (${parts[1]}) must be equal`);
82
+ throw Error(`requested position (${position}) and returned offset (${parts[1]}) must be equal`);
77
83
  if (position + length > parseInt(parts[3], 10)) {
78
84
  throw new RangeError(`Read range out of bounds: The requested range ends at position ${position + length}, which exceeds the file's limit of ${parts[3]} bytes.`);
79
85
  }
@@ -81,10 +87,6 @@ export default function getHTTPReader(url) {
81
87
  if (length !== returnedLength) {
82
88
  throw new Error(`Returned length (${returnedLength}) is not requested length (${length}).`);
83
89
  }
84
- if ((message.statusCode == null) || Math.floor(message.statusCode / 100) !== 2) {
85
- message.destroy();
86
- throw new Error(`Server responded with status code: ${message.statusCode} `);
87
- }
88
90
  /**
89
91
  * Collects and concatenates response data chunks into a buffer.
90
92
  * @type {Buffer}
@@ -93,7 +95,7 @@ export default function getHTTPReader(url) {
93
95
  const buffers = [];
94
96
  message
95
97
  .on('data', (chunk) => buffers.push(chunk))
96
- .on('error', err => {
98
+ .on('error', (err) => {
97
99
  message.destroy();
98
100
  reject(err);
99
101
  })
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@versatiles/container",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "description": "A client library for reading VersaTiles containers",
5
5
  "scripts": {
6
6
  "build": "rm -rf dist && tsc -p tsconfig.build.json && npm run doc-graph",
7
- "check": "npm run lint && npm run build && npm run test",
7
+ "check": "npm run format:check && npm run lint && npm run build && npm run test",
8
8
  "doc": "npm run doc-typescript && npm run doc-graph",
9
9
  "doc-typescript": "vrt doc-typescript -f html",
10
10
  "doc-graph": "vrt deps-graph | vrt doc-insert README.md '## Dependency Graph'",
11
+ "format": "prettier --write 'src/**/*.ts'",
12
+ "format:check": "prettier --check 'src/**/*.ts'",
11
13
  "lint": "eslint . --color",
12
14
  "prepack": "npm run build",
13
15
  "release": "vrt release-npm",
@@ -23,7 +25,7 @@
23
25
  "type": "git",
24
26
  "url": "git+https://github.com/versatiles-org/node-versatiles-container.git"
25
27
  },
26
- "homepage": "https://github.com/versatiles-org/node-versatiles-container/blob/main/versatiles-container/README.md",
28
+ "homepage": "https://github.com/versatiles-org/node-versatiles-container",
27
29
  "main": "dist/index.js",
28
30
  "types": "dist/index.d.ts",
29
31
  "type": "module",
@@ -51,16 +53,18 @@
51
53
  "versatiles"
52
54
  ],
53
55
  "devDependencies": {
54
- "@types/node": "^24.10.1",
55
- "@typescript-eslint/eslint-plugin": "^8.47.0",
56
- "@typescript-eslint/parser": "^8.47.0",
57
- "@versatiles/release-tool": "^2.4.5",
58
- "@vitest/coverage-v8": "^4.0.10",
59
- "eslint": "^9.39.1",
56
+ "@types/node": "^25.2.3",
57
+ "@typescript-eslint/eslint-plugin": "^8.55.0",
58
+ "@typescript-eslint/parser": "^8.55.0",
59
+ "@versatiles/release-tool": "^2.7.1",
60
+ "@vitest/coverage-v8": "^4.0.18",
61
+ "eslint": "^9.39.2",
62
+ "eslint-config-prettier": "^10.1.8",
63
+ "prettier": "^3.8.1",
60
64
  "ts-node": "^10.9.2",
61
- "tsx": "^4.20.6",
65
+ "tsx": "^4.21.0",
62
66
  "typescript": "^5.9.3",
63
- "typescript-eslint": "^8.47.0",
64
- "vitest": "^4.0.10"
67
+ "typescript-eslint": "^8.55.0",
68
+ "vitest": "^4.0.18"
65
69
  }
66
70
  }