@fedify/vocab-runtime 2.4.0-dev.2169 → 2.4.0-dev.2193
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/deno.json +1 -1
- package/dist/{docloader-ClQraSWr.d.cts → docloader-C63enuyr.d.cts} +53 -1
- package/dist/{docloader-ClQraSWr.d.ts → docloader-C63enuyr.d.ts} +53 -1
- package/dist/internal/jsonld-cache.cjs +1 -1
- package/dist/internal/jsonld-cache.d.cts +1 -1
- package/dist/internal/jsonld-cache.d.ts +1 -1
- package/dist/internal/jsonld-cache.js +1 -1
- package/dist/internal/portable-dereference.cjs +1 -1
- package/dist/internal/portable-dereference.d.cts +2 -2
- package/dist/internal/portable-dereference.d.ts +2 -2
- package/dist/internal/portable-dereference.js +1 -1
- package/dist/mod.cjs +206 -17
- package/dist/mod.d.cts +7 -3
- package/dist/mod.d.ts +7 -3
- package/dist/mod.js +205 -18
- package/dist/{portable-ilkFPcXa.d.cts → portable-Cux3IA20.d.cts} +1 -1
- package/dist/{portable-DRtvOxTb.d.ts → portable-DBA1FS_L.d.ts} +1 -1
- package/dist/tests/{body-CNwDKYQs.mjs → body-D1z0X88T.mjs} +55 -2
- package/dist/tests/{body-DHAC8qhR.cjs → body-ORlui-Nx.cjs} +60 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/decimal.test.cjs +2 -2
- package/dist/tests/decimal.test.mjs +2 -2
- package/dist/tests/{docloader-DWkl3u7X.mjs → docloader-CUdtpDuf.mjs} +153 -19
- package/dist/tests/{docloader-DLkb9qAS.cjs → docloader-Vc3BC9ad.cjs} +164 -18
- package/dist/tests/docloader.test.cjs +266 -3
- package/dist/tests/docloader.test.mjs +267 -4
- package/dist/tests/internal/portable-dereference.test.cjs +2 -2
- package/dist/tests/internal/portable-dereference.test.mjs +2 -2
- package/dist/tests/{jsonld-cache-BO-QXxIc.cjs → jsonld-cache-BQMn_ILF.cjs} +1 -1
- package/dist/tests/{jsonld-cache-B7PKo3Lu.mjs → jsonld-cache-DUmuWRwp.mjs} +1 -1
- package/dist/tests/jsonld-cache.test.cjs +2 -2
- package/dist/tests/jsonld-cache.test.mjs +2 -2
- package/dist/tests/{request-Dm3ye46t.cjs → request-C5_3S-un.cjs} +1 -1
- package/dist/tests/{request-Cg8MQByW.mjs → request-IIntZ5kj.mjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/dist/tests/{url-gLKqAO1H.cjs → url-B8xyTwP-.cjs} +5 -1
- package/dist/tests/{url-D7qRF-dF.mjs → url-DfS-cvwr.mjs} +5 -1
- package/dist/tests/url.test.cjs +2 -2
- package/dist/tests/url.test.mjs +2 -2
- package/dist/{url-BHZYe8Vu.js → url-Be3moMor.js} +5 -1
- package/dist/{url-P6l9s9dN.cjs → url-DDVweCXr.cjs} +5 -1
- package/package.json +1 -1
- package/src/body.ts +57 -0
- package/src/docloader.test.ts +341 -3
- package/src/docloader.ts +205 -5
- package/src/mod.ts +2 -0
- package/src/url.test.ts +7 -1
- package/src/url.ts +6 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-C5_3S-un.cjs");
|
|
3
3
|
const require_contexts = require("./contexts-DizzBjz4.cjs");
|
|
4
|
-
const require_url = require("./url-
|
|
5
|
-
const require_docloader = require("./docloader-
|
|
4
|
+
const require_url = require("./url-B8xyTwP-.cjs");
|
|
5
|
+
const require_docloader = require("./docloader-Vc3BC9ad.cjs");
|
|
6
6
|
let node_test = require("node:test");
|
|
7
7
|
let node_zlib = require("node:zlib");
|
|
8
8
|
let _logtape_logtape = require("@logtape/logtape");
|
|
@@ -1990,4 +1990,267 @@ var esm_default = new class FetchMock {
|
|
|
1990
1990
|
esm_default.hardReset();
|
|
1991
1991
|
}
|
|
1992
1992
|
});
|
|
1993
|
+
async function withServer(handler, callback) {
|
|
1994
|
+
const server = (0, node_http.createServer)(handler);
|
|
1995
|
+
await new Promise((resolve, reject) => {
|
|
1996
|
+
server.once("error", reject);
|
|
1997
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
1998
|
+
});
|
|
1999
|
+
try {
|
|
2000
|
+
const address = server.address();
|
|
2001
|
+
(0, node_assert.ok)(address != null && typeof address !== "string");
|
|
2002
|
+
return await callback(`http://127.0.0.1:${address.port}`);
|
|
2003
|
+
} finally {
|
|
2004
|
+
await new Promise((resolve, reject) => {
|
|
2005
|
+
server.close((error) => error == null ? resolve() : reject(error));
|
|
2006
|
+
server.closeAllConnections();
|
|
2007
|
+
});
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
function isTimeoutFetchError(error, url) {
|
|
2011
|
+
(0, node_assert.ok)(error instanceof require_request.FetchError, String(error));
|
|
2012
|
+
(0, node_assert.deepStrictEqual)(error.url.href, url);
|
|
2013
|
+
(0, node_assert.deepStrictEqual)(error.response, void 0);
|
|
2014
|
+
(0, node_assert.ok)(error.cause instanceof DOMException);
|
|
2015
|
+
(0, node_assert.deepStrictEqual)(error.cause.name, "TimeoutError");
|
|
2016
|
+
return true;
|
|
2017
|
+
}
|
|
2018
|
+
(0, node_test.test)("resolveDocumentLoaderTimeout() validates timeouts", () => {
|
|
2019
|
+
(0, node_assert.deepStrictEqual)(require_docloader.resolveDocumentLoaderTimeout(void 0), 1e4);
|
|
2020
|
+
(0, node_assert.deepStrictEqual)(require_docloader.resolveDocumentLoaderTimeout(null), null);
|
|
2021
|
+
(0, node_assert.deepStrictEqual)(require_docloader.resolveDocumentLoaderTimeout(1500), 1500);
|
|
2022
|
+
(0, node_assert.deepStrictEqual)(require_docloader.resolveDocumentLoaderTimeout(.5), 1);
|
|
2023
|
+
(0, node_assert.deepStrictEqual)(require_docloader.resolveDocumentLoaderTimeout(2147483647), 2147483647);
|
|
2024
|
+
for (const invalid of [
|
|
2025
|
+
0,
|
|
2026
|
+
-1,
|
|
2027
|
+
NaN,
|
|
2028
|
+
Infinity,
|
|
2029
|
+
2147483648
|
|
2030
|
+
]) (0, node_assert.throws)(() => require_docloader.resolveDocumentLoaderTimeout(invalid), RangeError);
|
|
2031
|
+
(0, node_assert.throws)(() => require_docloader.getDocumentLoader({ timeout: 0 }), RangeError);
|
|
2032
|
+
});
|
|
2033
|
+
(0, node_test.test)("getDocumentLoader() times out a request without a response", async () => {
|
|
2034
|
+
await withServer(() => {}, async (baseUrl) => {
|
|
2035
|
+
const url = `${baseUrl}/hang`;
|
|
2036
|
+
await (0, node_assert.rejects)(require_docloader.getDocumentLoader({
|
|
2037
|
+
allowPrivateAddress: true,
|
|
2038
|
+
timeout: 100
|
|
2039
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2040
|
+
});
|
|
2041
|
+
});
|
|
2042
|
+
(0, node_test.test)("getDocumentLoader() times out a stalled response body", async () => {
|
|
2043
|
+
for (const status of [200, 404]) await withServer((_, response) => {
|
|
2044
|
+
response.writeHead(status, { "Content-Type": "application/activity+json" });
|
|
2045
|
+
response.write("{\"id\":");
|
|
2046
|
+
}, async (baseUrl) => {
|
|
2047
|
+
const url = `${baseUrl}/stalled`;
|
|
2048
|
+
await (0, node_assert.rejects)(require_docloader.getDocumentLoader({
|
|
2049
|
+
allowPrivateAddress: true,
|
|
2050
|
+
timeout: 200
|
|
2051
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2052
|
+
});
|
|
2053
|
+
});
|
|
2054
|
+
(0, node_test.test)("getDocumentLoader() shares the timeout across redirects", async () => {
|
|
2055
|
+
let requests = 0;
|
|
2056
|
+
await withServer((request, response) => {
|
|
2057
|
+
requests++;
|
|
2058
|
+
const index = Number(request.url?.split("/").at(-1));
|
|
2059
|
+
setTimeout(() => {
|
|
2060
|
+
if (index >= 15) {
|
|
2061
|
+
response.writeHead(200, { "Content-Type": "application/activity+json" });
|
|
2062
|
+
response.end("{\"done\":true}");
|
|
2063
|
+
return;
|
|
2064
|
+
}
|
|
2065
|
+
response.writeHead(302, { Location: `/redirect/${index + 1}` });
|
|
2066
|
+
response.end();
|
|
2067
|
+
}, 50);
|
|
2068
|
+
}, async (baseUrl) => {
|
|
2069
|
+
const url = `${baseUrl}/redirect/0`;
|
|
2070
|
+
await (0, node_assert.rejects)(require_docloader.getDocumentLoader({
|
|
2071
|
+
allowPrivateAddress: true,
|
|
2072
|
+
timeout: 300
|
|
2073
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2074
|
+
(0, node_assert.ok)(requests < 16, `requests: ${requests}`);
|
|
2075
|
+
(0, node_assert.deepStrictEqual)((await require_docloader.getDocumentLoader({
|
|
2076
|
+
allowPrivateAddress: true,
|
|
2077
|
+
timeout: null
|
|
2078
|
+
})(url)).document, { done: true });
|
|
2079
|
+
});
|
|
2080
|
+
});
|
|
2081
|
+
(0, node_test.test)("getDocumentLoader() shares the timeout across alternates", async (t) => {
|
|
2082
|
+
for (const html of [false, true]) await t.test(html ? "HTML" : "Link header", async () => {
|
|
2083
|
+
await withServer((request, response) => {
|
|
2084
|
+
const index = Number(request.url?.split("/").at(-1));
|
|
2085
|
+
setTimeout(() => {
|
|
2086
|
+
if (index >= 15) {
|
|
2087
|
+
response.writeHead(200, { "Content-Type": "application/activity+json" });
|
|
2088
|
+
response.end("{\"done\":true}");
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
const next = `/alternate/${index + 1}`;
|
|
2092
|
+
response.writeHead(200, html ? { "Content-Type": "text/html" } : {
|
|
2093
|
+
"Content-Type": "text/plain",
|
|
2094
|
+
Link: `<${next}>; rel="alternate"; type="application/activity+json"`
|
|
2095
|
+
});
|
|
2096
|
+
response.end(html ? `<link rel="alternate" type="application/activity+json" href="${next}">` : "not JSON");
|
|
2097
|
+
}, 50);
|
|
2098
|
+
}, async (baseUrl) => {
|
|
2099
|
+
const url = `${baseUrl}/alternate/0`;
|
|
2100
|
+
await (0, node_assert.rejects)(require_docloader.getDocumentLoader({
|
|
2101
|
+
allowPrivateAddress: true,
|
|
2102
|
+
timeout: 300
|
|
2103
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2104
|
+
});
|
|
2105
|
+
});
|
|
2106
|
+
});
|
|
2107
|
+
(0, node_test.test)("getDocumentLoader() lets the caller's signal abort a request", async () => {
|
|
2108
|
+
await withServer(() => {}, async (baseUrl) => {
|
|
2109
|
+
const url = `${baseUrl}/hang`;
|
|
2110
|
+
for (const timeout of [
|
|
2111
|
+
void 0,
|
|
2112
|
+
6e4,
|
|
2113
|
+
null
|
|
2114
|
+
]) {
|
|
2115
|
+
const loader = require_docloader.getDocumentLoader({
|
|
2116
|
+
allowPrivateAddress: true,
|
|
2117
|
+
timeout
|
|
2118
|
+
});
|
|
2119
|
+
const controller = new AbortController();
|
|
2120
|
+
const reason = /* @__PURE__ */ new Error("Canceled by the caller");
|
|
2121
|
+
setTimeout(() => controller.abort(reason), 50);
|
|
2122
|
+
await (0, node_assert.rejects)(loader(url, { signal: controller.signal }), (e) => {
|
|
2123
|
+
(0, node_assert.deepStrictEqual)(e, reason);
|
|
2124
|
+
return true;
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2127
|
+
const loader = require_docloader.getDocumentLoader({
|
|
2128
|
+
allowPrivateAddress: true,
|
|
2129
|
+
timeout: 50
|
|
2130
|
+
});
|
|
2131
|
+
const controller = new AbortController();
|
|
2132
|
+
const reason = /* @__PURE__ */ new Error("Canceled by the caller");
|
|
2133
|
+
controller.abort(reason);
|
|
2134
|
+
await (0, node_assert.rejects)(loader(url, { signal: controller.signal }), (e) => {
|
|
2135
|
+
(0, node_assert.deepStrictEqual)(e, reason);
|
|
2136
|
+
return true;
|
|
2137
|
+
});
|
|
2138
|
+
});
|
|
2139
|
+
});
|
|
2140
|
+
(0, node_test.test)("getDocumentLoader() bounds DNS lookups that ignore the timeout", async (t) => {
|
|
2141
|
+
if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted") {
|
|
2142
|
+
t.skip("requires the net permission");
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2145
|
+
esm_default.mockGlobal();
|
|
2146
|
+
let requests = 0;
|
|
2147
|
+
const url = "https://slow-dns.example/object";
|
|
2148
|
+
esm_default.get(url, () => {
|
|
2149
|
+
requests++;
|
|
2150
|
+
return Response.json({ id: url });
|
|
2151
|
+
});
|
|
2152
|
+
const originalLookup = node_dns_promises.default.lookup;
|
|
2153
|
+
let resolveLookup = () => {};
|
|
2154
|
+
const lookedUp = new Promise((resolve) => resolveLookup = resolve);
|
|
2155
|
+
node_dns_promises.default.lookup = (() => new Promise((resolve) => setTimeout(() => {
|
|
2156
|
+
resolve([{
|
|
2157
|
+
address: "93.184.215.14",
|
|
2158
|
+
family: 4
|
|
2159
|
+
}]);
|
|
2160
|
+
resolveLookup();
|
|
2161
|
+
}, 200)));
|
|
2162
|
+
try {
|
|
2163
|
+
await (0, node_assert.rejects)(require_docloader.getDocumentLoader({ timeout: 50 })(url), (e) => isTimeoutFetchError(e, url));
|
|
2164
|
+
await lookedUp;
|
|
2165
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2166
|
+
(0, node_assert.deepStrictEqual)(requests, 0);
|
|
2167
|
+
} finally {
|
|
2168
|
+
node_dns_promises.default.lookup = originalLookup;
|
|
2169
|
+
esm_default.hardReset();
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
(0, node_test.test)("withDocumentLoaderTimeout() cleans up after each call", async () => {
|
|
2173
|
+
const signals = [];
|
|
2174
|
+
const loader = require_docloader.withDocumentLoaderTimeout((url, options) => {
|
|
2175
|
+
signals.push(options.signal);
|
|
2176
|
+
return Promise.resolve({
|
|
2177
|
+
contextUrl: null,
|
|
2178
|
+
document: {},
|
|
2179
|
+
documentUrl: url
|
|
2180
|
+
});
|
|
2181
|
+
}, 50);
|
|
2182
|
+
(0, node_assert.deepStrictEqual)((await Promise.all([loader("https://example.com/a"), loader("https://example.com/b")])).map((r) => r.documentUrl), ["https://example.com/a", "https://example.com/b"]);
|
|
2183
|
+
(0, node_assert.ok)(signals[0] !== signals[1]);
|
|
2184
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2185
|
+
(0, node_assert.ok)(signals.every((signal) => !signal.aborted));
|
|
2186
|
+
const inner = () => Promise.reject(/* @__PURE__ */ new Error("unused"));
|
|
2187
|
+
(0, node_assert.ok)(require_docloader.withDocumentLoaderTimeout(inner, null) === inner);
|
|
2188
|
+
});
|
|
2189
|
+
(0, node_test.test)("getRemoteDocument() keeps error bodies byte for byte", async () => {
|
|
2190
|
+
const bytes = new Uint8Array([
|
|
2191
|
+
239,
|
|
2192
|
+
187,
|
|
2193
|
+
191,
|
|
2194
|
+
78,
|
|
2195
|
+
111,
|
|
2196
|
+
255,
|
|
2197
|
+
254
|
|
2198
|
+
]);
|
|
2199
|
+
const url = "https://example.com/error";
|
|
2200
|
+
let error;
|
|
2201
|
+
await (0, node_assert.rejects)(require_docloader.getRemoteDocument(url, new Response(bytes, { status: 404 }), () => Promise.reject(/* @__PURE__ */ new Error("unused"))), (e) => {
|
|
2202
|
+
error = e;
|
|
2203
|
+
return true;
|
|
2204
|
+
});
|
|
2205
|
+
(0, node_assert.ok)(error instanceof require_request.FetchError);
|
|
2206
|
+
(0, node_assert.ok)(error.response != null);
|
|
2207
|
+
(0, node_assert.deepStrictEqual)(error.response.status, 404);
|
|
2208
|
+
(0, node_assert.deepStrictEqual)(new Uint8Array(await error.response.arrayBuffer()), bytes);
|
|
2209
|
+
});
|
|
2210
|
+
(0, node_test.test)("getRemoteDocument() keeps metadata of bodiless or large errors", async () => {
|
|
2211
|
+
const url = "https://example.com/error";
|
|
2212
|
+
for (const response of [new Response(null, {
|
|
2213
|
+
status: 304,
|
|
2214
|
+
headers: { ETag: "\"a\"" }
|
|
2215
|
+
}), new Response(/* @__PURE__ */ new Uint8Array(1048577), {
|
|
2216
|
+
status: 500,
|
|
2217
|
+
headers: { ETag: "\"a\"" }
|
|
2218
|
+
})]) await (0, node_assert.rejects)(require_docloader.getRemoteDocument(url, response, () => Promise.reject(/* @__PURE__ */ new Error("unused"))), (e) => {
|
|
2219
|
+
(0, node_assert.ok)(e instanceof require_request.FetchError);
|
|
2220
|
+
(0, node_assert.ok)(e.response != null);
|
|
2221
|
+
(0, node_assert.deepStrictEqual)(e.response.status, response.status);
|
|
2222
|
+
(0, node_assert.deepStrictEqual)(e.response.headers.get("ETag"), "\"a\"");
|
|
2223
|
+
(0, node_assert.deepStrictEqual)(e.response.body, null);
|
|
2224
|
+
return true;
|
|
2225
|
+
});
|
|
2226
|
+
});
|
|
2227
|
+
(0, node_test.test)("getDocumentLoader() reports statuses that Response cannot hold", async () => {
|
|
2228
|
+
await withServer((_, response) => {
|
|
2229
|
+
response.writeHead(999);
|
|
2230
|
+
response.end("Request denied");
|
|
2231
|
+
}, async (baseUrl) => {
|
|
2232
|
+
const url = `${baseUrl}/denied`;
|
|
2233
|
+
const loader = require_docloader.getDocumentLoader({ allowPrivateAddress: true });
|
|
2234
|
+
let error;
|
|
2235
|
+
await (0, node_assert.rejects)(loader(url), (e) => {
|
|
2236
|
+
error = e;
|
|
2237
|
+
return true;
|
|
2238
|
+
});
|
|
2239
|
+
(0, node_assert.ok)(error instanceof require_request.FetchError, String(error));
|
|
2240
|
+
(0, node_assert.deepStrictEqual)(error.response?.status, 999);
|
|
2241
|
+
(0, node_assert.deepStrictEqual)(await error.response.text(), "Request denied");
|
|
2242
|
+
});
|
|
2243
|
+
});
|
|
2244
|
+
(0, node_test.test)("getDocumentLoader() times out a stalled body of such a status", async () => {
|
|
2245
|
+
await withServer((_, response) => {
|
|
2246
|
+
response.writeHead(999);
|
|
2247
|
+
response.write("Request");
|
|
2248
|
+
}, async (baseUrl) => {
|
|
2249
|
+
const url = `${baseUrl}/stalled-denied`;
|
|
2250
|
+
await (0, node_assert.rejects)(require_docloader.getDocumentLoader({
|
|
2251
|
+
allowPrivateAddress: true,
|
|
2252
|
+
timeout: 200
|
|
2253
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2254
|
+
});
|
|
2255
|
+
});
|
|
1993
2256
|
//#endregion
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { t as FetchError } from "./request-
|
|
1
|
+
import { t as FetchError } from "./request-IIntZ5kj.mjs";
|
|
2
2
|
import { n as cid_v1_default, t as preloadedContexts } from "./contexts-CIKsin4e.mjs";
|
|
3
|
-
import { t as UrlError } from "./url-
|
|
4
|
-
import { n as getRemoteDocument, t as getDocumentLoader } from "./docloader-
|
|
3
|
+
import { t as UrlError } from "./url-DfS-cvwr.mjs";
|
|
4
|
+
import { i as withDocumentLoaderTimeout, n as getRemoteDocument, r as resolveDocumentLoaderTimeout, t as getDocumentLoader } from "./docloader-CUdtpDuf.mjs";
|
|
5
5
|
import { test } from "node:test";
|
|
6
6
|
import { gzipSync } from "node:zlib";
|
|
7
7
|
import { configure, reset } from "@logtape/logtape";
|
|
8
|
-
import { deepStrictEqual, ok, rejects } from "node:assert";
|
|
8
|
+
import { deepStrictEqual, ok, rejects, throws } from "node:assert";
|
|
9
9
|
import dns from "node:dns/promises";
|
|
10
10
|
import { createServer } from "node:http";
|
|
11
11
|
//#region \0rolldown/runtime.js
|
|
@@ -2008,5 +2008,268 @@ test("getDocumentLoader() rejects cancellation before fetching", async () => {
|
|
|
2008
2008
|
esm_default.hardReset();
|
|
2009
2009
|
}
|
|
2010
2010
|
});
|
|
2011
|
+
async function withServer(handler, callback) {
|
|
2012
|
+
const server = createServer(handler);
|
|
2013
|
+
await new Promise((resolve, reject) => {
|
|
2014
|
+
server.once("error", reject);
|
|
2015
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
2016
|
+
});
|
|
2017
|
+
try {
|
|
2018
|
+
const address = server.address();
|
|
2019
|
+
ok(address != null && typeof address !== "string");
|
|
2020
|
+
return await callback(`http://127.0.0.1:${address.port}`);
|
|
2021
|
+
} finally {
|
|
2022
|
+
await new Promise((resolve, reject) => {
|
|
2023
|
+
server.close((error) => error == null ? resolve() : reject(error));
|
|
2024
|
+
server.closeAllConnections();
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
function isTimeoutFetchError(error, url) {
|
|
2029
|
+
ok(error instanceof FetchError, String(error));
|
|
2030
|
+
deepStrictEqual(error.url.href, url);
|
|
2031
|
+
deepStrictEqual(error.response, void 0);
|
|
2032
|
+
ok(error.cause instanceof DOMException);
|
|
2033
|
+
deepStrictEqual(error.cause.name, "TimeoutError");
|
|
2034
|
+
return true;
|
|
2035
|
+
}
|
|
2036
|
+
test("resolveDocumentLoaderTimeout() validates timeouts", () => {
|
|
2037
|
+
deepStrictEqual(resolveDocumentLoaderTimeout(void 0), 1e4);
|
|
2038
|
+
deepStrictEqual(resolveDocumentLoaderTimeout(null), null);
|
|
2039
|
+
deepStrictEqual(resolveDocumentLoaderTimeout(1500), 1500);
|
|
2040
|
+
deepStrictEqual(resolveDocumentLoaderTimeout(.5), 1);
|
|
2041
|
+
deepStrictEqual(resolveDocumentLoaderTimeout(2147483647), 2147483647);
|
|
2042
|
+
for (const invalid of [
|
|
2043
|
+
0,
|
|
2044
|
+
-1,
|
|
2045
|
+
NaN,
|
|
2046
|
+
Infinity,
|
|
2047
|
+
2147483648
|
|
2048
|
+
]) throws(() => resolveDocumentLoaderTimeout(invalid), RangeError);
|
|
2049
|
+
throws(() => getDocumentLoader({ timeout: 0 }), RangeError);
|
|
2050
|
+
});
|
|
2051
|
+
test("getDocumentLoader() times out a request without a response", async () => {
|
|
2052
|
+
await withServer(() => {}, async (baseUrl) => {
|
|
2053
|
+
const url = `${baseUrl}/hang`;
|
|
2054
|
+
await rejects(getDocumentLoader({
|
|
2055
|
+
allowPrivateAddress: true,
|
|
2056
|
+
timeout: 100
|
|
2057
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2058
|
+
});
|
|
2059
|
+
});
|
|
2060
|
+
test("getDocumentLoader() times out a stalled response body", async () => {
|
|
2061
|
+
for (const status of [200, 404]) await withServer((_, response) => {
|
|
2062
|
+
response.writeHead(status, { "Content-Type": "application/activity+json" });
|
|
2063
|
+
response.write("{\"id\":");
|
|
2064
|
+
}, async (baseUrl) => {
|
|
2065
|
+
const url = `${baseUrl}/stalled`;
|
|
2066
|
+
await rejects(getDocumentLoader({
|
|
2067
|
+
allowPrivateAddress: true,
|
|
2068
|
+
timeout: 200
|
|
2069
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2070
|
+
});
|
|
2071
|
+
});
|
|
2072
|
+
test("getDocumentLoader() shares the timeout across redirects", async () => {
|
|
2073
|
+
let requests = 0;
|
|
2074
|
+
await withServer((request, response) => {
|
|
2075
|
+
requests++;
|
|
2076
|
+
const index = Number(request.url?.split("/").at(-1));
|
|
2077
|
+
setTimeout(() => {
|
|
2078
|
+
if (index >= 15) {
|
|
2079
|
+
response.writeHead(200, { "Content-Type": "application/activity+json" });
|
|
2080
|
+
response.end("{\"done\":true}");
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
response.writeHead(302, { Location: `/redirect/${index + 1}` });
|
|
2084
|
+
response.end();
|
|
2085
|
+
}, 50);
|
|
2086
|
+
}, async (baseUrl) => {
|
|
2087
|
+
const url = `${baseUrl}/redirect/0`;
|
|
2088
|
+
await rejects(getDocumentLoader({
|
|
2089
|
+
allowPrivateAddress: true,
|
|
2090
|
+
timeout: 300
|
|
2091
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2092
|
+
ok(requests < 16, `requests: ${requests}`);
|
|
2093
|
+
deepStrictEqual((await getDocumentLoader({
|
|
2094
|
+
allowPrivateAddress: true,
|
|
2095
|
+
timeout: null
|
|
2096
|
+
})(url)).document, { done: true });
|
|
2097
|
+
});
|
|
2098
|
+
});
|
|
2099
|
+
test("getDocumentLoader() shares the timeout across alternates", async (t) => {
|
|
2100
|
+
for (const html of [false, true]) await t.test(html ? "HTML" : "Link header", async () => {
|
|
2101
|
+
await withServer((request, response) => {
|
|
2102
|
+
const index = Number(request.url?.split("/").at(-1));
|
|
2103
|
+
setTimeout(() => {
|
|
2104
|
+
if (index >= 15) {
|
|
2105
|
+
response.writeHead(200, { "Content-Type": "application/activity+json" });
|
|
2106
|
+
response.end("{\"done\":true}");
|
|
2107
|
+
return;
|
|
2108
|
+
}
|
|
2109
|
+
const next = `/alternate/${index + 1}`;
|
|
2110
|
+
response.writeHead(200, html ? { "Content-Type": "text/html" } : {
|
|
2111
|
+
"Content-Type": "text/plain",
|
|
2112
|
+
Link: `<${next}>; rel="alternate"; type="application/activity+json"`
|
|
2113
|
+
});
|
|
2114
|
+
response.end(html ? `<link rel="alternate" type="application/activity+json" href="${next}">` : "not JSON");
|
|
2115
|
+
}, 50);
|
|
2116
|
+
}, async (baseUrl) => {
|
|
2117
|
+
const url = `${baseUrl}/alternate/0`;
|
|
2118
|
+
await rejects(getDocumentLoader({
|
|
2119
|
+
allowPrivateAddress: true,
|
|
2120
|
+
timeout: 300
|
|
2121
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2122
|
+
});
|
|
2123
|
+
});
|
|
2124
|
+
});
|
|
2125
|
+
test("getDocumentLoader() lets the caller's signal abort a request", async () => {
|
|
2126
|
+
await withServer(() => {}, async (baseUrl) => {
|
|
2127
|
+
const url = `${baseUrl}/hang`;
|
|
2128
|
+
for (const timeout of [
|
|
2129
|
+
void 0,
|
|
2130
|
+
6e4,
|
|
2131
|
+
null
|
|
2132
|
+
]) {
|
|
2133
|
+
const loader = getDocumentLoader({
|
|
2134
|
+
allowPrivateAddress: true,
|
|
2135
|
+
timeout
|
|
2136
|
+
});
|
|
2137
|
+
const controller = new AbortController();
|
|
2138
|
+
const reason = /* @__PURE__ */ new Error("Canceled by the caller");
|
|
2139
|
+
setTimeout(() => controller.abort(reason), 50);
|
|
2140
|
+
await rejects(loader(url, { signal: controller.signal }), (e) => {
|
|
2141
|
+
deepStrictEqual(e, reason);
|
|
2142
|
+
return true;
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
const loader = getDocumentLoader({
|
|
2146
|
+
allowPrivateAddress: true,
|
|
2147
|
+
timeout: 50
|
|
2148
|
+
});
|
|
2149
|
+
const controller = new AbortController();
|
|
2150
|
+
const reason = /* @__PURE__ */ new Error("Canceled by the caller");
|
|
2151
|
+
controller.abort(reason);
|
|
2152
|
+
await rejects(loader(url, { signal: controller.signal }), (e) => {
|
|
2153
|
+
deepStrictEqual(e, reason);
|
|
2154
|
+
return true;
|
|
2155
|
+
});
|
|
2156
|
+
});
|
|
2157
|
+
});
|
|
2158
|
+
test("getDocumentLoader() bounds DNS lookups that ignore the timeout", async (t) => {
|
|
2159
|
+
if ("Deno" in globalThis && (await Deno.permissions.query({ name: "net" })).state !== "granted") {
|
|
2160
|
+
t.skip("requires the net permission");
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
esm_default.mockGlobal();
|
|
2164
|
+
let requests = 0;
|
|
2165
|
+
const url = "https://slow-dns.example/object";
|
|
2166
|
+
esm_default.get(url, () => {
|
|
2167
|
+
requests++;
|
|
2168
|
+
return Response.json({ id: url });
|
|
2169
|
+
});
|
|
2170
|
+
const originalLookup = dns.lookup;
|
|
2171
|
+
let resolveLookup = () => {};
|
|
2172
|
+
const lookedUp = new Promise((resolve) => resolveLookup = resolve);
|
|
2173
|
+
dns.lookup = (() => new Promise((resolve) => setTimeout(() => {
|
|
2174
|
+
resolve([{
|
|
2175
|
+
address: "93.184.215.14",
|
|
2176
|
+
family: 4
|
|
2177
|
+
}]);
|
|
2178
|
+
resolveLookup();
|
|
2179
|
+
}, 200)));
|
|
2180
|
+
try {
|
|
2181
|
+
await rejects(getDocumentLoader({ timeout: 50 })(url), (e) => isTimeoutFetchError(e, url));
|
|
2182
|
+
await lookedUp;
|
|
2183
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2184
|
+
deepStrictEqual(requests, 0);
|
|
2185
|
+
} finally {
|
|
2186
|
+
dns.lookup = originalLookup;
|
|
2187
|
+
esm_default.hardReset();
|
|
2188
|
+
}
|
|
2189
|
+
});
|
|
2190
|
+
test("withDocumentLoaderTimeout() cleans up after each call", async () => {
|
|
2191
|
+
const signals = [];
|
|
2192
|
+
const loader = withDocumentLoaderTimeout((url, options) => {
|
|
2193
|
+
signals.push(options.signal);
|
|
2194
|
+
return Promise.resolve({
|
|
2195
|
+
contextUrl: null,
|
|
2196
|
+
document: {},
|
|
2197
|
+
documentUrl: url
|
|
2198
|
+
});
|
|
2199
|
+
}, 50);
|
|
2200
|
+
deepStrictEqual((await Promise.all([loader("https://example.com/a"), loader("https://example.com/b")])).map((r) => r.documentUrl), ["https://example.com/a", "https://example.com/b"]);
|
|
2201
|
+
ok(signals[0] !== signals[1]);
|
|
2202
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2203
|
+
ok(signals.every((signal) => !signal.aborted));
|
|
2204
|
+
const inner = () => Promise.reject(/* @__PURE__ */ new Error("unused"));
|
|
2205
|
+
ok(withDocumentLoaderTimeout(inner, null) === inner);
|
|
2206
|
+
});
|
|
2207
|
+
test("getRemoteDocument() keeps error bodies byte for byte", async () => {
|
|
2208
|
+
const bytes = new Uint8Array([
|
|
2209
|
+
239,
|
|
2210
|
+
187,
|
|
2211
|
+
191,
|
|
2212
|
+
78,
|
|
2213
|
+
111,
|
|
2214
|
+
255,
|
|
2215
|
+
254
|
|
2216
|
+
]);
|
|
2217
|
+
const url = "https://example.com/error";
|
|
2218
|
+
let error;
|
|
2219
|
+
await rejects(getRemoteDocument(url, new Response(bytes, { status: 404 }), () => Promise.reject(/* @__PURE__ */ new Error("unused"))), (e) => {
|
|
2220
|
+
error = e;
|
|
2221
|
+
return true;
|
|
2222
|
+
});
|
|
2223
|
+
ok(error instanceof FetchError);
|
|
2224
|
+
ok(error.response != null);
|
|
2225
|
+
deepStrictEqual(error.response.status, 404);
|
|
2226
|
+
deepStrictEqual(new Uint8Array(await error.response.arrayBuffer()), bytes);
|
|
2227
|
+
});
|
|
2228
|
+
test("getRemoteDocument() keeps metadata of bodiless or large errors", async () => {
|
|
2229
|
+
const url = "https://example.com/error";
|
|
2230
|
+
for (const response of [new Response(null, {
|
|
2231
|
+
status: 304,
|
|
2232
|
+
headers: { ETag: "\"a\"" }
|
|
2233
|
+
}), new Response(/* @__PURE__ */ new Uint8Array(1048577), {
|
|
2234
|
+
status: 500,
|
|
2235
|
+
headers: { ETag: "\"a\"" }
|
|
2236
|
+
})]) await rejects(getRemoteDocument(url, response, () => Promise.reject(/* @__PURE__ */ new Error("unused"))), (e) => {
|
|
2237
|
+
ok(e instanceof FetchError);
|
|
2238
|
+
ok(e.response != null);
|
|
2239
|
+
deepStrictEqual(e.response.status, response.status);
|
|
2240
|
+
deepStrictEqual(e.response.headers.get("ETag"), "\"a\"");
|
|
2241
|
+
deepStrictEqual(e.response.body, null);
|
|
2242
|
+
return true;
|
|
2243
|
+
});
|
|
2244
|
+
});
|
|
2245
|
+
test("getDocumentLoader() reports statuses that Response cannot hold", async () => {
|
|
2246
|
+
await withServer((_, response) => {
|
|
2247
|
+
response.writeHead(999);
|
|
2248
|
+
response.end("Request denied");
|
|
2249
|
+
}, async (baseUrl) => {
|
|
2250
|
+
const url = `${baseUrl}/denied`;
|
|
2251
|
+
const loader = getDocumentLoader({ allowPrivateAddress: true });
|
|
2252
|
+
let error;
|
|
2253
|
+
await rejects(loader(url), (e) => {
|
|
2254
|
+
error = e;
|
|
2255
|
+
return true;
|
|
2256
|
+
});
|
|
2257
|
+
ok(error instanceof FetchError, String(error));
|
|
2258
|
+
deepStrictEqual(error.response?.status, 999);
|
|
2259
|
+
deepStrictEqual(await error.response.text(), "Request denied");
|
|
2260
|
+
});
|
|
2261
|
+
});
|
|
2262
|
+
test("getDocumentLoader() times out a stalled body of such a status", async () => {
|
|
2263
|
+
await withServer((_, response) => {
|
|
2264
|
+
response.writeHead(999);
|
|
2265
|
+
response.write("Request");
|
|
2266
|
+
}, async (baseUrl) => {
|
|
2267
|
+
const url = `${baseUrl}/stalled-denied`;
|
|
2268
|
+
await rejects(getDocumentLoader({
|
|
2269
|
+
allowPrivateAddress: true,
|
|
2270
|
+
timeout: 200
|
|
2271
|
+
})(url), (e) => isTimeoutFetchError(e, url));
|
|
2272
|
+
});
|
|
2273
|
+
});
|
|
2011
2274
|
//#endregion
|
|
2012
2275
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_contexts = require("../contexts-DizzBjz4.cjs");
|
|
2
|
-
const require_url = require("../url-
|
|
3
|
-
const require_jsonld_cache = require("../jsonld-cache-
|
|
2
|
+
const require_url = require("../url-B8xyTwP-.cjs");
|
|
3
|
+
const require_jsonld_cache = require("../jsonld-cache-BQMn_ILF.cjs");
|
|
4
4
|
let node_assert_strict = require("node:assert/strict");
|
|
5
5
|
let node_test = require("node:test");
|
|
6
6
|
let _logtape_logtape = require("@logtape/logtape");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as preloadedContexts } from "../contexts-CIKsin4e.mjs";
|
|
2
|
-
import { a as formatIri, m as parseIri } from "../url-
|
|
3
|
-
import { n as createScopedContextLoader, o as registerDocumentLoaderWrapper, s as unwrapReleasedDocumentLoader } from "../jsonld-cache-
|
|
2
|
+
import { a as formatIri, m as parseIri } from "../url-DfS-cvwr.mjs";
|
|
3
|
+
import { n as createScopedContextLoader, o as registerDocumentLoaderWrapper, s as unwrapReleasedDocumentLoader } from "../jsonld-cache-DUmuWRwp.mjs";
|
|
4
4
|
import { deepStrictEqual, ok, throws } from "node:assert/strict";
|
|
5
5
|
import { test } from "node:test";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
|
|
2
|
-
const require_url = require("./url-
|
|
2
|
+
const require_url = require("./url-B8xyTwP-.cjs");
|
|
3
3
|
let jsonld_dist_jsonld_esm_js = require("jsonld/dist/jsonld.esm.js");
|
|
4
4
|
jsonld_dist_jsonld_esm_js = require_rolldown_runtime.__toESM(jsonld_dist_jsonld_esm_js, 1);
|
|
5
5
|
//#region src/jsonld.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as formatIri, c as haveSameFe34Origin, l as haveSameIriOrigin } from "./url-
|
|
1
|
+
import { a as formatIri, c as haveSameFe34Origin, l as haveSameIriOrigin } from "./url-DfS-cvwr.mjs";
|
|
2
2
|
import jsonld from "jsonld/dist/jsonld.esm.js";
|
|
3
3
|
//#region src/jsonld.ts
|
|
4
4
|
var jsonld_default = jsonld;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_url = require("./url-
|
|
2
|
-
const require_jsonld_cache = require("./jsonld-cache-
|
|
1
|
+
const require_url = require("./url-B8xyTwP-.cjs");
|
|
2
|
+
const require_jsonld_cache = require("./jsonld-cache-BQMn_ILF.cjs");
|
|
3
3
|
let node_test = require("node:test");
|
|
4
4
|
let node_assert = require("node:assert");
|
|
5
5
|
//#region src/jsonld-cache.test.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { m as parseIri } from "./url-
|
|
2
|
-
import { a as normalizeJsonLdIris, c as jsonld_default, i as isTrustedIriOrigin, r as getJsonLdContext, t as compactJsonLdCache } from "./jsonld-cache-
|
|
1
|
+
import { m as parseIri } from "./url-DfS-cvwr.mjs";
|
|
2
|
+
import { a as normalizeJsonLdIris, c as jsonld_default, i as isTrustedIriOrigin, r as getJsonLdContext, t as compactJsonLdCache } from "./jsonld-cache-DUmuWRwp.mjs";
|
|
3
3
|
import { test } from "node:test";
|
|
4
4
|
import { deepStrictEqual, ok, strictEqual } from "node:assert";
|
|
5
5
|
//#region src/jsonld-cache.test.ts
|
|
@@ -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.0-dev.
|
|
6
|
+
var version = "2.4.0-dev.2193+402149b5";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/request.ts
|
|
9
9
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-C5_3S-un.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-
|
|
1
|
+
import { n as createActivityPubRequest, o as version, r as getUserAgent } from "./request-IIntZ5kj.mjs";
|
|
2
2
|
import { test } from "node:test";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { deepStrictEqual } from "node:assert";
|
|
@@ -226,10 +226,14 @@ function isGatewayUrl(url) {
|
|
|
226
226
|
}
|
|
227
227
|
/**
|
|
228
228
|
* Parses and validates an FEP-ef61 gateway base URI.
|
|
229
|
+
* @throws {TypeError} If the URI is malformed, or is not an HTTP(S) base URI
|
|
230
|
+
* with no credentials, path, query, or fragment. In the
|
|
231
|
+
* latter case, the message starts with
|
|
232
|
+
* `Invalid FEP-ef61 gateway:`.
|
|
229
233
|
*/
|
|
230
234
|
function parseGatewayUrl(url) {
|
|
231
235
|
const parsed = parseIri(url);
|
|
232
|
-
if (!isGatewayUrl(parsed)) throw new TypeError(
|
|
236
|
+
if (!isGatewayUrl(parsed)) throw new TypeError(`Invalid FEP-ef61 gateway: ${url}. FEP-ef61 gateways must be HTTP(S) base URIs with no credentials, path, query, or fragment.`);
|
|
233
237
|
return parsed;
|
|
234
238
|
}
|
|
235
239
|
const COMPATIBLE_ID_PATH_PREFIX = "/.well-known/apgateway/";
|