@internetdata/internetdata 1.0.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -0
  3. package/dist/client.d.ts +123 -0
  4. package/dist/client.js +253 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/errors.d.ts +29 -0
  7. package/dist/errors.js +74 -0
  8. package/dist/errors.js.map +1 -0
  9. package/dist/generated/client/client.gen.d.ts +2 -0
  10. package/dist/generated/client/client.gen.js +217 -0
  11. package/dist/generated/client/client.gen.js.map +1 -0
  12. package/dist/generated/client/index.d.ts +10 -0
  13. package/dist/generated/client/index.js +7 -0
  14. package/dist/generated/client/index.js.map +1 -0
  15. package/dist/generated/client/types.gen.d.ts +120 -0
  16. package/dist/generated/client/types.gen.js +3 -0
  17. package/dist/generated/client/types.gen.js.map +1 -0
  18. package/dist/generated/client/utils.gen.d.ts +37 -0
  19. package/dist/generated/client/utils.gen.js +229 -0
  20. package/dist/generated/client/utils.gen.js.map +1 -0
  21. package/dist/generated/client.gen.d.ts +12 -0
  22. package/dist/generated/client.gen.js +4 -0
  23. package/dist/generated/client.gen.js.map +1 -0
  24. package/dist/generated/core/auth.gen.d.ts +25 -0
  25. package/dist/generated/core/auth.gen.js +15 -0
  26. package/dist/generated/core/auth.gen.js.map +1 -0
  27. package/dist/generated/core/bodySerializer.gen.d.ts +25 -0
  28. package/dist/generated/core/bodySerializer.gen.js +58 -0
  29. package/dist/generated/core/bodySerializer.gen.js.map +1 -0
  30. package/dist/generated/core/params.gen.d.ts +43 -0
  31. package/dist/generated/core/params.gen.js +110 -0
  32. package/dist/generated/core/params.gen.js.map +1 -0
  33. package/dist/generated/core/pathSerializer.gen.d.ts +33 -0
  34. package/dist/generated/core/pathSerializer.gen.js +107 -0
  35. package/dist/generated/core/pathSerializer.gen.js.map +1 -0
  36. package/dist/generated/core/queryKeySerializer.gen.d.ts +18 -0
  37. package/dist/generated/core/queryKeySerializer.gen.js +93 -0
  38. package/dist/generated/core/queryKeySerializer.gen.js.map +1 -0
  39. package/dist/generated/core/serverSentEvents.gen.d.ts +71 -0
  40. package/dist/generated/core/serverSentEvents.gen.js +133 -0
  41. package/dist/generated/core/serverSentEvents.gen.js.map +1 -0
  42. package/dist/generated/core/types.gen.d.ts +83 -0
  43. package/dist/generated/core/types.gen.js +3 -0
  44. package/dist/generated/core/types.gen.js.map +1 -0
  45. package/dist/generated/core/utils.gen.d.ts +19 -0
  46. package/dist/generated/core/utils.gen.js +88 -0
  47. package/dist/generated/core/utils.gen.js.map +1 -0
  48. package/dist/generated/index.d.ts +2 -0
  49. package/dist/generated/index.js +3 -0
  50. package/dist/generated/index.js.map +1 -0
  51. package/dist/generated/sdk.gen.d.ts +84 -0
  52. package/dist/generated/sdk.gen.js +116 -0
  53. package/dist/generated/sdk.gen.js.map +1 -0
  54. package/dist/generated/types.gen.d.ts +538 -0
  55. package/dist/generated/types.gen.js +3 -0
  56. package/dist/generated/types.gen.js.map +1 -0
  57. package/dist/index.d.ts +6 -0
  58. package/dist/index.js +4 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/types.d.ts +11 -0
  61. package/dist/types.js +10 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mslm Dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # [<img src="https://s3.internetdata.io/internetdata-public/brand/mark.svg" alt="InternetData" width="24"/>](https://internetdata.io/) InternetData Node.js Client Library
