@fedify/vocab-runtime 2.4.5-dev.2462 → 2.4.6-dev.2628

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 (120) hide show
  1. package/deno.json +5 -2
  2. package/dist/{docloader-BMHljyYb.d.cts → docloader-DOWjnNCz.d.cts} +4 -8
  3. package/dist/{docloader-BMHljyYb.d.ts → docloader-DOWjnNCz.d.ts} +4 -8
  4. package/dist/internal/jsonld-cache.cjs +1 -1
  5. package/dist/internal/jsonld-cache.d.cts +1 -1
  6. package/dist/internal/jsonld-cache.d.ts +1 -1
  7. package/dist/internal/jsonld-cache.js +1 -1
  8. package/dist/internal/portable-dereference.cjs +1 -1
  9. package/dist/internal/portable-dereference.d.cts +2 -2
  10. package/dist/internal/portable-dereference.d.ts +2 -2
  11. package/dist/internal/portable-dereference.js +1 -1
  12. package/dist/internal.cjs +6 -0
  13. package/dist/internal.d.cts +108 -0
  14. package/dist/internal.d.ts +108 -0
  15. package/dist/internal.js +3 -0
  16. package/dist/mod.cjs +104 -38
  17. package/dist/mod.d.cts +3 -336
  18. package/dist/mod.d.ts +4 -336
  19. package/dist/mod.js +104 -38
  20. package/dist/{portable-6Aj-7dZJ.d.cts → portable-CTnZWX7J.d.cts} +1 -1
  21. package/dist/{portable-nkTiqH0w.d.ts → portable-Cq-rhQgY.d.ts} +1 -1
  22. package/dist/public-fetch-Dvfvawei.cjs +527 -0
  23. package/dist/public-fetch-ziZ39L5I.js +510 -0
  24. package/dist/tests/{body-Dlnsb-QX.cjs → body-1uyjqhY5.cjs} +1 -1
  25. package/dist/tests/{body-BXrFIcFa.mjs → body-BIuoyur4.mjs} +1 -1
  26. package/dist/tests/body.test.cjs +1 -1
  27. package/dist/tests/body.test.mjs +1 -1
  28. package/dist/tests/decimal.test.cjs +3 -3
  29. package/dist/tests/decimal.test.mjs +3 -3
  30. package/dist/tests/{docloader-DsuF8YDf.mjs → docloader-CmylAvrm.mjs} +106 -40
  31. package/dist/tests/{docloader-c9BQWaF1.cjs → docloader-DGDSOOhc.cjs} +111 -39
  32. package/dist/tests/docloader.test.cjs +531 -1293
  33. package/dist/tests/docloader.test.mjs +472 -1252
  34. package/dist/tests/esm-Ds-eHTfY.mjs +1229 -0
  35. package/dist/tests/esm-Q2tdh5f3.cjs +1215 -0
  36. package/dist/tests/internal/portable-dereference.test.cjs +3 -3
  37. package/dist/tests/internal/portable-dereference.test.mjs +3 -3
  38. package/dist/tests/{jsonld-cache-BEXiiM-V.cjs → jsonld-cache-DKIWKxEX.cjs} +1 -1
  39. package/dist/tests/{jsonld-cache-DFnWsLuZ.mjs → jsonld-cache-KH40z9_7.mjs} +1 -1
  40. package/dist/tests/jsonld-cache.test.cjs +2 -2
  41. package/dist/tests/jsonld-cache.test.mjs +2 -2
  42. package/dist/tests/node-BvS3AhZ2.cjs +89 -0
  43. package/dist/tests/node-Cg4pRuYy.mjs +84 -0
  44. package/dist/tests/pin-grant-CPrpk1l4.cjs +70 -0
  45. package/dist/tests/pin-grant-H5XhM1Xs.mjs +53 -0
  46. package/dist/tests/pin-grant.test.cjs +87 -0
  47. package/dist/tests/pin-grant.test.d.cts +1 -0
  48. package/dist/tests/pin-grant.test.d.mts +1 -0
  49. package/dist/tests/pin-grant.test.mjs +88 -0
  50. package/dist/tests/pinners/bun.test.cjs +166 -0
  51. package/dist/tests/pinners/bun.test.d.cts +1 -0
  52. package/dist/tests/pinners/bun.test.d.mts +1 -0
  53. package/dist/tests/pinners/bun.test.mjs +167 -0
  54. package/dist/tests/pinners/node.test.cjs +269 -0
  55. package/dist/tests/pinners/node.test.d.cts +1 -0
  56. package/dist/tests/pinners/node.test.d.mts +1 -0
  57. package/dist/tests/pinners/node.test.mjs +268 -0
  58. package/dist/tests/pinners/pinners.test.cjs +196 -0
  59. package/dist/tests/pinners/pinners.test.d.cts +1 -0
  60. package/dist/tests/pinners/pinners.test.d.mts +1 -0
  61. package/dist/tests/pinners/pinners.test.mjs +197 -0
  62. package/dist/tests/pinners/testdata/node-child.cjs +135 -0
  63. package/dist/tests/pinners/testdata/node-child.d.cts +1 -0
  64. package/dist/tests/pinners/testdata/node-child.d.mts +1 -0
  65. package/dist/tests/pinners/testdata/node-child.mjs +134 -0
  66. package/dist/tests/pinners-CJi9ZkYs.cjs +220 -0
  67. package/dist/tests/pinners-zSofbiy2.mjs +203 -0
  68. package/dist/tests/{portable-dereference-DmTYDy2p.mjs → portable-dereference-BHRE5Pkm.mjs} +2 -2
  69. package/dist/tests/{portable-dereference-qTLMqe2_.cjs → portable-dereference-mRHrC7PI.cjs} +2 -2
  70. package/dist/tests/{portable-media-M7idvaUq.mjs → portable-media-B83gylai.mjs} +3 -3
  71. package/dist/tests/{portable-media-CS4czG6X.cjs → portable-media-DyuL0sR_.cjs} +3 -3
  72. package/dist/tests/portable-media.test.cjs +1 -1
  73. package/dist/tests/portable-media.test.mjs +1 -1
  74. package/dist/tests/portable-workers.test.cjs +2 -2
  75. package/dist/tests/portable-workers.test.mjs +2 -2
  76. package/dist/tests/public-fetch-DNkPoks1.mjs +170 -0
  77. package/dist/tests/public-fetch-U822jbKB.cjs +186 -0
  78. package/dist/tests/public-fetch.test.cjs +1073 -0
  79. package/dist/tests/public-fetch.test.d.cts +1 -0
  80. package/dist/tests/public-fetch.test.d.mts +1 -0
  81. package/dist/tests/public-fetch.test.mjs +1074 -0
  82. package/dist/tests/{request-CgTgsBUA.cjs → request-BDe7VfMX.cjs} +1 -1
  83. package/dist/tests/{request-C336eT6A.mjs → request-Bj4ZeRfh.mjs} +1 -1
  84. package/dist/tests/request.test.cjs +1 -1
  85. package/dist/tests/request.test.mjs +1 -1
  86. package/dist/tests/support-BmzI3dRJ.cjs +363 -0
  87. package/dist/tests/support-CiHDVJgh.mjs +272 -0
  88. package/dist/tests/{url-BNakuZ8k.cjs → url-Bdj-rTcC.cjs} +88 -12
  89. package/dist/tests/{url-DMxmp7ZG.mjs → url-COj5Q8mb.mjs} +65 -13
  90. package/dist/tests/url.test.cjs +4 -1
  91. package/dist/tests/url.test.mjs +4 -1
  92. package/dist/url-4EE56sNP.d.cts +352 -0
  93. package/dist/url-4EE56sNP.d.ts +352 -0
  94. package/dist/{url-DrGTR8yv.cjs → url-DIKZnaJv.cjs} +88 -12
  95. package/dist/{url-Dzyp-NsC.js → url-mWveR5GA.js} +65 -13
  96. package/package.json +14 -3
  97. package/src/docloader.test.ts +696 -48
  98. package/src/docloader.ts +186 -75
  99. package/src/internal.ts +13 -0
  100. package/src/pin-grant.test.ts +118 -0
  101. package/src/pin-grant.ts +99 -0
  102. package/src/pinners/bun.test.ts +278 -0
  103. package/src/pinners/bun.ts +223 -0
  104. package/src/pinners/mod.ts +59 -0
  105. package/src/pinners/node.test.ts +415 -0
  106. package/src/pinners/node.ts +144 -0
  107. package/src/pinners/pinners.test.ts +316 -0
  108. package/src/pinners/testdata/node-child.ts +147 -0
  109. package/src/pinners/testdata/proxy-child.ts +82 -0
  110. package/src/pinners/testdata/support.ts +343 -0
  111. package/src/pinners/testdata/tls-cert.pem +12 -0
  112. package/src/pinners/testdata/tls-child.ts +88 -0
  113. package/src/pinners/testdata/tls-key.pem +5 -0
  114. package/src/pinners/types.ts +48 -0
  115. package/src/public-fetch.test.ts +1286 -0
  116. package/src/public-fetch.ts +338 -0
  117. package/src/testdata/public-fetch-deno-worker.ts +74 -0
  118. package/src/url.test.ts +11 -0
  119. package/src/url.ts +113 -22
  120. package/tsdown.config.ts +7 -2
