@fedify/vocab-runtime 2.4.0-dev.2122 → 2.4.0-dev.2129
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-Dr8wEkif.d.cts → docloader-oRpq1nQ8.d.cts} +8 -1
- package/dist/{docloader-Dr8wEkif.d.ts → docloader-oRpq1nQ8.d.ts} +8 -1
- package/dist/internal/jsonld-cache.cjs +50 -0
- package/dist/internal/jsonld-cache.d.cts +28 -2
- package/dist/internal/jsonld-cache.d.ts +28 -2
- package/dist/internal/jsonld-cache.js +48 -1
- package/dist/internal/portable-dereference.cjs +28 -12
- package/dist/internal/portable-dereference.d.cts +12 -4
- package/dist/internal/portable-dereference.d.ts +12 -4
- package/dist/internal/portable-dereference.js +28 -12
- package/dist/mod.cjs +15 -9
- package/dist/mod.d.cts +8 -2
- package/dist/mod.d.ts +8 -2
- package/dist/mod.js +15 -9
- package/dist/{portable-comBI05Y.d.cts → portable-Drfl02vZ.d.cts} +1 -1
- package/dist/{portable-DH3947GK.d.ts → portable-rwhiyMvY.d.ts} +1 -1
- package/dist/tests/{body-tLaZa-9t.cjs → body-B98QT2cn.cjs} +1 -1
- package/dist/tests/{body-DkyJy_0c.mjs → body-CrD70FCs.mjs} +1 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/decimal.test.cjs +1 -1
- package/dist/tests/decimal.test.mjs +1 -1
- package/dist/tests/{docloader-DFs6K8ol.cjs → docloader-BVoNdutR.cjs} +16 -10
- package/dist/tests/{docloader-CSfFzxWm.mjs → docloader-CBscxl9w.mjs} +16 -10
- package/dist/tests/docloader.test.cjs +49 -2
- package/dist/tests/docloader.test.mjs +49 -2
- package/dist/tests/internal/portable-dereference.test.cjs +67 -6
- package/dist/tests/internal/portable-dereference.test.mjs +67 -6
- package/dist/tests/jsonld-cache-9jap4yM0.cjs +373 -0
- package/dist/tests/jsonld-cache-DnZS0z1G.mjs +324 -0
- package/dist/tests/jsonld-cache.test.cjs +20 -291
- package/dist/tests/jsonld-cache.test.mjs +2 -273
- package/dist/tests/{request-BLe2W5ua.cjs → request-BMNsRCJF.cjs} +1 -1
- package/dist/tests/{request-CmMy4YVK.mjs → request-CRVyLEa-.mjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/package.json +1 -1
- package/src/docloader.test.ts +73 -0
- package/src/docloader.ts +46 -17
- package/src/internal/jsonld-cache.ts +60 -0
- package/src/internal/portable-dereference.test.ts +71 -0
- package/src/internal/portable-dereference.ts +37 -24
- package/src/preprocessor.ts +7 -0
- package/dist/tests/jsonld-CmDhHNTx.cjs +0 -12
- package/dist/tests/jsonld-DweIJ07b.mjs +0 -5
package/dist/mod.cjs
CHANGED
|
@@ -16,7 +16,7 @@ let _multiformats_base_x = require("@multiformats/base-x");
|
|
|
16
16
|
_multiformats_base_x = require_rolldown_runtime.__toESM(_multiformats_base_x, 1);
|
|
17
17
|
//#region deno.json
|
|
18
18
|
var name = "@fedify/vocab-runtime";
|
|
19
|
-
var version = "2.4.0-dev.
|
|
19
|
+
var version = "2.4.0-dev.2129+c0ddb433";
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/request.ts
|
|
22
22
|
/**
|
|
@@ -369,15 +369,21 @@ function createResponseMetadata(response) {
|
|
|
369
369
|
* @param url The URL of the document to load.
|
|
370
370
|
* @param response The response to get the document from.
|
|
371
371
|
* @param fetch The function to fetch the document.
|
|
372
|
+
* @param options The options for loading the document.
|
|
372
373
|
* @returns The loaded remote document.
|
|
373
374
|
* @throws {FetchError} If the response is not OK.
|
|
374
375
|
* @internal
|
|
375
376
|
*/
|
|
376
|
-
async function getRemoteDocument(url, response, fetch) {
|
|
377
|
+
async function getRemoteDocument(url, response, fetch, options) {
|
|
377
378
|
const documentUrl = response.url === "" ? url : response.url;
|
|
378
379
|
const docUrl = new URL(documentUrl);
|
|
379
380
|
if (!response.ok) {
|
|
380
|
-
logger.
|
|
381
|
+
if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
|
|
382
|
+
status: response.status,
|
|
383
|
+
url: documentUrl,
|
|
384
|
+
headers: Object.fromEntries(response.headers.entries())
|
|
385
|
+
});
|
|
386
|
+
else logger.error("Failed to fetch document: {status} {url} {headers}", {
|
|
381
387
|
status: response.status,
|
|
382
388
|
url: documentUrl,
|
|
383
389
|
headers: Object.fromEntries(response.headers.entries())
|
|
@@ -411,7 +417,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
411
417
|
alternateUrl: altUri.href,
|
|
412
418
|
url: documentUrl
|
|
413
419
|
});
|
|
414
|
-
return await fetch(altUri.href);
|
|
420
|
+
return await fetch(altUri.href, options);
|
|
415
421
|
}
|
|
416
422
|
}
|
|
417
423
|
}
|
|
@@ -447,7 +453,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
447
453
|
alternateUrl: attribs.href,
|
|
448
454
|
url: documentUrl
|
|
449
455
|
});
|
|
450
|
-
return await fetch(new URL(attribs.href, docUrl).href);
|
|
456
|
+
return await fetch(new URL(attribs.href, docUrl).href, options);
|
|
451
457
|
}
|
|
452
458
|
}
|
|
453
459
|
try {
|
|
@@ -505,7 +511,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
505
511
|
if (!allowPrivateAddress) try {
|
|
506
512
|
await require_url.validatePublicUrl(currentUrl);
|
|
507
513
|
} catch (error) {
|
|
508
|
-
if (error instanceof require_url.UrlError) logger
|
|
514
|
+
if (error instanceof require_url.UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
509
515
|
url: currentUrl,
|
|
510
516
|
error
|
|
511
517
|
});
|
|
@@ -526,7 +532,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
526
532
|
span.setAttribute("http.response.status_code", response.status);
|
|
527
533
|
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
528
534
|
if (redirected >= maximumRedirection) {
|
|
529
|
-
logger
|
|
535
|
+
logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
|
|
530
536
|
redirections: redirected + 1,
|
|
531
537
|
url: currentUrl
|
|
532
538
|
});
|
|
@@ -535,7 +541,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
535
541
|
const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
|
|
536
542
|
span.setAttribute("http.redirect.url", redirectUrl);
|
|
537
543
|
if (visited.has(redirectUrl)) {
|
|
538
|
-
logger
|
|
544
|
+
logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
|
|
539
545
|
url: currentUrl,
|
|
540
546
|
redirectUrl
|
|
541
547
|
});
|
|
@@ -543,7 +549,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
543
549
|
}
|
|
544
550
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
545
551
|
}
|
|
546
|
-
const result = await getRemoteDocument(currentUrl, response, load);
|
|
552
|
+
const result = await getRemoteDocument(currentUrl, response, load, options);
|
|
547
553
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
548
554
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
549
555
|
return result;
|
package/dist/mod.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-
|
|
3
|
-
import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-
|
|
2
|
+
import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-oRpq1nQ8.cjs";
|
|
3
|
+
import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-Drfl02vZ.cjs";
|
|
4
4
|
import { TracerProvider } from "@opentelemetry/api";
|
|
5
5
|
|
|
6
6
|
//#region src/contexts.d.ts
|
|
@@ -384,6 +384,12 @@ interface PropertyPreprocessorContext {
|
|
|
384
384
|
contextLoader?: DocumentLoader;
|
|
385
385
|
/** OpenTelemetry tracer provider for instrumentation. */
|
|
386
386
|
tracerProvider?: TracerProvider;
|
|
387
|
+
/**
|
|
388
|
+
* The default FEP-ef61 portable object verifier that objects returned by
|
|
389
|
+
* the preprocessor should use for their property accessors.
|
|
390
|
+
* @since 2.4.0
|
|
391
|
+
*/
|
|
392
|
+
verifyPortableObject?: PortableObjectVerifier;
|
|
387
393
|
/** Base URL for resolving relative references. */
|
|
388
394
|
baseUrl?: URL;
|
|
389
395
|
}
|
package/dist/mod.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-
|
|
3
|
-
import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-
|
|
2
|
+
import { a as DocumentLoaderOptions, c as getDocumentLoader, d as FetchError, f as GetUserAgentOptions, h as logRequest, i as DocumentLoaderFactoryOptions, l as getRemoteDocument, m as getUserAgent, n as DocumentLoader, o as GetDocumentLoaderOptions, p as createActivityPubRequest, r as DocumentLoaderFactory, s as RemoteDocument, t as AuthenticatedDocumentLoaderFactory, u as CreateRequestOptions } from "./docloader-oRpq1nQ8.js";
|
|
3
|
+
import { i as PortableObjectVerifierOptions, n as PortableObjectVerification, r as PortableObjectVerifier, t as PortableObjectReferrer } from "./portable-rwhiyMvY.js";
|
|
4
4
|
import { TracerProvider } from "@opentelemetry/api";
|
|
5
5
|
//#region src/contexts.d.ts
|
|
6
6
|
declare const preloadedContexts: Record<string, unknown>;
|
|
@@ -383,6 +383,12 @@ interface PropertyPreprocessorContext {
|
|
|
383
383
|
contextLoader?: DocumentLoader;
|
|
384
384
|
/** OpenTelemetry tracer provider for instrumentation. */
|
|
385
385
|
tracerProvider?: TracerProvider;
|
|
386
|
+
/**
|
|
387
|
+
* The default FEP-ef61 portable object verifier that objects returned by
|
|
388
|
+
* the preprocessor should use for their property accessors.
|
|
389
|
+
* @since 2.4.0
|
|
390
|
+
*/
|
|
391
|
+
verifyPortableObject?: PortableObjectVerifier;
|
|
386
392
|
/** Base URL for resolving relative references. */
|
|
387
393
|
baseUrl?: URL;
|
|
388
394
|
}
|
package/dist/mod.js
CHANGED
|
@@ -12,7 +12,7 @@ import { PublicKeyInfo } from "pkijs";
|
|
|
12
12
|
import baseX from "@multiformats/base-x";
|
|
13
13
|
//#region deno.json
|
|
14
14
|
var name = "@fedify/vocab-runtime";
|
|
15
|
-
var version = "2.4.0-dev.
|
|
15
|
+
var version = "2.4.0-dev.2129+c0ddb433";
|
|
16
16
|
//#endregion
|
|
17
17
|
//#region src/request.ts
|
|
18
18
|
/**
|
|
@@ -365,15 +365,21 @@ function createResponseMetadata(response) {
|
|
|
365
365
|
* @param url The URL of the document to load.
|
|
366
366
|
* @param response The response to get the document from.
|
|
367
367
|
* @param fetch The function to fetch the document.
|
|
368
|
+
* @param options The options for loading the document.
|
|
368
369
|
* @returns The loaded remote document.
|
|
369
370
|
* @throws {FetchError} If the response is not OK.
|
|
370
371
|
* @internal
|
|
371
372
|
*/
|
|
372
|
-
async function getRemoteDocument(url, response, fetch) {
|
|
373
|
+
async function getRemoteDocument(url, response, fetch, options) {
|
|
373
374
|
const documentUrl = response.url === "" ? url : response.url;
|
|
374
375
|
const docUrl = new URL(documentUrl);
|
|
375
376
|
if (!response.ok) {
|
|
376
|
-
logger.
|
|
377
|
+
if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
|
|
378
|
+
status: response.status,
|
|
379
|
+
url: documentUrl,
|
|
380
|
+
headers: Object.fromEntries(response.headers.entries())
|
|
381
|
+
});
|
|
382
|
+
else logger.error("Failed to fetch document: {status} {url} {headers}", {
|
|
377
383
|
status: response.status,
|
|
378
384
|
url: documentUrl,
|
|
379
385
|
headers: Object.fromEntries(response.headers.entries())
|
|
@@ -407,7 +413,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
407
413
|
alternateUrl: altUri.href,
|
|
408
414
|
url: documentUrl
|
|
409
415
|
});
|
|
410
|
-
return await fetch(altUri.href);
|
|
416
|
+
return await fetch(altUri.href, options);
|
|
411
417
|
}
|
|
412
418
|
}
|
|
413
419
|
}
|
|
@@ -443,7 +449,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
443
449
|
alternateUrl: attribs.href,
|
|
444
450
|
url: documentUrl
|
|
445
451
|
});
|
|
446
|
-
return await fetch(new URL(attribs.href, docUrl).href);
|
|
452
|
+
return await fetch(new URL(attribs.href, docUrl).href, options);
|
|
447
453
|
}
|
|
448
454
|
}
|
|
449
455
|
try {
|
|
@@ -501,7 +507,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
501
507
|
if (!allowPrivateAddress) try {
|
|
502
508
|
await validatePublicUrl(currentUrl);
|
|
503
509
|
} catch (error) {
|
|
504
|
-
if (error instanceof UrlError) logger
|
|
510
|
+
if (error instanceof UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
505
511
|
url: currentUrl,
|
|
506
512
|
error
|
|
507
513
|
});
|
|
@@ -522,7 +528,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
522
528
|
span.setAttribute("http.response.status_code", response.status);
|
|
523
529
|
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
524
530
|
if (redirected >= maximumRedirection) {
|
|
525
|
-
logger
|
|
531
|
+
logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
|
|
526
532
|
redirections: redirected + 1,
|
|
527
533
|
url: currentUrl
|
|
528
534
|
});
|
|
@@ -531,7 +537,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
531
537
|
const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
|
|
532
538
|
span.setAttribute("http.redirect.url", redirectUrl);
|
|
533
539
|
if (visited.has(redirectUrl)) {
|
|
534
|
-
logger
|
|
540
|
+
logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
|
|
535
541
|
url: currentUrl,
|
|
536
542
|
redirectUrl
|
|
537
543
|
});
|
|
@@ -539,7 +545,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
539
545
|
}
|
|
540
546
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
541
547
|
}
|
|
542
|
-
const result = await getRemoteDocument(currentUrl, response, load);
|
|
548
|
+
const result = await getRemoteDocument(currentUrl, response, load, options);
|
|
543
549
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
544
550
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
545
551
|
return result;
|
package/dist/tests/body.test.cjs
CHANGED
package/dist/tests/body.test.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as readBoundedText, t as BodyTooLargeError } from "./body-
|
|
1
|
+
import { r as readBoundedText, t as BodyTooLargeError } from "./body-CrD70FCs.mjs";
|
|
2
2
|
import { deepStrictEqual, ok, rejects } from "node:assert/strict";
|
|
3
3
|
import { test } from "node:test";
|
|
4
4
|
import { gunzipSync, gzipSync } from "node:zlib";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_request = require("./request-
|
|
2
|
-
const require_body = require("./body-
|
|
1
|
+
const require_request = require("./request-BMNsRCJF.cjs");
|
|
2
|
+
const require_body = require("./body-B98QT2cn.cjs");
|
|
3
3
|
const require_contexts = require("./contexts-Ch3v2Cgu.cjs");
|
|
4
4
|
const require_link = require("./link-DlKm8bEr.cjs");
|
|
5
5
|
const require_url = require("./url-BqlldzT8.cjs");
|
|
@@ -25,15 +25,21 @@ function createResponseMetadata(response) {
|
|
|
25
25
|
* @param url The URL of the document to load.
|
|
26
26
|
* @param response The response to get the document from.
|
|
27
27
|
* @param fetch The function to fetch the document.
|
|
28
|
+
* @param options The options for loading the document.
|
|
28
29
|
* @returns The loaded remote document.
|
|
29
30
|
* @throws {FetchError} If the response is not OK.
|
|
30
31
|
* @internal
|
|
31
32
|
*/
|
|
32
|
-
async function getRemoteDocument(url, response, fetch) {
|
|
33
|
+
async function getRemoteDocument(url, response, fetch, options) {
|
|
33
34
|
const documentUrl = response.url === "" ? url : response.url;
|
|
34
35
|
const docUrl = new URL(documentUrl);
|
|
35
36
|
if (!response.ok) {
|
|
36
|
-
logger.
|
|
37
|
+
if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
|
|
38
|
+
status: response.status,
|
|
39
|
+
url: documentUrl,
|
|
40
|
+
headers: Object.fromEntries(response.headers.entries())
|
|
41
|
+
});
|
|
42
|
+
else logger.error("Failed to fetch document: {status} {url} {headers}", {
|
|
37
43
|
status: response.status,
|
|
38
44
|
url: documentUrl,
|
|
39
45
|
headers: Object.fromEntries(response.headers.entries())
|
|
@@ -67,7 +73,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
67
73
|
alternateUrl: altUri.href,
|
|
68
74
|
url: documentUrl
|
|
69
75
|
});
|
|
70
|
-
return await fetch(altUri.href);
|
|
76
|
+
return await fetch(altUri.href, options);
|
|
71
77
|
}
|
|
72
78
|
}
|
|
73
79
|
}
|
|
@@ -103,7 +109,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
103
109
|
alternateUrl: attribs.href,
|
|
104
110
|
url: documentUrl
|
|
105
111
|
});
|
|
106
|
-
return await fetch(new URL(attribs.href, docUrl).href);
|
|
112
|
+
return await fetch(new URL(attribs.href, docUrl).href, options);
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
try {
|
|
@@ -161,7 +167,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
161
167
|
if (!allowPrivateAddress) try {
|
|
162
168
|
await require_url.validatePublicUrl(currentUrl);
|
|
163
169
|
} catch (error) {
|
|
164
|
-
if (error instanceof require_url.UrlError) logger
|
|
170
|
+
if (error instanceof require_url.UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
165
171
|
url: currentUrl,
|
|
166
172
|
error
|
|
167
173
|
});
|
|
@@ -182,7 +188,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
182
188
|
span.setAttribute("http.response.status_code", response.status);
|
|
183
189
|
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
184
190
|
if (redirected >= maximumRedirection) {
|
|
185
|
-
logger
|
|
191
|
+
logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
|
|
186
192
|
redirections: redirected + 1,
|
|
187
193
|
url: currentUrl
|
|
188
194
|
});
|
|
@@ -191,7 +197,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
191
197
|
const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
|
|
192
198
|
span.setAttribute("http.redirect.url", redirectUrl);
|
|
193
199
|
if (visited.has(redirectUrl)) {
|
|
194
|
-
logger
|
|
200
|
+
logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
|
|
195
201
|
url: currentUrl,
|
|
196
202
|
redirectUrl
|
|
197
203
|
});
|
|
@@ -199,7 +205,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
199
205
|
}
|
|
200
206
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
201
207
|
}
|
|
202
|
-
const result = await getRemoteDocument(currentUrl, response, load);
|
|
208
|
+
const result = await getRemoteDocument(currentUrl, response, load, options);
|
|
203
209
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
204
210
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
205
211
|
return result;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-
|
|
2
|
-
import { n as MAX_BODY_SIZE, r as readBoundedText, t as BodyTooLargeError } from "./body-
|
|
1
|
+
import { a as name, i as logRequest, n as createActivityPubRequest, o as version, t as FetchError } from "./request-CRVyLEa-.mjs";
|
|
2
|
+
import { n as MAX_BODY_SIZE, r as readBoundedText, t as BodyTooLargeError } from "./body-CrD70FCs.mjs";
|
|
3
3
|
import { t as preloadedContexts } from "./contexts-BBX_qhBL.mjs";
|
|
4
4
|
import { t as HttpHeaderLink } from "./link-Cevmc87v.mjs";
|
|
5
5
|
import { t as UrlError, v as validatePublicUrl } from "./url-DgJM9WJn.mjs";
|
|
@@ -25,15 +25,21 @@ function createResponseMetadata(response) {
|
|
|
25
25
|
* @param url The URL of the document to load.
|
|
26
26
|
* @param response The response to get the document from.
|
|
27
27
|
* @param fetch The function to fetch the document.
|
|
28
|
+
* @param options The options for loading the document.
|
|
28
29
|
* @returns The loaded remote document.
|
|
29
30
|
* @throws {FetchError} If the response is not OK.
|
|
30
31
|
* @internal
|
|
31
32
|
*/
|
|
32
|
-
async function getRemoteDocument(url, response, fetch) {
|
|
33
|
+
async function getRemoteDocument(url, response, fetch, options) {
|
|
33
34
|
const documentUrl = response.url === "" ? url : response.url;
|
|
34
35
|
const docUrl = new URL(documentUrl);
|
|
35
36
|
if (!response.ok) {
|
|
36
|
-
logger.
|
|
37
|
+
if (options?.suppressError) logger.warn("Failed to fetch document: {status} {url} {headers}", {
|
|
38
|
+
status: response.status,
|
|
39
|
+
url: documentUrl,
|
|
40
|
+
headers: Object.fromEntries(response.headers.entries())
|
|
41
|
+
});
|
|
42
|
+
else logger.error("Failed to fetch document: {status} {url} {headers}", {
|
|
37
43
|
status: response.status,
|
|
38
44
|
url: documentUrl,
|
|
39
45
|
headers: Object.fromEntries(response.headers.entries())
|
|
@@ -67,7 +73,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
67
73
|
alternateUrl: altUri.href,
|
|
68
74
|
url: documentUrl
|
|
69
75
|
});
|
|
70
|
-
return await fetch(altUri.href);
|
|
76
|
+
return await fetch(altUri.href, options);
|
|
71
77
|
}
|
|
72
78
|
}
|
|
73
79
|
}
|
|
@@ -103,7 +109,7 @@ async function getRemoteDocument(url, response, fetch) {
|
|
|
103
109
|
alternateUrl: attribs.href,
|
|
104
110
|
url: documentUrl
|
|
105
111
|
});
|
|
106
|
-
return await fetch(new URL(attribs.href, docUrl).href);
|
|
112
|
+
return await fetch(new URL(attribs.href, docUrl).href, options);
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
try {
|
|
@@ -161,7 +167,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
161
167
|
if (!allowPrivateAddress) try {
|
|
162
168
|
await validatePublicUrl(currentUrl);
|
|
163
169
|
} catch (error) {
|
|
164
|
-
if (error instanceof UrlError) logger
|
|
170
|
+
if (error instanceof UrlError) logger[options?.suppressError ? "warn" : "error"]("Disallowed private URL: {url}", {
|
|
165
171
|
url: currentUrl,
|
|
166
172
|
error
|
|
167
173
|
});
|
|
@@ -182,7 +188,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
182
188
|
span.setAttribute("http.response.status_code", response.status);
|
|
183
189
|
if (response.status >= 300 && response.status < 400 && response.headers.has("Location")) {
|
|
184
190
|
if (redirected >= maximumRedirection) {
|
|
185
|
-
logger
|
|
191
|
+
logger[options?.suppressError ? "warn" : "error"]("Too many redirections ({redirections}) while fetching document.", {
|
|
186
192
|
redirections: redirected + 1,
|
|
187
193
|
url: currentUrl
|
|
188
194
|
});
|
|
@@ -191,7 +197,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
191
197
|
const redirectUrl = new URL(response.headers.get("Location"), response.url === "" ? currentUrl : response.url).href;
|
|
192
198
|
span.setAttribute("http.redirect.url", redirectUrl);
|
|
193
199
|
if (visited.has(redirectUrl)) {
|
|
194
|
-
logger
|
|
200
|
+
logger[options?.suppressError ? "warn" : "error"]("Detected a redirect loop while fetching document: {url} -> {redirectUrl}", {
|
|
195
201
|
url: currentUrl,
|
|
196
202
|
redirectUrl
|
|
197
203
|
});
|
|
@@ -199,7 +205,7 @@ function getDocumentLoader({ allowPrivateAddress, maxRedirection, skipPreloadedC
|
|
|
199
205
|
}
|
|
200
206
|
return await load(redirectUrl, options, redirected + 1, visited);
|
|
201
207
|
}
|
|
202
|
-
const result = await getRemoteDocument(currentUrl, response, load);
|
|
208
|
+
const result = await getRemoteDocument(currentUrl, response, load, options);
|
|
203
209
|
span.setAttribute("docloader.document_url", result.documentUrl);
|
|
204
210
|
if (result.contextUrl != null) span.setAttribute("docloader.context_url", result.contextUrl);
|
|
205
211
|
return result;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-emK7D4bc.cjs");
|
|
2
|
-
const require_request = require("./request-
|
|
2
|
+
const require_request = require("./request-BMNsRCJF.cjs");
|
|
3
3
|
const require_contexts = require("./contexts-Ch3v2Cgu.cjs");
|
|
4
4
|
const require_url = require("./url-BqlldzT8.cjs");
|
|
5
|
-
const require_docloader = require("./docloader-
|
|
5
|
+
const require_docloader = require("./docloader-BVoNdutR.cjs");
|
|
6
6
|
let node_test = require("node:test");
|
|
7
7
|
let node_zlib = require("node:zlib");
|
|
8
|
+
let _logtape_logtape = require("@logtape/logtape");
|
|
8
9
|
let node_assert = require("node:assert");
|
|
9
10
|
let node_http = require("node:http");
|
|
10
11
|
//#region ../../node_modules/.pnpm/glob-to-regexp@0.4.1/node_modules/glob-to-regexp/index.js
|
|
@@ -1216,6 +1217,52 @@ var esm_default = new class FetchMock {
|
|
|
1216
1217
|
}({ ...defaultFetchMockConfig });
|
|
1217
1218
|
//#endregion
|
|
1218
1219
|
//#region src/docloader.test.ts
|
|
1220
|
+
(0, node_test.test)("getRemoteDocument() forwards options to alternate documents", async () => {
|
|
1221
|
+
const records = [];
|
|
1222
|
+
await (0, _logtape_logtape.reset)();
|
|
1223
|
+
await (0, _logtape_logtape.configure)({
|
|
1224
|
+
sinks: { capture: (record) => records.push(record) },
|
|
1225
|
+
loggers: [{
|
|
1226
|
+
category: ["fedify"],
|
|
1227
|
+
lowestLevel: "debug",
|
|
1228
|
+
sinks: ["capture"]
|
|
1229
|
+
}]
|
|
1230
|
+
});
|
|
1231
|
+
try {
|
|
1232
|
+
for (const linkHeader of [true, false]) for (const suppressError of [
|
|
1233
|
+
true,
|
|
1234
|
+
false,
|
|
1235
|
+
void 0
|
|
1236
|
+
]) {
|
|
1237
|
+
records.length = 0;
|
|
1238
|
+
const url = "https://example.com/alternate-source";
|
|
1239
|
+
const alternateUrl = "https://example.com/missing-alternate";
|
|
1240
|
+
const options = {
|
|
1241
|
+
suppressError,
|
|
1242
|
+
signal: new AbortController().signal
|
|
1243
|
+
};
|
|
1244
|
+
const response = new Response(`<link rel="alternate" type="application/activity+json" href="${alternateUrl}">`, { headers: {
|
|
1245
|
+
"Content-Type": "text/html",
|
|
1246
|
+
...linkHeader ? { Link: `<${alternateUrl}>; rel="alternate"; type="application/activity+json"` } : {}
|
|
1247
|
+
} });
|
|
1248
|
+
let alternateRequests = 0;
|
|
1249
|
+
await (0, node_assert.rejects)(() => require_docloader.getRemoteDocument(url, response, async (requestedUrl, forwarded) => {
|
|
1250
|
+
alternateRequests++;
|
|
1251
|
+
(0, node_assert.deepStrictEqual)(requestedUrl, alternateUrl);
|
|
1252
|
+
(0, node_assert.deepStrictEqual)(forwarded, options);
|
|
1253
|
+
return await require_docloader.getRemoteDocument(requestedUrl, new Response(null, { status: 404 }), () => {
|
|
1254
|
+
throw new Error("Unexpected additional alternate");
|
|
1255
|
+
}, forwarded);
|
|
1256
|
+
}, options), require_request.FetchError);
|
|
1257
|
+
(0, node_assert.deepStrictEqual)(alternateRequests, 1);
|
|
1258
|
+
const failures = records.filter((record) => record.rawMessage === "Failed to fetch document: {status} {url} {headers}");
|
|
1259
|
+
(0, node_assert.deepStrictEqual)(failures.length, 1);
|
|
1260
|
+
(0, node_assert.deepStrictEqual)(failures[0].level, suppressError ? "warning" : "error");
|
|
1261
|
+
}
|
|
1262
|
+
} finally {
|
|
1263
|
+
await (0, _logtape_logtape.reset)();
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1219
1266
|
(0, node_test.test)("new FetchError()", () => {
|
|
1220
1267
|
const e = new require_request.FetchError("https://example.com/", "An error message.");
|
|
1221
1268
|
(0, node_assert.deepStrictEqual)(e.name, "FetchError");
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { t as FetchError } from "./request-
|
|
1
|
+
import { t as FetchError } from "./request-CRVyLEa-.mjs";
|
|
2
2
|
import { n as cid_v1_default, t as preloadedContexts } from "./contexts-BBX_qhBL.mjs";
|
|
3
3
|
import { t as UrlError } from "./url-DgJM9WJn.mjs";
|
|
4
|
-
import { n as getRemoteDocument, t as getDocumentLoader } from "./docloader-
|
|
4
|
+
import { n as getRemoteDocument, t as getDocumentLoader } from "./docloader-CBscxl9w.mjs";
|
|
5
5
|
import { test } from "node:test";
|
|
6
6
|
import { gzipSync } from "node:zlib";
|
|
7
|
+
import { configure, reset } from "@logtape/logtape";
|
|
7
8
|
import { deepStrictEqual, ok, rejects } from "node:assert";
|
|
8
9
|
import { createServer } from "node:http";
|
|
9
10
|
//#region \0rolldown/runtime.js
|
|
@@ -1235,6 +1236,52 @@ var esm_default = new class FetchMock {
|
|
|
1235
1236
|
}({ ...defaultFetchMockConfig });
|
|
1236
1237
|
//#endregion
|
|
1237
1238
|
//#region src/docloader.test.ts
|
|
1239
|
+
test("getRemoteDocument() forwards options to alternate documents", async () => {
|
|
1240
|
+
const records = [];
|
|
1241
|
+
await reset();
|
|
1242
|
+
await configure({
|
|
1243
|
+
sinks: { capture: (record) => records.push(record) },
|
|
1244
|
+
loggers: [{
|
|
1245
|
+
category: ["fedify"],
|
|
1246
|
+
lowestLevel: "debug",
|
|
1247
|
+
sinks: ["capture"]
|
|
1248
|
+
}]
|
|
1249
|
+
});
|
|
1250
|
+
try {
|
|
1251
|
+
for (const linkHeader of [true, false]) for (const suppressError of [
|
|
1252
|
+
true,
|
|
1253
|
+
false,
|
|
1254
|
+
void 0
|
|
1255
|
+
]) {
|
|
1256
|
+
records.length = 0;
|
|
1257
|
+
const url = "https://example.com/alternate-source";
|
|
1258
|
+
const alternateUrl = "https://example.com/missing-alternate";
|
|
1259
|
+
const options = {
|
|
1260
|
+
suppressError,
|
|
1261
|
+
signal: new AbortController().signal
|
|
1262
|
+
};
|
|
1263
|
+
const response = new Response(`<link rel="alternate" type="application/activity+json" href="${alternateUrl}">`, { headers: {
|
|
1264
|
+
"Content-Type": "text/html",
|
|
1265
|
+
...linkHeader ? { Link: `<${alternateUrl}>; rel="alternate"; type="application/activity+json"` } : {}
|
|
1266
|
+
} });
|
|
1267
|
+
let alternateRequests = 0;
|
|
1268
|
+
await rejects(() => getRemoteDocument(url, response, async (requestedUrl, forwarded) => {
|
|
1269
|
+
alternateRequests++;
|
|
1270
|
+
deepStrictEqual(requestedUrl, alternateUrl);
|
|
1271
|
+
deepStrictEqual(forwarded, options);
|
|
1272
|
+
return await getRemoteDocument(requestedUrl, new Response(null, { status: 404 }), () => {
|
|
1273
|
+
throw new Error("Unexpected additional alternate");
|
|
1274
|
+
}, forwarded);
|
|
1275
|
+
}, options), FetchError);
|
|
1276
|
+
deepStrictEqual(alternateRequests, 1);
|
|
1277
|
+
const failures = records.filter((record) => record.rawMessage === "Failed to fetch document: {status} {url} {headers}");
|
|
1278
|
+
deepStrictEqual(failures.length, 1);
|
|
1279
|
+
deepStrictEqual(failures[0].level, suppressError ? "warning" : "error");
|
|
1280
|
+
}
|
|
1281
|
+
} finally {
|
|
1282
|
+
await reset();
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1238
1285
|
test("new FetchError()", () => {
|
|
1239
1286
|
const e = new FetchError("https://example.com/", "An error message.");
|
|
1240
1287
|
deepStrictEqual(e.name, "FetchError");
|