@fedify/fedify 2.4.0-dev.2219 → 2.4.0-dev.2233
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/dist/{builder-C5rYBZ16.mjs → builder-BmoDmjWk.mjs} +2 -2
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-D0xY7MBs.mjs → compound-proof-Pn8766TV.mjs} +2 -2
- package/dist/{deno-Dj1TFhf4.mjs → deno-62DcBMwc.mjs} +1 -1
- package/dist/{docloader-CzyJe90o.mjs → docloader-Be9TaKa_.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +3 -3
- package/dist/federation/handler-compound-proof.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +73 -6
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +7 -7
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +248 -6
- package/dist/federation/portable-actor.test.mjs +3 -3
- package/dist/federation/portable-chain.test.mjs +3 -3
- package/dist/federation/portable-collection.test.mjs +4 -4
- package/dist/federation/portable-delivery.test.mjs +2 -2
- package/dist/federation/portable-gateway-keys.test.mjs +4 -4
- package/dist/federation/portable-inbox.test.mjs +4 -4
- package/dist/federation/portable-parse-uri.test.mjs +1 -1
- package/dist/federation/portable-route-activity.test.mjs +2 -2
- package/dist/federation/portable.test.mjs +80 -3
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/tasks/enqueue.test.mjs +1 -1
- package/dist/federation/tasks/tasks.test.mjs +2 -2
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{federation-DC1yfb-8.cjs → federation-BVkPF8vF.cjs} +246 -31
- package/dist/{http-Cuk0w0rp.cjs → http-BbDZCEnR.cjs} +1 -1
- package/dist/{http-Dx7yMmfw.js → http-D4JQwy-3.js} +1 -1
- package/dist/{http-D-DpP4sd.mjs → http-SIEv_YGW.mjs} +4 -4
- package/dist/{key-Djyt1BFx.mjs → key-CtAhsSFI.mjs} +2 -2
- package/dist/{kv-cache-CUZOCSKZ.js → kv-cache-DXFAaMh2.js} +1 -1
- package/dist/{kv-cache-BmLTVLXc.cjs → kv-cache-DxLtK3Np.cjs} +1 -1
- package/dist/{kv-cache-ecUXfCqW.mjs → kv-cache-Fn7dxiMu.mjs} +1 -1
- package/dist/{ld-CNVWdooi.mjs → ld-BuI0RakW.mjs} +3 -3
- package/dist/{metrics-BnYleVpg.mjs → metrics-jr7IbGjd.mjs} +1 -1
- package/dist/{middleware-Bh592bk8.mjs → middleware-BWhRFmO0.mjs} +1 -1
- package/dist/{middleware-C2_LcbL3.mjs → middleware-BhtaUtlt.mjs} +243 -28
- package/dist/{middleware-BdzcazaN.js → middleware-D0t1NBIE.js} +246 -31
- package/dist/mod.cjs +4 -4
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-D_BDPwm2.mjs → owner-CoNYVTQp.mjs} +3 -3
- package/dist/{portable-collection-hcONGyUs.mjs → portable-collection-CxP30PWK.mjs} +2 -2
- package/dist/{portable-collection-DwJ8YJP2.cjs → portable-collection-FLEUNFj5.cjs} +1 -1
- package/dist/{portable-collection-C0c0rUN9.js → portable-collection-ZczKiIeK.js} +1 -1
- package/dist/{portable-key-B880yVlC.mjs → portable-key-90Ux6h7F.mjs} +1 -1
- package/dist/{proof-z6Prgi5I.mjs → proof-Bhsb_KYD.mjs} +4 -4
- package/dist/{send-Cw545L_2.mjs → send-CdRJj10a.mjs} +3 -3
- package/dist/sig/compound-proof-discovery.test.mjs +1 -1
- package/dist/sig/compound-proof-producer.test.mjs +1 -1
- package/dist/sig/compound-proof-verification.test.mjs +2 -2
- package/dist/sig/compound-proof.test.mjs +2 -2
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/portable-collection.test.mjs +1 -1
- package/dist/sig/portable-key.test.mjs +6 -6
- package/dist/sig/proof.test.mjs +5 -3
- package/dist/{temporal-Cy-8WCod.mjs → temporal-vBRC6bwu.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +7 -7
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
const require_rolldown_runtime = require("./rolldown-runtime-Dmm3t92W.cjs");
|
|
3
3
|
const require_transformers = require("./transformers-BalCrSsr.cjs");
|
|
4
|
-
const require_http = require("./http-
|
|
4
|
+
const require_http = require("./http-BbDZCEnR.cjs");
|
|
5
5
|
const require_types = require("./types-poIao40f.cjs");
|
|
6
|
-
const require_portable_collection = require("./portable-collection-
|
|
7
|
-
const require_kv_cache = require("./kv-cache-
|
|
6
|
+
const require_portable_collection = require("./portable-collection-FLEUNFj5.cjs");
|
|
7
|
+
const require_kv_cache = require("./kv-cache-DxLtK3Np.cjs");
|
|
8
8
|
let _logtape_logtape = require("@logtape/logtape");
|
|
9
9
|
let _fedify_uri_template = require("@fedify/uri-template");
|
|
10
10
|
let _fedify_vocab = require("@fedify/vocab");
|
|
@@ -1457,7 +1457,7 @@ const textEncoder = new TextEncoder();
|
|
|
1457
1457
|
function isPortableIdValue(value) {
|
|
1458
1458
|
return typeof value === "string" && require_http.isPortableId(value);
|
|
1459
1459
|
}
|
|
1460
|
-
function isJsonMap(value) {
|
|
1460
|
+
function isJsonMap$1(value) {
|
|
1461
1461
|
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
1462
1462
|
}
|
|
1463
1463
|
function isCompoundProofJsonObject(value) {
|
|
@@ -1523,7 +1523,7 @@ function addBytes(statistics, bytes, limits, path) {
|
|
|
1523
1523
|
if (statistics.byteLength > limits.maxBytes) return limitExceeded("bytes", limits.maxBytes, statistics.byteLength, path);
|
|
1524
1524
|
}
|
|
1525
1525
|
function inspectJsonTree(root, limits) {
|
|
1526
|
-
if (!isJsonMap(root)) return {
|
|
1526
|
+
if (!isJsonMap$1(root)) return {
|
|
1527
1527
|
status: "unsupported",
|
|
1528
1528
|
reason: {
|
|
1529
1529
|
type: "invalidJsonTree",
|
|
@@ -1586,7 +1586,7 @@ function inspectJsonTree(root, limits) {
|
|
|
1586
1586
|
insideProof: current.insideProof,
|
|
1587
1587
|
insideContext: current.insideContext
|
|
1588
1588
|
});
|
|
1589
|
-
} else if (isJsonMap(value)) {
|
|
1589
|
+
} else if (isJsonMap$1(value)) {
|
|
1590
1590
|
const prototype = Object.getPrototypeOf(value);
|
|
1591
1591
|
if (seen.has(value) || !hasOnlyDataProperties(value) || prototype !== Object.prototype && prototype !== null) return {
|
|
1592
1592
|
status: "unsupported",
|
|
@@ -1607,7 +1607,7 @@ function inspectJsonTree(root, limits) {
|
|
|
1607
1607
|
if (hasDirectProof) {
|
|
1608
1608
|
statistics.proofCount++;
|
|
1609
1609
|
if (statistics.proofCount > limits.maxProofs) return limitExceeded("proofs", limits.maxProofs, statistics.proofCount, childPath(current.path, "proof"));
|
|
1610
|
-
if (!isJsonMap(value.proof)) return {
|
|
1610
|
+
if (!isJsonMap$1(value.proof)) return {
|
|
1611
1611
|
status: "unsupported",
|
|
1612
1612
|
reason: {
|
|
1613
1613
|
type: "unsupportedProofShape",
|
|
@@ -1782,7 +1782,7 @@ function inspectCompoundPortableObjectApplicability(json, limits) {
|
|
|
1782
1782
|
iterator: value.values(),
|
|
1783
1783
|
depth: frame.depth + 1
|
|
1784
1784
|
});
|
|
1785
|
-
} else if (isJsonMap(value)) {
|
|
1785
|
+
} else if (isJsonMap$1(value)) {
|
|
1786
1786
|
mapCount++;
|
|
1787
1787
|
if (mapCount > limits.maxMaps) return "indeterminate";
|
|
1788
1788
|
if ([value.id, value["@id"]].some(isPortableIdValue)) return "present";
|
|
@@ -1878,7 +1878,7 @@ function containsCompoundPortableObject(json) {
|
|
|
1878
1878
|
* @internal
|
|
1879
1879
|
*/
|
|
1880
1880
|
function findUnsupportedCompoundProofShape(json) {
|
|
1881
|
-
return findInJsonMaps(json, (map, path) => Object.hasOwn(map, "proof") && !isJsonMap(map.proof) ? childPath(path, "proof") : void 0) ?? null;
|
|
1881
|
+
return findInJsonMaps(json, (map, path) => Object.hasOwn(map, "proof") && !isJsonMap$1(map.proof) ? childPath(path, "proof") : void 0) ?? null;
|
|
1882
1882
|
}
|
|
1883
1883
|
/**
|
|
1884
1884
|
* Discovers direct literal proof-bearing maps in an immutable JSON snapshot.
|
|
@@ -2080,13 +2080,13 @@ async function isEmbeddedPortableKey(parent, member, key, parentId) {
|
|
|
2080
2080
|
}
|
|
2081
2081
|
if (expanded.length !== 1 || hasGraphKeyword(expanded)) return false;
|
|
2082
2082
|
const node = expanded[0];
|
|
2083
|
-
if (!isJsonMap(node) || typeof node["@id"] !== "string" || getCanonicalPortableIdOf(node["@id"]) !== parentPortableId) return false;
|
|
2083
|
+
if (!isJsonMap$1(node) || typeof node["@id"] !== "string" || getCanonicalPortableIdOf(node["@id"]) !== parentPortableId) return false;
|
|
2084
2084
|
const properties = Object.keys(node).filter((property) => property !== "@id" && property !== "@type");
|
|
2085
2085
|
if (properties.length !== 1 || properties[0] !== `${SECURITY}${member}`) return false;
|
|
2086
2086
|
const values = node[properties[0]];
|
|
2087
2087
|
if (!Array.isArray(values) || values.length !== 1) return false;
|
|
2088
2088
|
const expandedKey = values[0];
|
|
2089
|
-
if (!isJsonMap(expandedKey) || expandedKey["@id"] !== literalIds[0] || Object.keys(expandedKey).some((property) => !KEY_PROPERTIES.has(property))) return false;
|
|
2089
|
+
if (!isJsonMap$1(expandedKey) || expandedKey["@id"] !== literalIds[0] || Object.keys(expandedKey).some((property) => !KEY_PROPERTIES.has(property))) return false;
|
|
2090
2090
|
const types = expandedKey["@type"];
|
|
2091
2091
|
if (types !== void 0 && (!Array.isArray(types) || types.some((type) => typeof type !== "string" || !KEY_TYPES.has(type)))) return false;
|
|
2092
2092
|
const pem = expandedKey[`${SECURITY}publicKeyPem`];
|
|
@@ -2097,7 +2097,7 @@ async function isEmbeddedPortableKey(parent, member, key, parentId) {
|
|
|
2097
2097
|
for (const property of [`${SECURITY}owner`, `${SECURITY}controller`]) {
|
|
2098
2098
|
const owners = expandedKey[property];
|
|
2099
2099
|
if (owners === void 0) continue;
|
|
2100
|
-
if (!Array.isArray(owners) || owners.length !== 1 || !isJsonMap(owners[0]) || Object.keys(owners[0]).length !== 1 || typeof owners[0]["@id"] !== "string" || getCanonicalPortableIdOf(owners[0]["@id"]) !== parentPortableId) return false;
|
|
2100
|
+
if (!Array.isArray(owners) || owners.length !== 1 || !isJsonMap$1(owners[0]) || Object.keys(owners[0]).length !== 1 || typeof owners[0]["@id"] !== "string" || getCanonicalPortableIdOf(owners[0]["@id"]) !== parentPortableId) return false;
|
|
2101
2101
|
}
|
|
2102
2102
|
return true;
|
|
2103
2103
|
}
|
|
@@ -2140,7 +2140,7 @@ function isSimpleContext(context) {
|
|
|
2140
2140
|
}
|
|
2141
2141
|
function hasGraphKeyword(value) {
|
|
2142
2142
|
if (Array.isArray(value)) return value.some(hasGraphKeyword);
|
|
2143
|
-
if (!isJsonMap(value)) return false;
|
|
2143
|
+
if (!isJsonMap$1(value)) return false;
|
|
2144
2144
|
return Object.entries(value).some(([key, child]) => key === "@graph" || key === "@included" || key === "@reverse" || hasGraphKeyword(child));
|
|
2145
2145
|
}
|
|
2146
2146
|
/**
|
|
@@ -2150,7 +2150,7 @@ function hasGraphKeyword(value) {
|
|
|
2150
2150
|
function isSingleStringValue(values, datatype) {
|
|
2151
2151
|
if (!Array.isArray(values) || values.length !== 1) return false;
|
|
2152
2152
|
const value = values[0];
|
|
2153
|
-
if (!isJsonMap(value) || typeof value["@value"] !== "string") return false;
|
|
2153
|
+
if (!isJsonMap$1(value) || typeof value["@value"] !== "string") return false;
|
|
2154
2154
|
const keys = Object.keys(value);
|
|
2155
2155
|
return keys.length === 1 || datatype != null && keys.length === 2 && value["@type"] === datatype;
|
|
2156
2156
|
}
|
|
@@ -2205,7 +2205,7 @@ async function verifyServedPortableObjects(json, options = {}) {
|
|
|
2205
2205
|
const maps = collected.maps;
|
|
2206
2206
|
const discovered = /* @__PURE__ */ new Map();
|
|
2207
2207
|
const ids = maps.map((candidate) => candidate.id);
|
|
2208
|
-
const rootId = isJsonMap(json) ? [json.id, json["@id"]].find(isPortableIdValue) : void 0;
|
|
2208
|
+
const rootId = isJsonMap$1(json) ? [json.id, json["@id"]].find(isPortableIdValue) : void 0;
|
|
2209
2209
|
if (rootId != null) ids.push(rootId);
|
|
2210
2210
|
for (const id of ids) discovered.set(id, (discovered.get(id) ?? 0) + 1);
|
|
2211
2211
|
let hidden;
|
|
@@ -2250,7 +2250,7 @@ function findHiddenPortableObject(expanded, discovered) {
|
|
|
2250
2250
|
pending.push(...value);
|
|
2251
2251
|
continue;
|
|
2252
2252
|
}
|
|
2253
|
-
if (!isJsonMap(value)) continue;
|
|
2253
|
+
if (!isJsonMap$1(value)) continue;
|
|
2254
2254
|
const id = value["@id"];
|
|
2255
2255
|
if (isPortableIdValue(id) && Object.keys(value).some((key) => key !== "@id")) {
|
|
2256
2256
|
const count = remaining.get(id) ?? 0;
|
|
@@ -2341,7 +2341,7 @@ function collectServedPortableMaps(json) {
|
|
|
2341
2341
|
}
|
|
2342
2342
|
async function checkServedPortableMap({ map, contexts }, options) {
|
|
2343
2343
|
if (Object.hasOwn(map, "proof")) {
|
|
2344
|
-
if (!isJsonMap(map.proof)) return "unsupportedProofShape";
|
|
2344
|
+
if (!isJsonMap$1(map.proof)) return "unsupportedProofShape";
|
|
2345
2345
|
if (!Object.hasOwn(map, "@context")) return "missingContext";
|
|
2346
2346
|
try {
|
|
2347
2347
|
const policy = await require_http.verifyPortableObjectProofPolicy(map, await require_http.verifyMapLocalProof(map, options), options);
|
|
@@ -2362,11 +2362,185 @@ async function checkServedPortableMap({ map, contexts }, options) {
|
|
|
2362
2362
|
} catch {
|
|
2363
2363
|
return "unsupportedContext";
|
|
2364
2364
|
}
|
|
2365
|
-
if (expanded.length !== 1 || !isJsonMap(expanded[0])) return "invalidPortableObject";
|
|
2365
|
+
if (expanded.length !== 1 || !isJsonMap$1(expanded[0])) return "invalidPortableObject";
|
|
2366
2366
|
const type = require_http.classifyFep2277CoreType(expanded[0]);
|
|
2367
2367
|
return UNSECURED_CORE_TYPES.has(type) ? null : "missingProof";
|
|
2368
2368
|
}
|
|
2369
2369
|
//#endregion
|
|
2370
|
+
//#region src/federation/compatible-id-warning.ts
|
|
2371
|
+
/** Returns a verified first gateway, without dereferencing the actor. */
|
|
2372
|
+
async function getLocalFirstGateway(context, ownerId, did) {
|
|
2373
|
+
try {
|
|
2374
|
+
const parsed = context.parseUri(ownerId, { portable: true });
|
|
2375
|
+
if (parsed?.type !== "actor" || parsed.authority !== did) return null;
|
|
2376
|
+
return firstGateway(await context.getActor(parsed.identifier), did);
|
|
2377
|
+
} catch (error) {
|
|
2378
|
+
(0, _logtape_logtape.getLogger)([
|
|
2379
|
+
"fedify",
|
|
2380
|
+
"federation",
|
|
2381
|
+
"object"
|
|
2382
|
+
]).debug("Could not check the first gateway of {ownerId}: {error}", {
|
|
2383
|
+
ownerId: ownerId.href,
|
|
2384
|
+
error
|
|
2385
|
+
});
|
|
2386
|
+
return null;
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
function firstGateway(actor, did) {
|
|
2390
|
+
if (actor?.id == null || require_http.getPortableDid(actor.id) !== did) return null;
|
|
2391
|
+
const gateway = actor.gateway;
|
|
2392
|
+
return gateway != null && (0, _fedify_vocab_runtime.isGatewayUrl)(gateway) ? gateway : null;
|
|
2393
|
+
}
|
|
2394
|
+
/** Looks for an actor already embedded in the document being published. */
|
|
2395
|
+
function getEmbeddedFirstGateway(json, ownerId, did) {
|
|
2396
|
+
const owner = require_http.getCanonicalPortableId(ownerId);
|
|
2397
|
+
if (owner == null) return null;
|
|
2398
|
+
return visitJsonMaps(json, (map) => {
|
|
2399
|
+
const id = parseMapId(map, isJsonMap(json) ? json : null);
|
|
2400
|
+
if (id == null || require_http.getCanonicalPortableId(id) !== owner) return;
|
|
2401
|
+
const gateways = map.gateways ?? map["https://w3id.org/fep/ef61/gateways"];
|
|
2402
|
+
const first = Array.isArray(gateways) ? gateways[0] : isJsonMap(gateways) && Array.isArray(gateways["@list"]) ? gateways["@list"][0] : null;
|
|
2403
|
+
const address = typeof first === "string" ? first : isJsonMap(first) ? first.id ?? first["@id"] : null;
|
|
2404
|
+
if (typeof address !== "string") return;
|
|
2405
|
+
try {
|
|
2406
|
+
const gateway = new URL(address);
|
|
2407
|
+
if (require_http.getPortableDid(id) === did && (0, _fedify_vocab_runtime.isGatewayUrl)(gateway)) return gateway;
|
|
2408
|
+
} catch (error) {
|
|
2409
|
+
if (!(error instanceof TypeError)) throw error;
|
|
2410
|
+
}
|
|
2411
|
+
}) ?? null;
|
|
2412
|
+
}
|
|
2413
|
+
function isJsonMap(value) {
|
|
2414
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
2415
|
+
}
|
|
2416
|
+
/** Warns only when the publisher's actual first gateway is known. */
|
|
2417
|
+
function warnCompatibleId(id, did, gateway, kind) {
|
|
2418
|
+
if (!(0, _fedify_vocab_runtime_internal_portable_dereference.isCompatibleEf61Iri)(id) || require_http.getPortableDid(id) !== did || id.origin === gateway.origin) return;
|
|
2419
|
+
(0, _logtape_logtape.getLogger)([
|
|
2420
|
+
"fedify",
|
|
2421
|
+
"federation",
|
|
2422
|
+
kind === "activity" ? "outbox" : "object"
|
|
2423
|
+
]).warn("The {kind} {id} has an FEP-ef61 compatible identifier on another gateway than its owner's first gateway, {gateway}. FEP-ef61 requires publishers to use the first gateway in the actor's gateways.", {
|
|
2424
|
+
kind,
|
|
2425
|
+
id: id.href,
|
|
2426
|
+
gateway: gateway.origin
|
|
2427
|
+
});
|
|
2428
|
+
}
|
|
2429
|
+
/** Reads the root ID without dereferencing or expanding the document. */
|
|
2430
|
+
function getCompactRootId(json) {
|
|
2431
|
+
return isJsonMap(json) ? parseMapId(json, json) : null;
|
|
2432
|
+
}
|
|
2433
|
+
/** Checks an activity and its embedded objects against each one's owner. */
|
|
2434
|
+
async function warnCompatibleIdsInJson(json, context) {
|
|
2435
|
+
const root = isJsonMap(json) ? json : null;
|
|
2436
|
+
const rootOwners = root == null ? [] : ownerIds(root, "actor", root);
|
|
2437
|
+
const gateways = /* @__PURE__ */ new Map();
|
|
2438
|
+
const maps = [];
|
|
2439
|
+
visitJsonMaps(json, (map, path) => {
|
|
2440
|
+
maps.push({
|
|
2441
|
+
map,
|
|
2442
|
+
path
|
|
2443
|
+
});
|
|
2444
|
+
});
|
|
2445
|
+
for (const { map, path } of maps) {
|
|
2446
|
+
const id = parseMapId(map, root);
|
|
2447
|
+
if (id == null || !(0, _fedify_vocab_runtime_internal_portable_dereference.isCompatibleEf61Iri)(id)) continue;
|
|
2448
|
+
const type = map.type ?? map["@type"];
|
|
2449
|
+
if ((Array.isArray(type) ? type : [type]).some((t) => typeof t === "string" && /(?:^|[#/:])(CryptographicKey|Multikey|JsonWebKey|Key)$/.test(t))) continue;
|
|
2450
|
+
const did = require_http.getPortableDid(id);
|
|
2451
|
+
if (did == null) continue;
|
|
2452
|
+
const owners = path === "" ? rootOwners : [
|
|
2453
|
+
...ownerIds(map, "actor", root),
|
|
2454
|
+
...ownerIds(map, "attributedTo", root),
|
|
2455
|
+
...rootOwners
|
|
2456
|
+
];
|
|
2457
|
+
for (const ownerId of owners) {
|
|
2458
|
+
if (require_http.getPortableDid(ownerId) !== did) continue;
|
|
2459
|
+
const key = require_http.getCanonicalPortableId(ownerId);
|
|
2460
|
+
if (key == null) continue;
|
|
2461
|
+
let gateway = gateways.get(key);
|
|
2462
|
+
if (gateway === void 0) {
|
|
2463
|
+
gateway = getEmbeddedFirstGateway(json, ownerId, did) ?? (context == null ? null : await getLocalFirstGateway(context, ownerId, did));
|
|
2464
|
+
gateways.set(key, gateway);
|
|
2465
|
+
}
|
|
2466
|
+
if (gateway != null) {
|
|
2467
|
+
warnCompatibleId(id, did, gateway, path === "" ? "activity" : "object");
|
|
2468
|
+
break;
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
function ownerIds(map, term, root) {
|
|
2474
|
+
const iri = `https://www.w3.org/ns/activitystreams#${term}`;
|
|
2475
|
+
const values = [map[term], map[iri]];
|
|
2476
|
+
for (const context of [map["@context"], root?.["@context"]]) for (const [alias, definition] of localContextEntries(context)) {
|
|
2477
|
+
const mapped = typeof definition === "string" ? definition : isJsonMap(definition) ? definition["@id"] : null;
|
|
2478
|
+
if (mapped === iri || mapped === `as:${term}`) values.push(map[alias]);
|
|
2479
|
+
}
|
|
2480
|
+
return values.flatMap((value) => parseOwnerIds(value, root));
|
|
2481
|
+
}
|
|
2482
|
+
function localContextEntries(context) {
|
|
2483
|
+
if (Array.isArray(context)) return context.flatMap(localContextEntries);
|
|
2484
|
+
return isJsonMap(context) ? Object.entries(context) : [];
|
|
2485
|
+
}
|
|
2486
|
+
function parseOwnerIds(value, root) {
|
|
2487
|
+
if (Array.isArray(value)) return value.flatMap((item) => parseOwnerIds(item, root));
|
|
2488
|
+
if (isJsonMap(value)) {
|
|
2489
|
+
const id = parseMapId(value, root);
|
|
2490
|
+
return id == null ? [] : [id];
|
|
2491
|
+
}
|
|
2492
|
+
if (typeof value !== "string") return [];
|
|
2493
|
+
try {
|
|
2494
|
+
return [(0, _fedify_vocab_runtime.parseIri)(value)];
|
|
2495
|
+
} catch (error) {
|
|
2496
|
+
if (error instanceof TypeError) return [];
|
|
2497
|
+
throw error;
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
function parseMapId(map, root) {
|
|
2501
|
+
let raw = map["@id"] ?? map.id;
|
|
2502
|
+
for (const context of [map["@context"], root?.["@context"]]) for (const [alias, definition] of localContextEntries(context)) if ((typeof definition === "string" ? definition : isJsonMap(definition) ? definition["@id"] : null) === "@id" && typeof map[alias] === "string") {
|
|
2503
|
+
raw = map[alias];
|
|
2504
|
+
break;
|
|
2505
|
+
}
|
|
2506
|
+
if (typeof raw !== "string") return null;
|
|
2507
|
+
try {
|
|
2508
|
+
return (0, _fedify_vocab_runtime.parseIri)(raw);
|
|
2509
|
+
} catch (error) {
|
|
2510
|
+
if (error instanceof TypeError) return null;
|
|
2511
|
+
throw error;
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
function visitJsonMaps(json, visit) {
|
|
2515
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2516
|
+
const pending = [{
|
|
2517
|
+
value: json,
|
|
2518
|
+
path: ""
|
|
2519
|
+
}];
|
|
2520
|
+
while (pending.length > 0) {
|
|
2521
|
+
const { value, path } = pending.pop();
|
|
2522
|
+
if (value == null || typeof value !== "object" || seen.has(value)) continue;
|
|
2523
|
+
seen.add(value);
|
|
2524
|
+
if (Array.isArray(value)) {
|
|
2525
|
+
for (let i = value.length - 1; i >= 0; i--) pending.push({
|
|
2526
|
+
value: value[i],
|
|
2527
|
+
path: `${path}/${i}`
|
|
2528
|
+
});
|
|
2529
|
+
continue;
|
|
2530
|
+
}
|
|
2531
|
+
const map = value;
|
|
2532
|
+
const result = visit(map, path);
|
|
2533
|
+
if (result !== void 0) return result;
|
|
2534
|
+
for (const key of Object.keys(map).reverse()) {
|
|
2535
|
+
if (key === "proof" || key === "@context") continue;
|
|
2536
|
+
pending.push({
|
|
2537
|
+
value: map[key],
|
|
2538
|
+
path: `${path}/${key}`
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
//#endregion
|
|
2370
2544
|
//#region src/federation/audience.ts
|
|
2371
2545
|
const AS_NAMESPACE = "https://www.w3.org/ns/activitystreams#";
|
|
2372
2546
|
/**
|
|
@@ -4161,6 +4335,7 @@ async function handleObject(request, { values, context, objectDispatcher, author
|
|
|
4161
4335
|
Vary: "Accept"
|
|
4162
4336
|
}
|
|
4163
4337
|
});
|
|
4338
|
+
await warnServedCompatibleObject(context, object, getCompactRootId(jsonLd));
|
|
4164
4339
|
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
4165
4340
|
"Content-Type": "application/activity+json",
|
|
4166
4341
|
Vary: "Accept"
|
|
@@ -4264,6 +4439,7 @@ async function handlePortableObject(request, { values, context, objectDispatcher
|
|
|
4264
4439
|
return portableObjectInternalServerError(request);
|
|
4265
4440
|
}
|
|
4266
4441
|
}
|
|
4442
|
+
if (!tombstone) await warnServedCompatibleObject(context, object, servedId);
|
|
4267
4443
|
const headers = new Headers({
|
|
4268
4444
|
"Content-Type": PORTABLE_OBJECT_CONTENT_TYPE,
|
|
4269
4445
|
Vary: "Accept"
|
|
@@ -4274,6 +4450,32 @@ async function handlePortableObject(request, { values, context, objectDispatcher
|
|
|
4274
4450
|
headers
|
|
4275
4451
|
});
|
|
4276
4452
|
}
|
|
4453
|
+
async function warnServedCompatibleObject(context, object, serializedId) {
|
|
4454
|
+
try {
|
|
4455
|
+
if ((0, _fedify_vocab.isActor)(object)) return;
|
|
4456
|
+
const id = typeof serializedId === "string" ? (0, _fedify_vocab_runtime.parseIri)(serializedId) : serializedId ?? object.id;
|
|
4457
|
+
if (id == null || !(0, _fedify_vocab_runtime_internal_portable_dereference.isCompatibleEf61Iri)(id)) return;
|
|
4458
|
+
const did = require_http.getPortableDid(id);
|
|
4459
|
+
if (did == null) return;
|
|
4460
|
+
const ownerIds = object instanceof _fedify_vocab.Activity ? object.actorIds : object.attributionIds;
|
|
4461
|
+
for (const ownerId of ownerIds) {
|
|
4462
|
+
if (require_http.getPortableDid(ownerId) !== did) continue;
|
|
4463
|
+
const gateway = await getLocalFirstGateway(context, ownerId, did);
|
|
4464
|
+
if (gateway == null) continue;
|
|
4465
|
+
warnCompatibleId(id, did, gateway, object instanceof _fedify_vocab.Activity ? "activity" : "object");
|
|
4466
|
+
break;
|
|
4467
|
+
}
|
|
4468
|
+
} catch (error) {
|
|
4469
|
+
(0, _logtape_logtape.getLogger)([
|
|
4470
|
+
"fedify",
|
|
4471
|
+
"federation",
|
|
4472
|
+
"object"
|
|
4473
|
+
]).debug("Could not check the first gateway of {objectId}: {error}", {
|
|
4474
|
+
objectId: object.id?.href,
|
|
4475
|
+
error
|
|
4476
|
+
});
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4277
4479
|
function isRequestedPortableObject(object, canonicalId) {
|
|
4278
4480
|
return object.id != null && require_http.getCanonicalPortableId(object.id) === canonicalId;
|
|
4279
4481
|
}
|
|
@@ -4377,13 +4579,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
|
4377
4579
|
* @param parameters The parameters for handling the collection.
|
|
4378
4580
|
* @returns A promise that resolves to an HTTP response.
|
|
4379
4581
|
*/
|
|
4380
|
-
async function handleCollection(request, { name: name$
|
|
4381
|
-
const spanName = name$
|
|
4582
|
+
async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, portable, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
|
|
4583
|
+
const spanName = name$1.trim().replace(/\s+/g, "_");
|
|
4382
4584
|
tracerProvider = tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
4383
4585
|
const tracer = tracerProvider.getTracer(require_http.name, require_http.version);
|
|
4384
4586
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
4385
4587
|
const metricBase = {
|
|
4386
|
-
kind: getCollectionMetricKind(name$
|
|
4588
|
+
kind: getCollectionMetricKind(name$1),
|
|
4387
4589
|
page: cursor != null,
|
|
4388
4590
|
dispatcher: "built_in"
|
|
4389
4591
|
};
|
|
@@ -4429,7 +4631,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
4429
4631
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
4430
4632
|
return await onNotFound(request);
|
|
4431
4633
|
}
|
|
4432
|
-
const items = filterCollectionItems(page.items, name$
|
|
4634
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
4433
4635
|
itemCount = items.length;
|
|
4434
4636
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
4435
4637
|
return items;
|
|
@@ -4471,7 +4673,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
4471
4673
|
} else {
|
|
4472
4674
|
const uri = new URL(portable == null ? baseUri : pageBase);
|
|
4473
4675
|
uri.searchParams.set("cursor", cursor);
|
|
4474
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
4676
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
4475
4677
|
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
4476
4678
|
attributes: {
|
|
4477
4679
|
"activitypub.collection.id": uri.href,
|
|
@@ -4487,7 +4689,7 @@ async function handleCollection(request, { name: name$2, identifier, uriGetter,
|
|
|
4487
4689
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
4488
4690
|
return await onNotFound(request);
|
|
4489
4691
|
}
|
|
4490
|
-
const items = filterCollectionItems(page.items, name$
|
|
4692
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
4491
4693
|
itemCount = items.length;
|
|
4492
4694
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
4493
4695
|
return {
|
|
@@ -4699,7 +4901,7 @@ async function handleOutbox(request, { identifier, context: ctx, outboxContextFa
|
|
|
4699
4901
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
4700
4902
|
});
|
|
4701
4903
|
}
|
|
4702
|
-
if (!activity.actorIds.every((actorId) => actorId
|
|
4904
|
+
if (!activity.actorIds.every((actorId) => require_http.isSameObjectId(actorId, expectedActorId))) {
|
|
4703
4905
|
const error = /* @__PURE__ */ new Error("The activity actor does not match the outbox owner.");
|
|
4704
4906
|
logger.error("The posted activity actor does not match outbox owner {identifier}.", {
|
|
4705
4907
|
identifier,
|
|
@@ -5678,8 +5880,8 @@ var CustomCollectionHandler = class {
|
|
|
5678
5880
|
* @param CollectionPage The CollectionPage constructor.
|
|
5679
5881
|
* @param filterPredicate Optional filter predicate for items.
|
|
5680
5882
|
*/
|
|
5681
|
-
constructor(name$
|
|
5682
|
-
this.name = name$
|
|
5883
|
+
constructor(name$2, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate, portable) {
|
|
5884
|
+
this.name = name$2;
|
|
5683
5885
|
this.values = values;
|
|
5684
5886
|
this.context = context;
|
|
5685
5887
|
this.callbacks = callbacks;
|
|
@@ -10603,17 +10805,26 @@ var ContextImpl = class ContextImpl {
|
|
|
10603
10805
|
activityId: activity.id?.href,
|
|
10604
10806
|
activity
|
|
10605
10807
|
});
|
|
10808
|
+
const activityJsonLd = await activity.toJsonLd({
|
|
10809
|
+
format: "compact",
|
|
10810
|
+
contextLoader: this.contextLoader
|
|
10811
|
+
});
|
|
10812
|
+
try {
|
|
10813
|
+
await warnCompatibleIdsInJson(activityJsonLd, this instanceof RequestContextImpl && !this.isInActorDispatcher() ? this : void 0);
|
|
10814
|
+
} catch (error) {
|
|
10815
|
+
logger.debug("Could not check the first gateway of activity {activityId}: {error}", {
|
|
10816
|
+
activityId: activity.id?.href,
|
|
10817
|
+
error
|
|
10818
|
+
});
|
|
10819
|
+
}
|
|
10606
10820
|
if (this.federation.fanoutQueue == null || options.immediate || options.fanout === "skip" || (options.fanout ?? "auto") === "auto" && globalThis.Object.keys(inboxes).length < FANOUT_THRESHOLD) {
|
|
10607
10821
|
await this.federation.sendActivity(keys, inboxes, activity, {
|
|
10608
10822
|
...opts,
|
|
10823
|
+
activityJsonLd,
|
|
10609
10824
|
normalizeExistingProofs: proofCreated || options.normalizeExistingProofs
|
|
10610
10825
|
});
|
|
10611
10826
|
return true;
|
|
10612
10827
|
}
|
|
10613
|
-
const activityJsonLd = await activity.toJsonLd({
|
|
10614
|
-
format: "compact",
|
|
10615
|
-
contextLoader: this.contextLoader
|
|
10616
|
-
});
|
|
10617
10828
|
assertSupportedCompoundProofShape(activityJsonLd, activity.id?.href);
|
|
10618
10829
|
const keyJwkPairs = await Promise.all(keys.map(async ({ keyId, privateKey }) => ({
|
|
10619
10830
|
keyId: keyId.href,
|
|
@@ -10796,6 +11007,10 @@ var RequestContextImpl = class RequestContextImpl extends ContextImpl {
|
|
|
10796
11007
|
#invokedFromActorDispatcher;
|
|
10797
11008
|
#invokedFromObjectDispatcher;
|
|
10798
11009
|
request;
|
|
11010
|
+
/** Whether a diagnostic actor lookup would re-enter the actor dispatcher. */
|
|
11011
|
+
isInActorDispatcher() {
|
|
11012
|
+
return this.#invokedFromActorDispatcher != null;
|
|
11013
|
+
}
|
|
10799
11014
|
url = void 0;
|
|
10800
11015
|
portableRequest;
|
|
10801
11016
|
constructor(options) {
|
|
@@ -16,7 +16,7 @@ json_canon = require_rolldown_runtime.__toESM(json_canon, 1);
|
|
|
16
16
|
let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
17
17
|
//#region deno.json
|
|
18
18
|
var name = "@fedify/fedify";
|
|
19
|
-
var version = "2.4.0-dev.
|
|
19
|
+
var version = "2.4.0-dev.2233+abb4a6b2";
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/sig/portable-key-id.ts
|
|
22
22
|
const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
|
|
@@ -14,7 +14,7 @@ import serialize from "json-canon";
|
|
|
14
14
|
import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
|
|
15
15
|
//#region deno.json
|
|
16
16
|
var name = "@fedify/fedify";
|
|
17
|
-
var version = "2.4.0-dev.
|
|
17
|
+
var version = "2.4.0-dev.2233+abb4a6b2";
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/sig/portable-key-id.ts
|
|
20
20
|
const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
|
|
@@ -2,12 +2,12 @@ import { Temporal } from "temporal-polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { m as parseKeyIdString } from "./portable-key-id-Ca30-hOa.mjs";
|
|
5
|
-
import { n as version, t as name } from "./deno-
|
|
6
|
-
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-
|
|
5
|
+
import { n as version, t as name } from "./deno-62DcBMwc.mjs";
|
|
6
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-jr7IbGjd.mjs";
|
|
7
7
|
import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPVqki78.mjs";
|
|
8
8
|
import { a as promoteKeyOwnerEvidence } from "./key-owner-evidence-APB6NpSk.mjs";
|
|
9
|
-
import { a as fetchKeyDetailed, c as validateCryptoKey, t as bypassKeyCacheReads } from "./key-
|
|
10
|
-
import { n as resolvePortableActorKey, r as verifyPortableGatewayKeyDocument } from "./portable-key-
|
|
9
|
+
import { a as fetchKeyDetailed, c as validateCryptoKey, t as bypassKeyCacheReads } from "./key-CtAhsSFI.mjs";
|
|
10
|
+
import { n as resolvePortableActorKey, r as verifyPortableGatewayKeyDocument } from "./portable-key-90Ux6h7F.mjs";
|
|
11
11
|
import { getLogger } from "@logtape/logtape";
|
|
12
12
|
import { CryptographicKey } from "@fedify/vocab";
|
|
13
13
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -2,8 +2,8 @@ import { Temporal } from "temporal-polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { c as isPortableActorDocument, d as isPortableUri, l as isPortableId, m as parseKeyIdString, s as isCompatibleKeyId } from "./portable-key-id-Ca30-hOa.mjs";
|
|
5
|
-
import { n as version, t as name } from "./deno-
|
|
6
|
-
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-
|
|
5
|
+
import { n as version, t as name } from "./deno-62DcBMwc.mjs";
|
|
6
|
+
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-jr7IbGjd.mjs";
|
|
7
7
|
import { n as attachKeyOwnerEvidence, t as MAX_PORTABLE_KEY_TTL } from "./key-owner-evidence-APB6NpSk.mjs";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
9
9
|
import { CryptographicKey, Multikey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { G as validateCryptoKey, ot as recordDocumentCache, t as doubleKnock } from "./http-
|
|
3
|
+
import { G as validateCryptoKey, ot as recordDocumentCache, t as doubleKnock } from "./http-D4JQwy-3.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { FetchError, UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, resolveDocumentLoaderTimeout, validatePublicUrl, withDocumentLoaderTimeout } from "@fedify/vocab-runtime";
|
|
6
6
|
import { curry } from "es-toolkit";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
|
-
const require_http = require("./http-
|
|
2
|
+
const require_http = require("./http-BbDZCEnR.cjs");
|
|
3
3
|
let _logtape_logtape = require("@logtape/logtape");
|
|
4
4
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
5
5
|
let es_toolkit = require("es-toolkit");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { p as recordDocumentCache } from "./metrics-
|
|
4
|
+
import { p as recordDocumentCache } from "./metrics-jr7IbGjd.mjs";
|
|
5
5
|
import { getLogger } from "@logtape/logtape";
|
|
6
6
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/utils/kv-cache.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-
|
|
6
|
-
import { c as validateCryptoKey, i as fetchKey, t as bypassKeyCacheReads } from "./key-
|
|
4
|
+
import { n as version, t as name } from "./deno-62DcBMwc.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-jr7IbGjd.mjs";
|
|
6
|
+
import { c as validateCryptoKey, i as fetchKey, t as bypassKeyCacheReads } from "./key-CtAhsSFI.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
|
|
9
9
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
4
|
+
import { n as version, t as name } from "./deno-62DcBMwc.mjs";
|
|
5
5
|
import { metrics } from "@opentelemetry/api";
|
|
6
6
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/federation/metrics.ts
|