2
+
3
+ [![npm](https://img.shields.io/npm/v/@internetdata/internetdata.svg)](https://www.npmjs.com/package/@internetdata/internetdata)
4
+ [![license](https://img.shields.io/npm/l/@internetdata/internetdata.svg)](LICENSE)
5
+
6
+ The official Node.js client library for the [InternetData](https://internetdata.io) API.
7
+
8
+ InternetData publishes IP databases: VPN and proxy address space, hosting and CDN ranges, provider catalogs, bogons and more, as gzipped CSV and as MMDB. This library lists the databases your organization is licensed for, tells you what is inside one before you fetch it, downloads it, and verifies the bytes you got.
9
+
10
+ ## Getting Started
11
+
12
+ ```bash
13
+ npm install @internetdata/internetdata
14
+ ```
15
+
16
+ Requires Node.js 22 or newer. TypeScript types are included.
17
+
18
+ ## Usage
19
+
20
+ Every call needs an API key carrying the `db.download` scope. Databases are licensed by contract rather than bought self-serve, so a key arrives with the licence; see the [API documentation](https://docs.internetdata.io/api) or write to [dev@internetdata.io](mailto:dev@internetdata.io).
21
+
22
+ ```js
23
+ import { InternetData } from '@internetdata/internetdata';
24
+
25
+ const client = new InternetData({ apiKey: process.env.INTERNETDATA_API_KEY });
26
+
27
+ for (const db of await client.database.list()) {
28
+ console.log(db.base, db.standing, db.versions.map((v) => v.id).join(', '));
29
+ }
30
+ ```
31
+
32
+ `list()` returns one entry per database FAMILY, because a licence is held against the family while a download names a specific version. `standing` is `licensed` if the family is yours today, `expired` if the term has ended, and `unlicensed` if it is published but has never been bought. `versions` carries the ids you pass everywhere else, oldest first, and the formats each one is actually built in.
33
+
34
+ **This listing is not the same for every key.** A database commissioned for a single customer is absent from the catalog for every other organization, rather than being listed as unlicensed. So the listing is only ever an answer about the key that asked, this library never caches one, and you should not carry an answer from one key over to another or treat it as the published catalog.
35
+
36
+ ### What is inside a database
37
+
38
+ ```js
39
+ const meta = await client.database.metadata('vpn_ip_v1');
40
+
41
+ console.log(meta.updated); // '2026-09-04', the day this build was generated
42
+ console.log(meta.entries); // rows in the build
43
+ console.log(meta.size.csvgz); // bytes you are about to move
44
+ console.log(meta.schema.csvgz); // [{ name, type, description }, ...]
45
+ console.log(meta.sample?.mmdb); // a few real rows
46
+ ```
47
+
48
+ Poll `updated` and `entries` to decide whether today's build is worth fetching; both are free of the transfer. `size` is also the honest way to budget a download before starting one.
49
+
50
+ ### Downloading
51
+
52
+ `download` streams a file to a path and returns the number of bytes written. Nothing larger than a chunk is ever held in memory, whatever the database weighs:
53
+
54
+ ```js
55
+ const written = await client.database.download('vpn_ip_v1', 'mmdb', './vpn_ip_v1.mmdb');
56
+ console.log(`${written} bytes`);
57
+ ```
58
+
59
+ The bytes go to a neighbouring `.part` file and the name only appears once the transfer completes, so an interruption cannot leave a truncated file that reads as a whole database. You can pass a writable stream instead of a path, in which case it stays yours to close and gets no such treatment.
60
+
61
+ Or take the link and run the transfer yourself. The API answers a redirect to time-limited object storage, and that URL authorizes itself, so it can be handed to something holding no API key:
62
+
63
+ ```js
64
+ const url = await client.database.downloadUrl('vpn_ip_v1', 'mmdb');
65
+ ```
66
+
67
+ Or, for a small database, take the bytes directly:
68
+
69
+ ```js
70
+ const bytes = await client.database.downloadBytes('bogon_ip_v1', 'csvgz');
71
+ ```
72
+
73
+ `downloadBytes` holds the whole file in memory and the catalog spans seven orders of magnitude, from a few hundred bytes to over 5 GiB, so use `download` for anything you have not checked with `metadata` first.
74
+
75
+ ### Verifying what you got
76
+
77
+ ```js
78
+ const sums = await client.database.checksums('vpn_ip_v1', 'mmdb');
79
+ console.log(sums.sha256); // also md5, sha1, sha512
80
+ ```
81
+
82
+ ### Download history
83
+
84
+ Your organization's recent attempts, newest first, refusals included, because a denial is what answers "it stopped working" and its absence answers nothing:
85
+
86
+ ```js
87
+ for (const d of await client.database.downloads({ limit: 20 })) {
88
+ console.log(d.created, d.dataset_id, d.format, d.outcome, d.http_status);
89
+ }
90
+ ```
91
+
92
+ ### Errors
93
+
94
+ Failures throw an `InternetDataError` carrying a `kind` and a `retryable` flag:
95
+
96
+ ```js
97
+ import { InternetDataError } from '@internetdata/internetdata';
98
+
99
+ try {
100
+ await client.database.download('vpn_ip_v1', 'mmdb', './vpn_ip_v1.mmdb');
101
+ } catch (err) {
102
+ if (err instanceof InternetDataError) {
103
+ console.error(err.kind, err.status, err.retryable);
104
+ }
105
+ }
106
+ ```
107
+
108
+ `kind` is one of `bad_request`, `unauthorized`, `forbidden`, `rate_limited`, `quota_exceeded`, `server_error` or `network`. The message is the API's own result code, such as `NOT_LICENSED` or `LICENSE_EXPIRED`, which is usually the specific thing you want to read.
109
+
110
+ Note that `rate_limited` and `quota_exceeded` both arrive as HTTP 429 and are not the same thing. A rate limit is the API facing a burst, so retrying later works; a spent quota needs your allowance raised or the window to roll over. The library retries the first for you and never the second.
111
+
112
+ A failure part way through a transfer is rethrown as it arrived rather than wrapped: a reset socket and a full disk are different problems, and only one of them is ours.
113
+
114
+ ## Other Libraries
115
+
116
+ There are official InternetData client libraries available for many languages including PHP, Python, Go, Java, Ruby, and many popular frameworks such as Django, Rails, and Laravel. See our GitHub at https://github.com/internetdata for more.
117
+
118
+ ## About InternetData
119
+
120
+ IP intelligence databases: VPN, proxy, hosting, CDN and relay address space, provider catalogs and network metadata, published as CSV and MMDB.
121
+
122
+ [<img src="https://s3.internetdata.io/internetdata-public/brand/mark.svg" alt="InternetData" width="96"/>](https://internetdata.io/)
123
+
124
+ ## License
125
+
126
+ This project is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,123 @@
1
+ import type { Writable } from 'node:stream';
2
+ import type { Client } from './generated/client/index.js';
3
+ import type { Database, DatabaseMetadata, DatasetFormat, DbChecksums, Download } from './types.js';
4
+ /**
5
+ * Where `download` puts the bytes: a path to write, or a stream you opened
6
+ * yourself and will close yourself.
7
+ */
8
+ export type DownloadDestination = string | Writable;
9
+ export declare const DEFAULT_BASE_URL = "https://internetdata.io";
10
+ export interface DownloadsOptions {
11
+ /** How many attempts to return, newest first. The API clamps this to 200. */
12
+ limit?: number;
13
+ }
14
+ export interface Options {
15
+ /**
16
+ * Your API key, carrying the `db.download` scope. Omit it to send no
17
+ * `Authorization` header at all, which is what a dataset offered without a
18
+ * licence would be read with.
19
+ */
20
+ apiKey?: string;
21
+ baseUrl?: string;
22
+ /** Retry attempts for a transient failure. Default 2. */
23
+ retries?: number;
24
+ /** Override the HTTP implementation, mostly for tests. */
25
+ fetch?: typeof globalThis.fetch;
26
+ }
27
+ /**
28
+ * A client for the InternetData API.
29
+ *
30
+ * Everything the API answers is scoped to the organization the key belongs to,
31
+ * including which databases are listed at all, so one client speaks for exactly
32
+ * one organization and nothing it learns may be reused for another key.
33
+ *
34
+ * The key is optional, and an absent one sends no `Authorization` header rather
35
+ * than an empty one. Every endpoint published today is licensed, so a keyless
36
+ * client is answered `401` for now; it exists because what the API serves
37
+ * without a licence is a product decision, not the client's to refuse.
38
+ */
39
+ export declare class InternetData {
40
+ /** The database catalog, downloads and their history. */
41
+ readonly database: DatabaseApi;
42
+ constructor(options?: Options);
43
+ }
44
+ /** The licensed database downloads. Access is granted by contract, not self-serve. */
45
+ export declare class DatabaseApi {
46
+ private readonly client;
47
+ private readonly retries;
48
+ private readonly fetchImpl;
49
+ constructor(client: Client, retries: number, fetchImpl: typeof globalThis.fetch);
50
+ /**
51
+ * The published catalog as your organization may see it, one entry per
52
+ * database FAMILY, with `standing` saying where your licence stands.
53
+ *
54
+ * **This listing is not the same for everyone, and it is not cached.** A
55
+ * database commissioned for a single customer is absent for every other
56
+ * organization rather than listed as unlicensed, so the answer is only ever
57
+ * the one this key's organization is entitled to see. Ask again rather than
58
+ * holding on to it, and never carry one key's answer over to another.
59
+ */
60
+ list(): Promise<Database[]>;
61
+ /**
62
+ * What is inside one database: its columns per format, sample rows, the row
63
+ * count, the byte size of each file, and the day it was last built.
64
+ *
65
+ * The cheap way to decide whether today's build is worth fetching, and the
66
+ * only way to know what a transfer will cost before starting it.
67
+ */
68
+ metadata(id: string): Promise<DatabaseMetadata>;
69
+ /**
70
+ * The digests for one database file.
71
+ *
72
+ * Returns the whole set rather than one algorithm: which digests a database
73
+ * publishes is the API's choice, not ours.
74
+ */
75
+ checksums(id: string, format: DatasetFormat): Promise<DbChecksums>;
76
+ /**
77
+ * Your organization's recent download attempts, newest first.
78
+ *
79
+ * Refusals are listed too: a denial is what answers "it stopped working",
80
+ * and its absence answers nothing.
81
+ */
82
+ downloads(options?: DownloadsOptions): Promise<Download[]>;
83
+ /**
84
+ * The time-limited URL for one database file.
85
+ *
86
+ * The API answers `302` to object storage. The URL is returned rather than
87
+ * the bytes so the caller decides how to transfer a file that runs to
88
+ * gigabytes; it carries its own authorization, so it can be handed to
89
+ * something that holds no API key. The link authorizes the START of a
90
+ * transfer, so one already running is not interrupted when it lapses.
91
+ */
92
+ downloadUrl(id: string, format: DatasetFormat): Promise<string>;
93
+ /**
94
+ * Download one database file, streaming it to `destination`.
95
+ *
96
+ * `destination` is either a path or a writable stream you opened yourself.
97
+ * A path is written through a neighboring `.part` file and renamed on
98
+ * completion, so a transfer that dies half way leaves no truncated file
99
+ * that reads as a whole database; a stream you pass is written as-is and
100
+ * stays yours to close. Nothing is ever held in memory beyond a single
101
+ * chunk, whatever the file weighs.
102
+ *
103
+ * Returns the number of bytes written.
104
+ *
105
+ * A failure DURING the transfer surfaces as the underlying error rather
106
+ * than an `InternetDataError`: a reset socket and a full disk are different
107
+ * problems and only one of them is ours.
108
+ */
109
+ download(id: string, format: DatasetFormat, destination: DownloadDestination): Promise<number>;
110
+ /**
111
+ * Download one database file and hand back its bytes.
112
+ *
113
+ * **This holds the entire file in memory**, and the catalog spans seven
114
+ * orders of magnitude: the smallest published build is a few hundred bytes,
115
+ * which is nothing, while the largest is over 5 GiB, which will cost you
116
+ * that much resident memory in one allocation and can fail outright. Reach
117
+ * for this at the small end, where the bytes are going straight into a
118
+ * parser; use `download` for anything you have not measured, and `metadata`
119
+ * to measure it before you do.
120
+ */
121
+ downloadBytes(id: string, format: DatasetFormat): Promise<Uint8Array>;
122
+ private fetchDatabaseFile;
123
+ }
package/dist/client.js ADDED
@@ -0,0 +1,253 @@
1
+ import pRetry from 'p-retry';
2
+ import { createClient, createConfig } from './generated/client/index.js';
3
+ import { databaseChecksumV2, databaseMetadataV2, downloadDatabaseV2 as downloadRedirect, listDatabases, listDownloads, } from './generated/sdk.gen.js';
4
+ import { errorFromResponse, InternetDataError, messageFromBody } from './errors.js';
5
+ export const DEFAULT_BASE_URL = 'https://internetdata.io';
6
+ /**
7
+ * A client for the InternetData API.
8
+ *
9
+ * Everything the API answers is scoped to the organization the key belongs to,
10
+ * including which databases are listed at all, so one client speaks for exactly
11
+ * one organization and nothing it learns may be reused for another key.
12
+ *
13
+ * The key is optional, and an absent one sends no `Authorization` header rather
14
+ * than an empty one. Every endpoint published today is licensed, so a keyless
15
+ * client is answered `401` for now; it exists because what the API serves
16
+ * without a licence is a product decision, not the client's to refuse.
17
+ */
18
+ export class InternetData {
19
+ /** The database catalog, downloads and their history. */
20
+ database;
21
+ constructor(options = {}) {
22
+ // Resolved once, because the download path calls object storage
23
+ // directly rather than through the generated client and has to reach
24
+ // the same implementation a test substituted.
25
+ const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
26
+ const client = createClient(createConfig({
27
+ baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
28
+ ...(options.apiKey === undefined ? {} : { auth: () => options.apiKey }),
29
+ fetch: fetchImpl,
30
+ }));
31
+ this.database = new DatabaseApi(client, options.retries ?? 2, fetchImpl);
32
+ }
33
+ }
34
+ /** The licensed database downloads. Access is granted by contract, not self-serve. */
35
+ export class DatabaseApi {
36
+ client;
37
+ retries;
38
+ fetchImpl;
39
+ constructor(client, retries, fetchImpl) {
40
+ this.client = client;
41
+ this.retries = retries;
42
+ this.fetchImpl = fetchImpl;
43
+ }
44
+ /**
45
+ * The published catalog as your organization may see it, one entry per
46
+ * database FAMILY, with `standing` saying where your licence stands.
47
+ *
48
+ * **This listing is not the same for everyone, and it is not cached.** A
49
+ * database commissioned for a single customer is absent for every other
50
+ * organization rather than listed as unlicensed, so the answer is only ever
51
+ * the one this key's organization is entitled to see. Ask again rather than
52
+ * holding on to it, and never carry one key's answer over to another.
53
+ */
54
+ async list() {
55
+ return withRetry(this.retries, async () => {
56
+ const res = await listDatabases({ client: this.client });
57
+ return unwrap(res).databases;
58
+ });
59
+ }
60
+ /**
61
+ * What is inside one database: its columns per format, sample rows, the row
62
+ * count, the byte size of each file, and the day it was last built.
63
+ *
64
+ * The cheap way to decide whether today's build is worth fetching, and the
65
+ * only way to know what a transfer will cost before starting it.
66
+ */
67
+ async metadata(id) {
68
+ return withRetry(this.retries, async () => {
69
+ const res = await databaseMetadataV2({ client: this.client, query: { id: id } });
70
+ return unwrap(res);
71
+ });
72
+ }
73
+ /**
74
+ * The digests for one database file.
75
+ *
76
+ * Returns the whole set rather than one algorithm: which digests a database
77
+ * publishes is the API's choice, not ours.
78
+ */
79
+ async checksums(id, format) {
80
+ return withRetry(this.retries, async () => {
81
+ const res = await databaseChecksumV2({
82
+ client: this.client, query: { id: id, format: format },
83
+ });
84
+ return unwrap(res).checksums;
85
+ });
86
+ }
87
+ /**
88
+ * Your organization's recent download attempts, newest first.
89
+ *
90
+ * Refusals are listed too: a denial is what answers "it stopped working",
91
+ * and its absence answers nothing.
92
+ */
93
+ async downloads(options = {}) {
94
+ return withRetry(this.retries, async () => {
95
+ const res = await listDownloads({
96
+ client: this.client,
97
+ ...(options.limit === undefined ? {} : { query: { limit: options.limit } }),
98
+ });
99
+ return unwrap(res).downloads;
100
+ });
101
+ }
102
+ /**
103
+ * The time-limited URL for one database file.
104
+ *
105
+ * The API answers `302` to object storage. The URL is returned rather than
106
+ * the bytes so the caller decides how to transfer a file that runs to
107
+ * gigabytes; it carries its own authorization, so it can be handed to
108
+ * something that holds no API key. The link authorizes the START of a
109
+ * transfer, so one already running is not interrupted when it lapses.
110
+ */
111
+ async downloadUrl(id, format) {
112
+ return withRetry(this.retries, async () => {
113
+ const res = await downloadRedirect({
114
+ client: this.client,
115
+ query: { id: id, format: format },
116
+ redirect: 'manual',
117
+ });
118
+ if (res.response === undefined) {
119
+ throw new InternetDataError('network', 'no response from the API');
120
+ }
121
+ const location = res.response.headers.get('location');
122
+ if (res.response.status === 302 && location !== null) {
123
+ return location;
124
+ }
125
+ unwrap(res);
126
+ throw new InternetDataError('server_error', 'expected a redirect to object storage', res.response.status);
127
+ });
128
+ }
129
+ /**
130
+ * Download one database file, streaming it to `destination`.
131
+ *
132
+ * `destination` is either a path or a writable stream you opened yourself.
133
+ * A path is written through a neighboring `.part` file and renamed on
134
+ * completion, so a transfer that dies half way leaves no truncated file
135
+ * that reads as a whole database; a stream you pass is written as-is and
136
+ * stays yours to close. Nothing is ever held in memory beyond a single
137
+ * chunk, whatever the file weighs.
138
+ *
139
+ * Returns the number of bytes written.
140
+ *
141
+ * A failure DURING the transfer surfaces as the underlying error rather
142
+ * than an `InternetDataError`: a reset socket and a full disk are different
143
+ * problems and only one of them is ours.
144
+ */
145
+ async download(id, format, destination) {
146
+ const res = await this.fetchDatabaseFile(id, format);
147
+ if (res.body === null) {
148
+ throw new InternetDataError('server_error', 'object storage answered with no body', res.status);
149
+ }
150
+ const { Readable } = await import('node:stream');
151
+ const { pipeline } = await import('node:stream/promises');
152
+ // `node:stream/web` and the DOM lib declare the same runtime object as
153
+ // two unrelated types, so `fromWeb` needs it restated.
154
+ const source = Readable.fromWeb(res.body);
155
+ let bytes = 0;
156
+ async function* counted() {
157
+ for await (const chunk of source) {
158
+ bytes += chunk.length;
159
+ yield chunk;
160
+ }
161
+ }
162
+ if (typeof destination !== 'string') {
163
+ await pipeline(counted(), destination);
164
+ return bytes;
165
+ }
166
+ const { createWriteStream } = await import('node:fs');
167
+ const { rename, unlink } = await import('node:fs/promises');
168
+ const partial = `${destination}.part`;
169
+ try {
170
+ await pipeline(counted(), createWriteStream(partial));
171
+ }
172
+ catch (err) {
173
+ await unlink(partial).catch(() => { });
174
+ throw err;
175
+ }
176
+ await rename(partial, destination);
177
+ return bytes;
178
+ }
179
+ /**
180
+ * Download one database file and hand back its bytes.
181
+ *
182
+ * **This holds the entire file in memory**, and the catalog spans seven
183
+ * orders of magnitude: the smallest published build is a few hundred bytes,
184
+ * which is nothing, while the largest is over 5 GiB, which will cost you
185
+ * that much resident memory in one allocation and can fail outright. Reach
186
+ * for this at the small end, where the bytes are going straight into a
187
+ * parser; use `download` for anything you have not measured, and `metadata`
188
+ * to measure it before you do.
189
+ */
190
+ async downloadBytes(id, format) {
191
+ const res = await this.fetchDatabaseFile(id, format);
192
+ return new Uint8Array(await res.arrayBuffer());
193
+ }
194
+ // Follows the 302 as a SECOND, unauthenticated request: the presigned URL
195
+ // carries its own authorization, so forwarding the API key would hand a
196
+ // credential to a host that has no business holding it.
197
+ async fetchDatabaseFile(id, format) {
198
+ const url = await this.downloadUrl(id, format);
199
+ return withRetry(this.retries, async () => {
200
+ const res = await this.fetchImpl(url);
201
+ if (!res.ok) {
202
+ // Left unread: the status is what separates a lapsed link from
203
+ // a refused one, and the body is not bounded by anything.
204
+ void res.body?.cancel();
205
+ throw errorFromResponse(res.status, res.headers, `object storage refused the download link with status ${res.status}`);
206
+ }
207
+ return res;
208
+ });
209
+ }
210
+ }
211
+ function unwrap(res) {
212
+ if (res.response === undefined) {
213
+ throw new InternetDataError('network', 'no response from the API');
214
+ }
215
+ if (!res.response.ok) {
216
+ throw errorFromResponse(res.response.status, res.response.headers, messageFromBody(res.error ?? res.data));
217
+ }
218
+ return res.data;
219
+ }
220
+ // p-retry owns the backoff schedule; the extra sleep here is what honors a
221
+ // server-supplied Retry-After, which p-retry has no way to know about. A 429
222
+ // carrying that header is the only 429 worth retrying, which is why the wait
223
+ // and the retry decision both key off the same field.
224
+ async function withRetry(retries, fn) {
225
+ try {
226
+ return await pRetry(fn, {
227
+ retries: retries,
228
+ shouldRetry: ({ error }) => !(error instanceof InternetDataError) || error.retryable,
229
+ onFailedAttempt: async ({ error }) => {
230
+ const seconds = error instanceof InternetDataError
231
+ ? error.retryAfterSeconds
232
+ : undefined;
233
+ if (seconds !== undefined && seconds > 0) {
234
+ await new Promise((r) => setTimeout(r, seconds * 1000));
235
+ }
236
+ },
237
+ });
238
+ }
239
+ catch (err) {
240
+ throw asError(err);
241
+ }
242
+ }
243
+ function asError(err) {
244
+ if (err instanceof InternetDataError) {
245
+ return err;
246
+ }
247
+ const cause = err?.cause;
248
+ if (cause instanceof InternetDataError) {
249
+ return cause;
250
+ }
251
+ return new InternetDataError('network', err instanceof Error ? err.message : String(err));
252
+ }
253
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Why a request failed.
3
+ *
4
+ * `rate_limited` and `quota_exceeded` both arrive as HTTP 429 and are NOT the
5
+ * same thing. A rate limit is the API protecting itself and carries
6
+ * `Retry-After`; retrying works. A spent quota carries no such header and
7
+ * retrying will not help until the window rolls over or the limit is raised.
8
+ * The header is the only thing that distinguishes them.
9
+ */
10
+ export type ErrorKind = 'bad_request' | 'unauthorized' | 'forbidden' | 'rate_limited' | 'quota_exceeded' | 'server_error' | 'network';
11
+ export declare class InternetDataError extends Error {
12
+ readonly kind: ErrorKind;
13
+ readonly status?: number;
14
+ readonly retryAfterSeconds?: number;
15
+ constructor(kind: ErrorKind, message: string, status?: number, retryAfterSeconds?: number);
16
+ /** Whether retrying this exact request could succeed. */
17
+ get retryable(): boolean;
18
+ }
19
+ export declare function errorFromResponse(status: number, headers: {
20
+ get(name: string): string | null;
21
+ }, message?: string): InternetDataError;
22
+ /**
23
+ * The `rc` an error envelope carries.
24
+ *
25
+ * Deliberately not an enum, in the spec or here: a code added later must stay
26
+ * readable to a client generated today, and the string IS the message a caller
27
+ * wants to see.
28
+ */
29
+ export declare function messageFromBody(body: unknown): string | undefined;
package/dist/errors.js ADDED
@@ -0,0 +1,74 @@
1
+ export class InternetDataError extends Error {
2
+ kind;
3
+ status;
4
+ retryAfterSeconds;
5
+ constructor(kind, message, status, retryAfterSeconds) {
6
+ super(message);
7
+ this.name = 'InternetDataError';
8
+ this.kind = kind;
9
+ this.status = status;
10
+ this.retryAfterSeconds = retryAfterSeconds;
11
+ }
12
+ /** Whether retrying this exact request could succeed. */
13
+ get retryable() {
14
+ return this.kind === 'rate_limited' || this.kind === 'server_error' || this.kind === 'network';
15
+ }
16
+ }
17
+ export function errorFromResponse(status, headers, message) {
18
+ const text = message ?? `request failed with status ${status}`;
19
+ const retryAfter = parseRetryAfter(headers.get('retry-after'));
20
+ if (status === 429) {
21
+ // Present means transient, absent means an allowance is spent. Nothing
22
+ // else in the response separates the two.
23
+ return retryAfter === undefined
24
+ ? new InternetDataError('quota_exceeded', text, status)
25
+ : new InternetDataError('rate_limited', text, status, retryAfter);
26
+ }
27
+ if (status === 400) {
28
+ return new InternetDataError('bad_request', text, status);
29
+ }
30
+ if (status === 401) {
31
+ return new InternetDataError('unauthorized', text, status);
32
+ }
33
+ if (status === 403) {
34
+ return new InternetDataError('forbidden', text, status);
35
+ }
36
+ // Any other 4xx is a CLIENT error. Falling through to the server_error
37
+ // default would make it retryable, so a misspelled dataset id (404
38
+ // UNKNOWN_DATASET) would be retried twice before failing. Only 5xx and
39
+ // transport failures are worth a retry.
40
+ if (status < 500) {
41
+ return new InternetDataError('bad_request', text, status);
42
+ }
43
+ return new InternetDataError('server_error', text, status);
44
+ }
45
+ /**
46
+ * The `rc` an error envelope carries.
47
+ *
48
+ * Deliberately not an enum, in the spec or here: a code added later must stay
49
+ * readable to a client generated today, and the string IS the message a caller
50
+ * wants to see.
51
+ */
52
+ export function messageFromBody(body) {
53
+ if (typeof body !== 'object' || body === null) {
54
+ return undefined;
55
+ }
56
+ const rc = body['rc'];
57
+ return typeof rc === 'string' ? rc : undefined;
58
+ }
59
+ function parseRetryAfter(value) {
60
+ if (value === null || value.trim() === '') {
61
+ return undefined;
62
+ }
63
+ const seconds = Number(value);
64
+ if (Number.isFinite(seconds) && seconds >= 0) {
65
+ return seconds;
66
+ }
67
+ // The header also permits an HTTP date.
68
+ const when = Date.parse(value);
69
+ if (Number.isNaN(when)) {
70
+ return undefined;
71
+ }
72
+ return Math.max(0, Math.ceil((when - Date.now()) / 1000));
73
+ }
74
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Client, Config } from './types.gen.js';
2
+ export declare const createClient: (config?: Config) => Client;