@eik/node-client 2.0.6 → 2.0.7

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [2.0.7](https://github.com/eik-lib/node-client/compare/v2.0.6...v2.0.7) (2025-05-08)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * redirections bug with Node 24 ([#230](https://github.com/eik-lib/node-client/issues/230)) ([9111ad0](https://github.com/eik-lib/node-client/commit/9111ad0c0fbc90dd89368507b6675740cb99cd5f))
7
+
1
8
  ## [2.0.6](https://github.com/eik-lib/node-client/compare/v2.0.5...v2.0.6) (2025-04-28)
2
9
 
3
10
 
package/dist/index.cjs CHANGED
@@ -60,21 +60,47 @@ const trimSlash = (value = "") => {
60
60
  return value;
61
61
  };
62
62
 
63
- const fetchImportMaps = async (urls = []) => {
63
+ /**
64
+ * @param {string[]} urls
65
+ * @param {object} options
66
+ * @param {number} options.maxRedirections - undici option for limiting redirects
67
+ * @returns {Promise<ImportMap[]>}
68
+ */
69
+ const fetchImportMaps = async (urls = [], options) => {
64
70
  try {
65
71
  const maps = urls.map(async (map) => {
66
- const { statusCode, body } = await undici.request(map, {
67
- maxRedirections: 2,
72
+ const response = await undici.request(map, {
73
+ dispatcher: new undici.Agent().compose(
74
+ undici.interceptors.redirect({
75
+ maxRedirections: options.maxRedirections,
76
+ }),
77
+ ),
68
78
  });
69
79
 
70
- if (statusCode === 404) {
80
+ if (response.statusCode === 404) {
71
81
  throw new Error("Import map could not be found on server");
72
- } else if (statusCode >= 400 && statusCode < 500) {
82
+ } else if (response.statusCode >= 400 && response.statusCode < 500) {
73
83
  throw new Error("Server rejected client request");
74
- } else if (statusCode >= 500) {
84
+ } else if (response.statusCode >= 500) {
75
85
  throw new Error("Server error");
76
86
  }
77
- return body.json();
87
+ let contentType = response.headers["content-type"];
88
+ if (!Array.isArray(contentType)) contentType = [contentType];
89
+
90
+ if (!contentType.find((type) => type.startsWith("application/json"))) {
91
+ const content = await response.body.text();
92
+ if (content.length === 0) {
93
+ throw new Error(
94
+ `${map} did not return JSON, got an empty response. HTTP status: ${response.statusCode}`,
95
+ );
96
+ }
97
+ throw new Error(
98
+ `${map} did not return JSON, got: ${content}. HTTP status: ${response.statusCode}`,
99
+ );
100
+ }
101
+
102
+ const json = await response.body.json();
103
+ return /** @type {ImportMap}*/ (json);
78
104
  });
79
105
  return await Promise.all(maps);
80
106
  } catch (err) {
@@ -90,6 +116,7 @@ const fetchImportMaps = async (urls = []) => {
90
116
  * @property {boolean} [development=false]
91
117
  * @property {boolean} [loadMaps=false]
92
118
  * @property {string} [path=process.cwd()]
119
+ * @property {number} [maxRedirections=2] Maximum number of redirects when looking up URLs.
93
120
  */
94
121
 
95
122
  /**
@@ -163,6 +190,7 @@ class Eik {
163
190
  #path;
164
191
  #base;
165
192
  #maps;
193
+ #maxRedirections;
166
194
 
167
195
  /**
168
196
  * @param {Options} options
@@ -172,6 +200,7 @@ class Eik {
172
200
  loadMaps = false,
173
201
  base = "",
174
202
  path = process.cwd(),
203
+ maxRedirections = 2,
175
204
  } = {}) {
176
205
  this.#development = development;
177
206
  this.#loadMaps = loadMaps;
@@ -179,6 +208,7 @@ class Eik {
179
208
  this.#path = path;
180
209
  this.#base = trimSlash(base);
181
210
  this.#maps = [];
211
+ this.#maxRedirections = maxRedirections;
182
212
  }
183
213
 
184
214
  /**
@@ -191,7 +221,9 @@ class Eik {
191
221
  async load() {
192
222
  this.#config = await common.helpers.getDefaults(this.#path);
193
223
  if (this.#loadMaps) {
194
- this.#maps = await fetchImportMaps(this.#config.map);
224
+ this.#maps = await fetchImportMaps(this.#config.map, {
225
+ maxRedirections: this.#maxRedirections,
226
+ });
195
227
  }
196
228
  }
197
229
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eik/node-client",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Utilities for working with assets and import maps on an Eik server",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -45,14 +45,14 @@
45
45
  "dependencies": {
46
46
  "@eik/common": "5.0.4",
47
47
  "abslog": "2.4.4",
48
- "undici": "6.21.2"
48
+ "undici": "7.8.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@eik/eslint-config": "1.0.12",
51
+ "@eik/eslint-config": "1.0.13",
52
52
  "@eik/prettier-config": "1.0.1",
53
53
  "@eik/semantic-release-config": "1.0.2",
54
54
  "@eik/typescript-config": "1.0.0",
55
- "eslint": "9.16.0",
55
+ "eslint": "9.25.1",
56
56
  "npm-run-all2": "7.0.2",
57
57
  "prettier": "3.4.1",
58
58
  "rimraf": "6.0.1",
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { helpers } from "@eik/common";
2
- import { request } from "undici";
2
+ import { request, interceptors, Agent } from "undici";
3
3
  import { join } from "path";
4
4
  import { Asset } from "./asset.js";
5
5
 
@@ -8,21 +8,47 @@ const trimSlash = (value = "") => {
8
8
  return value;
9
9
  };
10
10
 
11
- const fetchImportMaps = async (urls = []) => {
11
+ /**
12
+ * @param {string[]} urls
13
+ * @param {object} options
14
+ * @param {number} options.maxRedirections - undici option for limiting redirects
15
+ * @returns {Promise<ImportMap[]>}
16
+ */
17
+ const fetchImportMaps = async (urls = [], options) => {
12
18
  try {
13
19
  const maps = urls.map(async (map) => {
14
- const { statusCode, body } = await request(map, {
15
- maxRedirections: 2,
20
+ const response = await request(map, {
21
+ dispatcher: new Agent().compose(
22
+ interceptors.redirect({
23
+ maxRedirections: options.maxRedirections,
24
+ }),
25
+ ),
16
26
  });
17
27
 
18
- if (statusCode === 404) {
28
+ if (response.statusCode === 404) {
19
29
  throw new Error("Import map could not be found on server");
20
- } else if (statusCode >= 400 && statusCode < 500) {
30
+ } else if (response.statusCode >= 400 && response.statusCode < 500) {
21
31
  throw new Error("Server rejected client request");
22
- } else if (statusCode >= 500) {
32
+ } else if (response.statusCode >= 500) {
23
33
  throw new Error("Server error");
24
34
  }
25
- return body.json();
35
+ let contentType = response.headers["content-type"];
36
+ if (!Array.isArray(contentType)) contentType = [contentType];
37
+
38
+ if (!contentType.find((type) => type.startsWith("application/json"))) {
39
+ const content = await response.body.text();
40
+ if (content.length === 0) {
41
+ throw new Error(
42
+ `${map} did not return JSON, got an empty response. HTTP status: ${response.statusCode}`,
43
+ );
44
+ }
45
+ throw new Error(
46
+ `${map} did not return JSON, got: ${content}. HTTP status: ${response.statusCode}`,
47
+ );
48
+ }
49
+
50
+ const json = await response.body.json();
51
+ return /** @type {ImportMap}*/ (json);
26
52
  });
27
53
  return await Promise.all(maps);
28
54
  } catch (err) {
@@ -38,6 +64,7 @@ const fetchImportMaps = async (urls = []) => {
38
64
  * @property {boolean} [development=false]
39
65
  * @property {boolean} [loadMaps=false]
40
66
  * @property {string} [path=process.cwd()]
67
+ * @property {number} [maxRedirections=2] Maximum number of redirects when looking up URLs.
41
68
  */
42
69
 
43
70
  /**
@@ -111,6 +138,7 @@ export default class Eik {
111
138
  #path;
112
139
  #base;
113
140
  #maps;
141
+ #maxRedirections;
114
142
 
115
143
  /**
116
144
  * @param {Options} options
@@ -120,6 +148,7 @@ export default class Eik {
120
148
  loadMaps = false,
121
149
  base = "",
122
150
  path = process.cwd(),
151
+ maxRedirections = 2,
123
152
  } = {}) {
124
153
  this.#development = development;
125
154
  this.#loadMaps = loadMaps;
@@ -127,6 +156,7 @@ export default class Eik {
127
156
  this.#path = path;
128
157
  this.#base = trimSlash(base);
129
158
  this.#maps = [];
159
+ this.#maxRedirections = maxRedirections;
130
160
  }
131
161
 
132
162
  /**
@@ -139,7 +169,9 @@ export default class Eik {
139
169
  async load() {
140
170
  this.#config = await helpers.getDefaults(this.#path);
141
171
  if (this.#loadMaps) {
142
- this.#maps = await fetchImportMaps(this.#config.map);
172
+ this.#maps = await fetchImportMaps(this.#config.map, {
173
+ maxRedirections: this.#maxRedirections,
174
+ });
143
175
  }
144
176
  }
145
177
 
package/types/index.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * @property {boolean} [development=false]
5
5
  * @property {boolean} [loadMaps=false]
6
6
  * @property {string} [path=process.cwd()]
7
+ * @property {number} [maxRedirections=2] Maximum number of redirects when looking up URLs.
7
8
  */
8
9
  /**
9
10
  * @typedef {object} ImportMap
@@ -72,7 +73,7 @@ export default class Eik {
72
73
  /**
73
74
  * @param {Options} options
74
75
  */
75
- constructor({ development, loadMaps, base, path, }?: Options);
76
+ constructor({ development, loadMaps, base, path, maxRedirections, }?: Options);
76
77
  /**
77
78
  * Reads the Eik config from disk into the object instance, used for building {@link file} links in production.
78
79
  *
@@ -212,6 +213,10 @@ export type Options = {
212
213
  development?: boolean;
213
214
  loadMaps?: boolean;
214
215
  path?: string;
216
+ /**
217
+ * Maximum number of redirects when looking up URLs.
218
+ */
219
+ maxRedirections?: number;
215
220
  };
216
221
  export type ImportMap = {
217
222
  imports: Record<string, string>;