@@ -3,7 +3,7 @@ let node_process = require("node:process");
3
3
  node_process = require_rolldown_runtime.__toESM(node_process, 1);
4
4
  //#region deno.json
5
5
  var name = "@fedify/vocab-runtime";
6
- var version = "2.4.5-dev.2462+46a3f2c5";
6
+ var version = "2.4.6-dev.2628+2a78382f";
7
7
  //#endregion
8
8
  //#region src/request.ts
9
9
  /**
@@ -1,7 +1,7 @@
1
1
  import process from "node:process";
2
2
  //#region deno.json
3
3
  var name = "@fedify/vocab-runtime";
4
- var version = "2.4.5-dev.2462+46a3f2c5";
4
+ var version = "2.4.6-dev.2628+2a78382f";
5
5
  //#endregion
6
6
  //#region src/request.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
2
- const require_request = require("./request-CgTgsBUA.cjs");
2
+ const require_request = require("./request-BDe7VfMX.cjs");
3
3
  let node_test = require("node:test");
4
4
  let node_process = require("node:process");
5
5
  node_process = require_rolldown_runtime.__toESM(node_process, 1);
@@ -1,4 +1,4 @@
1
- import { n as createActivityPubRequest, o as version, r as getUserAgent } from "./request-C336eT6A.mjs";
1
+ import { n as createActivityPubRequest, o as version, r as getUserAgent } from "./request-Bj4ZeRfh.mjs";
2
2
  import { test } from "node:test";
3
3
  import process from "node:process";
4
4
  import { deepStrictEqual } from "node:assert";
@@ -0,0 +1,363 @@
1
+ const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
2
+ const require_url = require("./url-Bdj-rTcC.cjs");
3
+ const require_pinners = require("./pinners-CJi9ZkYs.cjs");
4
+ let node_process = require("node:process");
5
+ node_process = require_rolldown_runtime.__toESM(node_process, 1);
6
+ let node_net = require("node:net");
7
+ let node_http = require("node:http");
8
+ let node_fs = require("node:fs");
9
+ let node_child_process = require("node:child_process");
10
+ let node_path = require("node:path");
11
+ let node_url = require("node:url");
12
+ //#region src/pinners/testdata/support.ts
13
+ /**
14
+ * Helpers shared by the pinner tests in *../\*.test.ts*. They start local
15
+ * servers and proxies, and run child processes.
16
+ * @module
17
+ */
18
+ const isBun = require_pinners.detectRuntime() === "bun";
19
+ const isNode = require_pinners.detectRuntime() === "node";
20
+ /** Pinner options that allow connecting to any address, e.g., loopback. */
21
+ const allowAll = { verifyAddress() {} };
22
+ const ipv4 = (address) => ({
23
+ address,
24
+ family: 4
25
+ });
26
+ const ipv6 = (address) => ({
27
+ address,
28
+ family: 6
29
+ });
30
+ /**
31
+ * Whether the error is the rejection of an address by `verifyAddress`.
32
+ * The Bun pinner throws the `UrlError` itself, and the Node.js pinner
33
+ * rejects with the `TypeError` of `fetch()`, caused by the `UrlError` that
34
+ * its lookup failed with.
35
+ */
36
+ function isAddressRejection(error) {
37
+ return error instanceof require_url.UrlError || error instanceof TypeError && error.cause instanceof require_url.UrlError;
38
+ }
39
+ function readBody(req) {
40
+ return new Promise((resolve, reject) => {
41
+ let body = "";
42
+ req.setEncoding("utf8");
43
+ req.on("data", (chunk) => body += chunk);
44
+ req.on("end", () => resolve(body));
45
+ req.on("error", reject);
46
+ });
47
+ }
48
+ async function listen(server, host = "127.0.0.1") {
49
+ await new Promise((resolve, reject) => {
50
+ server.once("error", reject);
51
+ server.listen(0, host, () => {
52
+ server.off("error", reject);
53
+ resolve();
54
+ });
55
+ });
56
+ return server.address().port;
57
+ }
58
+ async function closeServer(server) {
59
+ server.closeAllConnections?.();
60
+ await new Promise((resolve) => server.close(() => resolve()));
61
+ }
62
+ function canConnect(host, port) {
63
+ return new Promise((resolve) => {
64
+ const socket = (0, node_net.connect)({
65
+ host,
66
+ port
67
+ });
68
+ const done = (result) => {
69
+ socket.destroy();
70
+ resolve(result);
71
+ };
72
+ socket.setTimeout(2e3, () => done(false));
73
+ socket.once("connect", () => done(true));
74
+ socket.once("error", () => done(false));
75
+ });
76
+ }
77
+ let loopbackSupport;
78
+ /**
79
+ * Checks which loopback addresses the tests can use. Only 127.0.0.1 is
80
+ * assumed: other addresses of 127.0.0.0/8 are not configured on macOS, and
81
+ * IPv6 can be disabled.
82
+ */
83
+ function getLoopbackSupport() {
84
+ loopbackSupport ??= (async () => {
85
+ const server = (0, node_net.createServer)((socket) => socket.destroy());
86
+ let port;
87
+ try {
88
+ port = await listen(server, "::");
89
+ } catch {
90
+ return {
91
+ ipv6: false,
92
+ dualStack: false
93
+ };
94
+ }
95
+ try {
96
+ const [v4, v6] = await Promise.all([canConnect("127.0.0.1", port), canConnect("::1", port)]);
97
+ return {
98
+ ipv6: v6,
99
+ dualStack: v4 && v6
100
+ };
101
+ } finally {
102
+ await closeServer(server);
103
+ }
104
+ })();
105
+ return loopbackSupport;
106
+ }
107
+ /**
108
+ * Starts an HTTP server that records the requests it receives.
109
+ */
110
+ async function startRecordingServer(host = "127.0.0.1", respond = (_, res) => res.end("pinned")) {
111
+ const requests = [];
112
+ const server = (0, node_http.createServer)(async (req, res) => {
113
+ const body = await readBody(req);
114
+ requests.push({
115
+ method: req.method ?? "",
116
+ url: req.url ?? "",
117
+ host: req.headers.host,
118
+ localAddress: req.socket.localAddress,
119
+ body
120
+ });
121
+ respond(req, res);
122
+ });
123
+ return {
124
+ server,
125
+ port: await listen(server, host),
126
+ requests
127
+ };
128
+ }
129
+ /**
130
+ * Starts a TCP server that only counts the connections it accepts, and drops
131
+ * them right away. It stands for an HTTPS server without a certificate.
132
+ */
133
+ async function startCountingServer() {
134
+ const counter = { connections: 0 };
135
+ const server = (0, node_net.createServer)((socket) => {
136
+ counter.connections++;
137
+ socket.destroy();
138
+ });
139
+ return {
140
+ server,
141
+ port: await listen(server),
142
+ counter
143
+ };
144
+ }
145
+ /**
146
+ * Starts a proxy that records the request targets it is asked for, and never
147
+ * forwards them. It answers a request in absolute form with `via-proxy`,
148
+ * and drops tunnels (`CONNECT`). It parses requests by itself since
149
+ * the `connect` event of `node:http` servers is not available on older Bun
150
+ * versions.
151
+ * @param options.refuseTunnels Whether to refuse tunnels with a `403`
152
+ * response instead of dropping them. Some
153
+ * clients retry dropped tunnels without end
154
+ * (e.g., the `EnvHttpProxyAgent` of Node.js),
155
+ * and some take the response of a refused
156
+ * tunnel for the response of the request
157
+ * (e.g., Bun 1.3.14).
158
+ */
159
+ async function startRecordingProxy({ refuseTunnels = false } = {}) {
160
+ const targets = [];
161
+ const server = (0, node_net.createServer)((socket) => {
162
+ let head = "";
163
+ socket.setEncoding("latin1");
164
+ socket.on("error", () => {});
165
+ socket.on("data", (chunk) => {
166
+ if (head.includes("\r\n\r\n")) return;
167
+ head += chunk;
168
+ if (!head.includes("\r\n\r\n")) return;
169
+ const [method, target] = head.slice(0, head.indexOf("\r\n")).split(" ");
170
+ targets.push(`${method} ${target}`);
171
+ if (method !== "CONNECT") socket.end("HTTP/1.1 200 OK\r\nContent-Length: 9\r\nConnection: close\r\n\r\nvia-proxy");
172
+ else if (refuseTunnels) socket.end("HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
173
+ else socket.destroy();
174
+ });
175
+ });
176
+ return {
177
+ server,
178
+ port: await listen(server),
179
+ targets
180
+ };
181
+ }
182
+ /**
183
+ * Returns the first of the given paths that exists.
184
+ */
185
+ function findFile(name, candidates) {
186
+ const found = candidates.find((path) => (0, node_fs.existsSync)(path));
187
+ if (found == null) throw new Error(`Cannot find ${name} in ${candidates.join(", ")}`);
188
+ return found;
189
+ }
190
+ function getModuleDirectory(moduleUrl) {
191
+ return typeof moduleUrl === "string" && moduleUrl.startsWith("file:") ? (0, node_path.dirname)((0, node_url.fileURLToPath)(moduleUrl)) : null;
192
+ }
193
+ const TESTDATA = [
194
+ "src",
195
+ "pinners",
196
+ "testdata"
197
+ ];
198
+ /**
199
+ * Finds a source file in *testdata/* (e.g., a child script that Bun runs
200
+ * directly). When a test runs from the compiled *dist/tests/pinners/*
201
+ * instead of *src/pinners/*, the test data is not compiled with it, so this
202
+ * falls back to the files in the package: first relative to the test module,
203
+ * then relative to the working directory (the package root, where the Bun
204
+ * test script runs), in case `import.meta.url` is unavailable in a CommonJS
205
+ * build.
206
+ * @param name The file name.
207
+ * @param moduleUrl The `import.meta.url` of the test module.
208
+ */
209
+ function resolveTestdata(name, moduleUrl) {
210
+ const candidates = [];
211
+ const here = getModuleDirectory(moduleUrl);
212
+ if (here != null) candidates.push((0, node_path.join)(here, TESTDATA[2], name), (0, node_path.join)(here, "..", "..", "..", ...TESTDATA, name));
213
+ candidates.push((0, node_path.join)(node_process.default.cwd(), ...TESTDATA, name));
214
+ return findFile(name, candidates);
215
+ }
216
+ /**
217
+ * Finds a child script of *testdata/* compiled into
218
+ * *dist/tests/pinners/testdata/* by *tsdown.config.ts*, for Node.js, which
219
+ * cannot run TypeScript sources without flags before 22.6.0. Node.js tests
220
+ * run only from *dist/tests/* (`cd dist/tests && node --test`), so this looks
221
+ * relative to the test module, then relative to the working directory, in
222
+ * case `import.meta.url` is unavailable in a CommonJS build.
223
+ * @param name The compiled file name, e.g., `node-child.mjs`.
224
+ * @param moduleUrl The `import.meta.url` of the test module.
225
+ */
226
+ function resolveCompiledTestdata(name, moduleUrl) {
227
+ const candidates = [];
228
+ const here = getModuleDirectory(moduleUrl);
229
+ if (here != null) candidates.push((0, node_path.join)(here, TESTDATA[2], name));
230
+ candidates.push((0, node_path.join)(node_process.default.cwd(), ...TESTDATA.slice(1), name), (0, node_path.join)(node_process.default.cwd(), "dist", "tests", ...TESTDATA.slice(1), name));
231
+ return findFile(name, candidates);
232
+ }
233
+ const PROXY_ENV_NAMES = [
234
+ "HTTP_PROXY",
235
+ "HTTPS_PROXY",
236
+ "ALL_PROXY",
237
+ "NO_PROXY"
238
+ ];
239
+ /**
240
+ * Runs a child script in a new process of the current runtime, without proxy
241
+ * environment variables (and `NODE_USE_ENV_PROXY`) but with the given ones,
242
+ * and parses the last line of its output as JSON.
243
+ * @param script The path of the script.
244
+ * @param args The arguments to the script.
245
+ * @param extraEnv The environment variables to set.
246
+ */
247
+ function runChild(script, args, extraEnv) {
248
+ const env = { ...node_process.default.env };
249
+ for (const name of PROXY_ENV_NAMES) {
250
+ delete env[name];
251
+ delete env[name.toLowerCase()];
252
+ }
253
+ delete env.NODE_USE_ENV_PROXY;
254
+ Object.assign(env, extraEnv);
255
+ return new Promise((resolve, reject) => {
256
+ (0, node_child_process.execFile)(node_process.default.execPath, [script, ...args], {
257
+ env,
258
+ timeout: 3e4
259
+ }, (error, stdout, stderr) => {
260
+ if (error != null) {
261
+ reject(new Error(`${script} failed: ${stderr}`, { cause: error }));
262
+ return;
263
+ }
264
+ const line = stdout.trim().split("\n").at(-1) ?? "";
265
+ try {
266
+ resolve(JSON.parse(line));
267
+ } catch (cause) {
268
+ reject(new Error(`Unexpected output: ${stdout}${stderr}`, { cause }));
269
+ }
270
+ });
271
+ });
272
+ }
273
+ //#endregion
274
+ Object.defineProperty(exports, "allowAll", {
275
+ enumerable: true,
276
+ get: function() {
277
+ return allowAll;
278
+ }
279
+ });
280
+ Object.defineProperty(exports, "closeServer", {
281
+ enumerable: true,
282
+ get: function() {
283
+ return closeServer;
284
+ }
285
+ });
286
+ Object.defineProperty(exports, "getLoopbackSupport", {
287
+ enumerable: true,
288
+ get: function() {
289
+ return getLoopbackSupport;
290
+ }
291
+ });
292
+ Object.defineProperty(exports, "ipv4", {
293
+ enumerable: true,
294
+ get: function() {
295
+ return ipv4;
296
+ }
297
+ });
298
+ Object.defineProperty(exports, "ipv6", {
299
+ enumerable: true,
300
+ get: function() {
301
+ return ipv6;
302
+ }
303
+ });
304
+ Object.defineProperty(exports, "isAddressRejection", {
305
+ enumerable: true,
306
+ get: function() {
307
+ return isAddressRejection;
308
+ }
309
+ });
310
+ Object.defineProperty(exports, "isBun", {
311
+ enumerable: true,
312
+ get: function() {
313
+ return isBun;
314
+ }
315
+ });
316
+ Object.defineProperty(exports, "isNode", {
317
+ enumerable: true,
318
+ get: function() {
319
+ return isNode;
320
+ }
321
+ });
322
+ Object.defineProperty(exports, "listen", {
323
+ enumerable: true,
324
+ get: function() {
325
+ return listen;
326
+ }
327
+ });
328
+ Object.defineProperty(exports, "resolveCompiledTestdata", {
329
+ enumerable: true,
330
+ get: function() {
331
+ return resolveCompiledTestdata;
332
+ }
333
+ });
334
+ Object.defineProperty(exports, "resolveTestdata", {
335
+ enumerable: true,
336
+ get: function() {
337
+ return resolveTestdata;
338
+ }
339
+ });
340
+ Object.defineProperty(exports, "runChild", {
341
+ enumerable: true,
342
+ get: function() {
343
+ return runChild;
344
+ }
345
+ });
346
+ Object.defineProperty(exports, "startCountingServer", {
347
+ enumerable: true,
348
+ get: function() {
349
+ return startCountingServer;
350
+ }
351
+ });
352
+ Object.defineProperty(exports, "startRecordingProxy", {
353
+ enumerable: true,
354
+ get: function() {
355
+ return startRecordingProxy;
356
+ }
357
+ });
358
+ Object.defineProperty(exports, "startRecordingServer", {
359
+ enumerable: true,
360
+ get: function() {
361
+ return startRecordingServer;
362
+ }
363
+ });
@@ -0,0 +1,272 @@
1
+ import { n as UrlError } from "./url-COj5Q8mb.mjs";
2
+ import { t as detectRuntime } from "./pinners-zSofbiy2.mjs";
3
+ import process from "node:process";
4
+ import { connect, createServer } from "node:net";
5
+ import { createServer as createServer$1 } from "node:http";
6
+ import { existsSync } from "node:fs";
7
+ import { execFile } from "node:child_process";
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ //#region src/pinners/testdata/support.ts
11
+ /**
12
+ * Helpers shared by the pinner tests in *../\*.test.ts*. They start local
13
+ * servers and proxies, and run child processes.
14
+ * @module
15
+ */
16
+ const isBun = detectRuntime() === "bun";
17
+ const isNode = detectRuntime() === "node";
18
+ /** Pinner options that allow connecting to any address, e.g., loopback. */
19
+ const allowAll = { verifyAddress() {} };
20
+ const ipv4 = (address) => ({
21
+ address,
22
+ family: 4
23
+ });
24
+ const ipv6 = (address) => ({
25
+ address,
26
+ family: 6
27
+ });
28
+ /**
29
+ * Whether the error is the rejection of an address by `verifyAddress`.
30
+ * The Bun pinner throws the `UrlError` itself, and the Node.js pinner
31
+ * rejects with the `TypeError` of `fetch()`, caused by the `UrlError` that
32
+ * its lookup failed with.
33
+ */
34
+ function isAddressRejection(error) {
35
+ return error instanceof UrlError || error instanceof TypeError && error.cause instanceof UrlError;
36
+ }
37
+ function readBody(req) {
38
+ return new Promise((resolve, reject) => {
39
+ let body = "";
40
+ req.setEncoding("utf8");
41
+ req.on("data", (chunk) => body += chunk);
42
+ req.on("end", () => resolve(body));
43
+ req.on("error", reject);
44
+ });
45
+ }
46
+ async function listen(server, host = "127.0.0.1") {
47
+ await new Promise((resolve, reject) => {
48
+ server.once("error", reject);
49
+ server.listen(0, host, () => {
50
+ server.off("error", reject);
51
+ resolve();
52
+ });
53
+ });
54
+ return server.address().port;
55
+ }
56
+ async function closeServer(server) {
57
+ server.closeAllConnections?.();
58
+ await new Promise((resolve) => server.close(() => resolve()));
59
+ }
60
+ function canConnect(host, port) {
61
+ return new Promise((resolve) => {
62
+ const socket = connect({
63
+ host,
64
+ port
65
+ });
66
+ const done = (result) => {
67
+ socket.destroy();
68
+ resolve(result);
69
+ };
70
+ socket.setTimeout(2e3, () => done(false));
71
+ socket.once("connect", () => done(true));
72
+ socket.once("error", () => done(false));
73
+ });
74
+ }
75
+ let loopbackSupport;
76
+ /**
77
+ * Checks which loopback addresses the tests can use. Only 127.0.0.1 is
78
+ * assumed: other addresses of 127.0.0.0/8 are not configured on macOS, and
79
+ * IPv6 can be disabled.
80
+ */
81
+ function getLoopbackSupport() {
82
+ loopbackSupport ??= (async () => {
83
+ const server = createServer((socket) => socket.destroy());
84
+ let port;
85
+ try {
86
+ port = await listen(server, "::");
87
+ } catch {
88
+ return {
89
+ ipv6: false,
90
+ dualStack: false
91
+ };
92
+ }
93
+ try {
94
+ const [v4, v6] = await Promise.all([canConnect("127.0.0.1", port), canConnect("::1", port)]);
95
+ return {
96
+ ipv6: v6,
97
+ dualStack: v4 && v6
98
+ };
99
+ } finally {
100
+ await closeServer(server);
101
+ }
102
+ })();
103
+ return loopbackSupport;
104
+ }
105
+ /**
106
+ * Starts an HTTP server that records the requests it receives.
107
+ */
108
+ async function startRecordingServer(host = "127.0.0.1", respond = (_, res) => res.end("pinned")) {
109
+ const requests = [];
110
+ const server = createServer$1(async (req, res) => {
111
+ const body = await readBody(req);
112
+ requests.push({
113
+ method: req.method ?? "",
114
+ url: req.url ?? "",
115
+ host: req.headers.host,
116
+ localAddress: req.socket.localAddress,
117
+ body
118
+ });
119
+ respond(req, res);
120
+ });
121
+ return {
122
+ server,
123
+ port: await listen(server, host),
124
+ requests
125
+ };
126
+ }
127
+ /**
128
+ * Starts a TCP server that only counts the connections it accepts, and drops
129
+ * them right away. It stands for an HTTPS server without a certificate.
130
+ */
131
+ async function startCountingServer() {
132
+ const counter = { connections: 0 };
133
+ const server = createServer((socket) => {
134
+ counter.connections++;
135
+ socket.destroy();
136
+ });
137
+ return {
138
+ server,
139
+ port: await listen(server),
140
+ counter
141
+ };
142
+ }
143
+ /**
144
+ * Starts a proxy that records the request targets it is asked for, and never
145
+ * forwards them. It answers a request in absolute form with `via-proxy`,
146
+ * and drops tunnels (`CONNECT`). It parses requests by itself since
147
+ * the `connect` event of `node:http` servers is not available on older Bun
148
+ * versions.
149
+ * @param options.refuseTunnels Whether to refuse tunnels with a `403`
150
+ * response instead of dropping them. Some
151
+ * clients retry dropped tunnels without end
152
+ * (e.g., the `EnvHttpProxyAgent` of Node.js),
153
+ * and some take the response of a refused
154
+ * tunnel for the response of the request
155
+ * (e.g., Bun 1.3.14).
156
+ */
157
+ async function startRecordingProxy({ refuseTunnels = false } = {}) {
158
+ const targets = [];
159
+ const server = createServer((socket) => {
160
+ let head = "";
161
+ socket.setEncoding("latin1");
162
+ socket.on("error", () => {});
163
+ socket.on("data", (chunk) => {
164
+ if (head.includes("\r\n\r\n")) return;
165
+ head += chunk;
166
+ if (!head.includes("\r\n\r\n")) return;
167
+ const [method, target] = head.slice(0, head.indexOf("\r\n")).split(" ");
168
+ targets.push(`${method} ${target}`);
169
+ if (method !== "CONNECT") socket.end("HTTP/1.1 200 OK\r\nContent-Length: 9\r\nConnection: close\r\n\r\nvia-proxy");
170
+ else if (refuseTunnels) socket.end("HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
171
+ else socket.destroy();
172
+ });
173
+ });
174
+ return {
175
+ server,
176
+ port: await listen(server),
177
+ targets
178
+ };
179
+ }
180
+ /**
181
+ * Returns the first of the given paths that exists.
182
+ */
183
+ function findFile(name, candidates) {
184
+ const found = candidates.find((path) => existsSync(path));
185
+ if (found == null) throw new Error(`Cannot find ${name} in ${candidates.join(", ")}`);
186
+ return found;
187
+ }
188
+ function getModuleDirectory(moduleUrl) {
189
+ return typeof moduleUrl === "string" && moduleUrl.startsWith("file:") ? dirname(fileURLToPath(moduleUrl)) : null;
190
+ }
191
+ const TESTDATA = [
192
+ "src",
193
+ "pinners",
194
+ "testdata"
195
+ ];
196
+ /**
197
+ * Finds a source file in *testdata/* (e.g., a child script that Bun runs
198
+ * directly). When a test runs from the compiled *dist/tests/pinners/*
199
+ * instead of *src/pinners/*, the test data is not compiled with it, so this
200
+ * falls back to the files in the package: first relative to the test module,
201
+ * then relative to the working directory (the package root, where the Bun
202
+ * test script runs), in case `import.meta.url` is unavailable in a CommonJS
203
+ * build.
204
+ * @param name The file name.
205
+ * @param moduleUrl The `import.meta.url` of the test module.
206
+ */
207
+ function resolveTestdata(name, moduleUrl) {
208
+ const candidates = [];
209
+ const here = getModuleDirectory(moduleUrl);
210
+ if (here != null) candidates.push(join(here, TESTDATA[2], name), join(here, "..", "..", "..", ...TESTDATA, name));
211
+ candidates.push(join(process.cwd(), ...TESTDATA, name));
212
+ return findFile(name, candidates);
213
+ }
214
+ /**
215
+ * Finds a child script of *testdata/* compiled into
216
+ * *dist/tests/pinners/testdata/* by *tsdown.config.ts*, for Node.js, which
217
+ * cannot run TypeScript sources without flags before 22.6.0. Node.js tests
218
+ * run only from *dist/tests/* (`cd dist/tests && node --test`), so this looks
219
+ * relative to the test module, then relative to the working directory, in
220
+ * case `import.meta.url` is unavailable in a CommonJS build.
221
+ * @param name The compiled file name, e.g., `node-child.mjs`.
222
+ * @param moduleUrl The `import.meta.url` of the test module.
223
+ */
224
+ function resolveCompiledTestdata(name, moduleUrl) {
225
+ const candidates = [];
226
+ const here = getModuleDirectory(moduleUrl);
227
+ if (here != null) candidates.push(join(here, TESTDATA[2], name));
228
+ candidates.push(join(process.cwd(), ...TESTDATA.slice(1), name), join(process.cwd(), "dist", "tests", ...TESTDATA.slice(1), name));
229
+ return findFile(name, candidates);
230
+ }
231
+ const PROXY_ENV_NAMES = [
232
+ "HTTP_PROXY",
233
+ "HTTPS_PROXY",
234
+ "ALL_PROXY",
235
+ "NO_PROXY"
236
+ ];
237
+ /**
238
+ * Runs a child script in a new process of the current runtime, without proxy
239
+ * environment variables (and `NODE_USE_ENV_PROXY`) but with the given ones,
240
+ * and parses the last line of its output as JSON.
241
+ * @param script The path of the script.
242
+ * @param args The arguments to the script.
243
+ * @param extraEnv The environment variables to set.
244
+ */
245
+ function runChild(script, args, extraEnv) {
246
+ const env = { ...process.env };
247
+ for (const name of PROXY_ENV_NAMES) {
248
+ delete env[name];
249
+ delete env[name.toLowerCase()];
250
+ }
251
+ delete env.NODE_USE_ENV_PROXY;
252
+ Object.assign(env, extraEnv);
253
+ return new Promise((resolve, reject) => {
254
+ execFile(process.execPath, [script, ...args], {
255
+ env,
256
+ timeout: 3e4
257
+ }, (error, stdout, stderr) => {
258
+ if (error != null) {
259
+ reject(new Error(`${script} failed: ${stderr}`, { cause: error }));
260
+ return;
261
+ }
262
+ const line = stdout.trim().split("\n").at(-1) ?? "";
263
+ try {
264
+ resolve(JSON.parse(line));
265
+ } catch (cause) {
266
+ reject(new Error(`Unexpected output: ${stdout}${stderr}`, { cause }));
267
+ }
268
+ });
269
+ });
270
+ }
271
+ //#endregion
272
+ export { ipv6 as a, isNode as c, resolveTestdata as d, runChild as f, startRecordingServer as h, ipv4 as i, listen as l, startRecordingProxy as m, closeServer as n, isAddressRejection as o, startCountingServer as p, getLoopbackSupport as r, isBun as s, allowAll as t, resolveCompiledTestdata as u };