@fedify/fedify 2.3.0-dev.1212 → 2.3.0-dev.1213
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-DdbtvTFp.mjs → builder-Bj-7Sl7u.mjs} +9 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/outgoing-jsonld.test.mjs +1 -1
- package/dist/compat/public-audience.test.mjs +1 -1
- package/dist/compat/transformers.test.mjs +2 -2
- package/dist/{context-DMHK7jqX.d.cts → context-BBVLF7lx.d.cts} +41 -2
- package/dist/{context-K9cg8oGx.d.ts → context-BU6jSQdo.d.ts} +42 -2
- package/dist/{deno-DTaoLXHr.mjs → deno-BUzynMVz.mjs} +1 -1
- package/dist/{docloader-CdNiXmNg.mjs → docloader-jQPthO4U.mjs} +2 -2
- package/dist/{esm-BQRw925N.mjs → esm-vrlUxr60.mjs} +23 -1
- package/dist/federation/builder.test.mjs +21 -2
- package/dist/federation/circuit-breaker.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +6 -6
- package/dist/federation/idempotency.test.mjs +4 -4
- package/dist/federation/keycache.test.mjs +1 -1
- package/dist/federation/kv.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +147 -1
- package/dist/federation/middleware.test.mjs +446 -18
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +3 -3
- package/dist/federation/mod.d.ts +3 -3
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +8 -4426
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +2 -2
- package/dist/{http-Czeyq7if.cjs → http-B1zlPuh3.cjs} +79 -2
- package/dist/{http-BEG9kx13.js → http-B_WbYMnB.js} +74 -3
- package/dist/{http-ByCfCX5K.mjs → http-CDaMGwCP.mjs} +4 -4
- package/dist/{key-Bhsx9PrC.mjs → key-DdP4HxTK.mjs} +2 -2
- package/dist/{kv-cache-qRBN2G2Z.cjs → kv-cache-CPIfTWt5.cjs} +1 -1
- package/dist/{kv-cache-D9U1AnXH.js → kv-cache-CXo8QM4m.js} +1 -1
- package/dist/{kv-cache-D4jzgeYW.mjs → kv-cache-DSjv5Aeh.mjs} +1 -1
- package/dist/{ld-CHtLb_Uh.mjs → ld-CuOEh5aB.mjs} +3 -3
- package/dist/{metrics-uwSF8DLC.mjs → metrics-B5vvJYMV.mjs} +74 -3
- package/dist/{middleware-BmSzD5U9.mjs → middleware-Cq9S8A5O.mjs} +328 -24
- package/dist/{middleware-CyiBzIwY.mjs → middleware-DPE-IRlD.mjs} +1 -1
- package/dist/{middleware-DrKDd2JT.js → middleware-Dft_sYeS.js} +352 -41
- package/dist/{middleware-CRORNnSU.cjs → middleware-DlqW4IRW.cjs} +351 -40
- package/dist/{mod-YLnSsEHY.d.cts → mod-C0F6kvgS.d.cts} +1 -1
- package/dist/{mod-CfOFqS0w.d.ts → mod-vPYVoa5n.d.ts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +4 -4
- package/dist/mod.d.ts +4 -4
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/client.test.mjs +2 -2
- package/dist/nodeinfo/handler.test.mjs +2 -2
- package/dist/nodeinfo/types.test.mjs +1 -1
- package/dist/otel/exporter.test.mjs +1 -1
- package/dist/{outgoing-jsonld-BgFLCJQ_.mjs → outgoing-jsonld-L_DbOaFe.mjs} +1 -1
- package/dist/{owner-B0Zrhs0w.mjs → owner--n8rmG51.mjs} +2 -2
- package/dist/{proof-frzCtYji.cjs → proof-BKpJ_p_d.cjs} +1 -1
- package/dist/{proof-CZhAX94C.js → proof-BsvB1vGI.js} +1 -1
- package/dist/{proof-DbJFxpzD.mjs → proof-dhtwaP4z.mjs} +5 -5
- package/dist/{send-kst2L0Df.mjs → send-CTQ30Wbe.mjs} +3 -3
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/http.test.mjs +4 -4
- package/dist/sig/key.test.mjs +2 -2
- package/dist/sig/ld.test.mjs +3 -3
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +2 -2
- package/dist/sig/proof.test.mjs +3 -3
- package/dist/{temporal-CcGypkzd.mjs → temporal-gfUaZjGU.mjs} +1 -1
- package/dist/testing/mod.d.mts +1 -0
- package/dist/utils/docloader.test.mjs +4 -4
- 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
- package/dist/chunk-DNRtMIoB.mjs +0 -29
- package/dist/execAsync-Dmet7-28.mjs +0 -13
- package/dist/getMachineId-bsd-Bn0le7-J.mjs +0 -29
- package/dist/getMachineId-darwin-CVjKuDgj.mjs +0 -26
- package/dist/getMachineId-linux-DbG4BXa-.mjs +0 -22
- package/dist/getMachineId-unsupported-lC8T9hPE.mjs +0 -17
- package/dist/getMachineId-win-c5zxTSS1.mjs +0 -28
- /package/dist/{accept-CceiKpCy.mjs → accept-CPkZzmGN.mjs} +0 -0
- /package/dist/{client-B_A6mfn3.mjs → client-ByXmQhYD.mjs} +0 -0
- /package/dist/{keys-C3kae-6B.mjs → keys-DGu1NFwu.mjs} +0 -0
- /package/dist/{kv-x2IvBUyq.mjs → kv-rV3vodCc.mjs} +0 -0
- /package/dist/{public-audience-N3pyOx2p.mjs → public-audience-Cvbr2Gzt.mjs} +0 -0
- /package/dist/{types-BFowWFTT.mjs → types-J53Kw7so.mjs} +0 -0
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, y as recordOutboxEnqueue } from "./metrics-
|
|
6
|
-
import { t as formatAcceptSignature } from "./accept-
|
|
7
|
-
import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-
|
|
8
|
-
import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-
|
|
9
|
-
import { t as getAuthenticatedDocumentLoader } from "./docloader-
|
|
10
|
-
import { n as kvCache } from "./kv-cache-
|
|
11
|
-
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-
|
|
12
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner
|
|
13
|
-
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-
|
|
14
|
-
import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-
|
|
15
|
-
import { t as getNodeInfo } from "./client-
|
|
16
|
-
import { t as nodeInfoToJson } from "./types-
|
|
17
|
-
import { n as
|
|
4
|
+
import { n as version, t as name } from "./deno-BUzynMVz.mjs";
|
|
5
|
+
import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-B5vvJYMV.mjs";
|
|
6
|
+
import { t as formatAcceptSignature } from "./accept-CPkZzmGN.mjs";
|
|
7
|
+
import { a as importJwk, o as validateCryptoKey, t as exportJwk } from "./key-DdP4HxTK.mjs";
|
|
8
|
+
import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-CDaMGwCP.mjs";
|
|
9
|
+
import { t as getAuthenticatedDocumentLoader } from "./docloader-jQPthO4U.mjs";
|
|
10
|
+
import { n as kvCache } from "./kv-cache-DSjv5Aeh.mjs";
|
|
11
|
+
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-CuOEh5aB.mjs";
|
|
12
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner--n8rmG51.mjs";
|
|
13
|
+
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-L_DbOaFe.mjs";
|
|
14
|
+
import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-dhtwaP4z.mjs";
|
|
15
|
+
import { t as getNodeInfo } from "./client-ByXmQhYD.mjs";
|
|
16
|
+
import { t as nodeInfoToJson } from "./types-J53Kw7so.mjs";
|
|
17
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-CTQ30Wbe.mjs";
|
|
18
|
+
import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-Bj-7Sl7u.mjs";
|
|
18
19
|
import { t as CircuitBreaker } from "./circuit-breaker-CSWsyoef.mjs";
|
|
19
20
|
import { t as buildCollectionSynchronizationHeader } from "./collection-Cc3DVAhE.mjs";
|
|
20
21
|
import { t as KvKeyCache } from "./keycache-BeU0LCII.mjs";
|
|
21
22
|
import { t as acceptsJsonLd } from "./negotiation-DDstyBvc.mjs";
|
|
22
|
-
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-
|
|
23
|
+
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-gfUaZjGU.mjs";
|
|
23
24
|
import { t as createExponentialBackoffPolicy } from "./retry-CXg_MBI-.mjs";
|
|
24
|
-
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-kst2L0Df.mjs";
|
|
25
25
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
26
26
|
import { RouterError } from "@fedify/uri-template";
|
|
27
27
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
@@ -30,6 +30,7 @@ import { SpanKind, SpanStatusCode, context, metrics, propagation, trace } from "
|
|
|
30
30
|
import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
|
|
31
31
|
import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_HEADER, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
|
|
32
32
|
import { uniq } from "es-toolkit";
|
|
33
|
+
import { DataPointType, MeterProvider as MeterProvider$1, MetricReader } from "@opentelemetry/sdk-metrics";
|
|
33
34
|
import { domainToASCII } from "node:url";
|
|
34
35
|
//#region src/compat/transformers.ts
|
|
35
36
|
const logger$1 = getLogger([
|
|
@@ -156,6 +157,201 @@ function handleNodeInfoJrd(_request, context) {
|
|
|
156
157
|
return Promise.resolve(response);
|
|
157
158
|
}
|
|
158
159
|
//#endregion
|
|
160
|
+
//#region src/federation/bench.ts
|
|
161
|
+
/**
|
|
162
|
+
* Metric reader owned by `benchmarkMode`.
|
|
163
|
+
* @since 2.3.0
|
|
164
|
+
*/
|
|
165
|
+
var BenchmarkMetricReader = class extends MetricReader {
|
|
166
|
+
onShutdown() {
|
|
167
|
+
return Promise.resolve();
|
|
168
|
+
}
|
|
169
|
+
onForceFlush() {
|
|
170
|
+
return Promise.resolve();
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Creates the in-process OpenTelemetry meter provider used by benchmark mode.
|
|
175
|
+
* @returns The meter provider and the metric reader attached to it.
|
|
176
|
+
* @since 2.3.0
|
|
177
|
+
*/
|
|
178
|
+
function createBenchmarkMeterProvider() {
|
|
179
|
+
const reader = new BenchmarkMetricReader();
|
|
180
|
+
return {
|
|
181
|
+
meterProvider: new MeterProvider$1({ readers: [reader] }),
|
|
182
|
+
reader
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Collects and serializes benchmark-mode metrics from a benchmark reader.
|
|
187
|
+
* @param reader The benchmark metric reader to collect from.
|
|
188
|
+
* @returns A server metric snapshot with any collection errors stringified.
|
|
189
|
+
* @since 2.3.0
|
|
190
|
+
*/
|
|
191
|
+
async function collectBenchmarkMetrics(reader) {
|
|
192
|
+
const result = await reader.collect();
|
|
193
|
+
return {
|
|
194
|
+
version: 1,
|
|
195
|
+
source: "server",
|
|
196
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
197
|
+
scopeMetrics: serializeScopeMetrics(result.resourceMetrics),
|
|
198
|
+
errors: result.errors.map((error) => String(error))
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Handles `GET /.well-known/fedify/bench/stats`.
|
|
203
|
+
* @param request The HTTP request to handle.
|
|
204
|
+
* @param reader The benchmark metric reader to collect from.
|
|
205
|
+
* @returns A JSON metric snapshot response, or `405 Method Not Allowed`.
|
|
206
|
+
* @since 2.3.0
|
|
207
|
+
*/
|
|
208
|
+
async function handleBenchmarkStats(request, reader) {
|
|
209
|
+
if (request.method !== "GET") return new Response("Method not allowed", {
|
|
210
|
+
status: 405,
|
|
211
|
+
headers: { "Allow": "GET" }
|
|
212
|
+
});
|
|
213
|
+
return jsonResponse(await collectBenchmarkMetrics(reader));
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Handles `POST /.well-known/fedify/bench/trigger`.
|
|
217
|
+
*
|
|
218
|
+
* The handler validates a benchmark trigger request, checks recipients against
|
|
219
|
+
* server-controlled trigger options, and calls `Context.sendActivity()` to use
|
|
220
|
+
* the target's normal outbox path.
|
|
221
|
+
* @param request The HTTP request to handle.
|
|
222
|
+
* @param context The Fedify context used to resolve actors and send activity.
|
|
223
|
+
* @param options Server-controlled benchmark trigger delivery options.
|
|
224
|
+
* @returns A JSON response describing the sent activity, or a validation error.
|
|
225
|
+
* @since 2.3.0
|
|
226
|
+
*/
|
|
227
|
+
async function handleBenchmarkTrigger(request, context, options = {}) {
|
|
228
|
+
if (request.method !== "POST") return new Response("Method not allowed", {
|
|
229
|
+
status: 405,
|
|
230
|
+
headers: { "Allow": "POST" }
|
|
231
|
+
});
|
|
232
|
+
let json;
|
|
233
|
+
try {
|
|
234
|
+
json = await request.json();
|
|
235
|
+
} catch {
|
|
236
|
+
return jsonResponse({ error: "Invalid JSON request body." }, 400);
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
const body = asRecord(json, "request body");
|
|
240
|
+
const sender = parseSender(body.sender);
|
|
241
|
+
const recipients = await parseRecipients(body.recipients, context);
|
|
242
|
+
const activity = await parseActivity(body.activity, context);
|
|
243
|
+
if (activity.id == null) throw new BenchmarkTriggerError("activity must have an id.");
|
|
244
|
+
const activityId = activity.id.href;
|
|
245
|
+
const inboxes = extractInboxes({ recipients });
|
|
246
|
+
const inboxUrls = Object.keys(inboxes);
|
|
247
|
+
if (inboxUrls.length < 1) throw new BenchmarkTriggerError("No valid recipient inboxes found. The recipients list must not be empty.");
|
|
248
|
+
const unsafeInboxes = options.allowUnsafeRecipients ? [] : inboxUrls.filter((inbox) => !options.sinks?.has(inbox));
|
|
249
|
+
if (unsafeInboxes.length > 0) return jsonResponse({
|
|
250
|
+
error: "unsafe_recipient",
|
|
251
|
+
unsafeInboxes
|
|
252
|
+
}, 403);
|
|
253
|
+
await context.sendActivity(sender, recipients, activity);
|
|
254
|
+
return jsonResponse({
|
|
255
|
+
version: 1,
|
|
256
|
+
activityId,
|
|
257
|
+
queueCorrelationId: activityId,
|
|
258
|
+
recipientCount: recipients.length,
|
|
259
|
+
inboxCount: inboxUrls.length
|
|
260
|
+
}, 202);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (error instanceof BenchmarkTriggerError) return jsonResponse({ error: error.message }, error.status);
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
var BenchmarkTriggerError = class extends Error {
|
|
267
|
+
status;
|
|
268
|
+
constructor(message, status = 400) {
|
|
269
|
+
super(message);
|
|
270
|
+
this.status = status;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
function parseSender(value) {
|
|
274
|
+
const sender = asRecord(value, "sender");
|
|
275
|
+
if (typeof sender.identifier === "string") return { identifier: sender.identifier };
|
|
276
|
+
if (typeof sender.username === "string") return { username: sender.username };
|
|
277
|
+
throw new BenchmarkTriggerError("sender must be { identifier } or { username }.");
|
|
278
|
+
}
|
|
279
|
+
async function parseRecipients(value, context) {
|
|
280
|
+
if (!Array.isArray(value)) throw new BenchmarkTriggerError("recipients must be an array.");
|
|
281
|
+
return await Promise.all(value.map(async (item) => {
|
|
282
|
+
let object;
|
|
283
|
+
try {
|
|
284
|
+
object = await Object$1.fromJsonLd(item, {
|
|
285
|
+
documentLoader: context.documentLoader,
|
|
286
|
+
contextLoader: context.contextLoader
|
|
287
|
+
});
|
|
288
|
+
} catch (error) {
|
|
289
|
+
throw new BenchmarkTriggerError(`Invalid ActivityPub recipient: ${error}`);
|
|
290
|
+
}
|
|
291
|
+
if (!isRecipient(object)) throw new BenchmarkTriggerError("each recipient must be an ActivityPub actor.");
|
|
292
|
+
const recipient = object;
|
|
293
|
+
if (recipient.id == null || recipient.inboxId == null) throw new BenchmarkTriggerError("each recipient must have id and inbox properties.");
|
|
294
|
+
return recipient;
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
function isRecipient(value) {
|
|
298
|
+
return value != null && typeof value === "object" && "id" in value && "inboxId" in value;
|
|
299
|
+
}
|
|
300
|
+
async function parseActivity(value, context) {
|
|
301
|
+
try {
|
|
302
|
+
return await Activity.fromJsonLd(value, {
|
|
303
|
+
documentLoader: context.documentLoader,
|
|
304
|
+
contextLoader: context.contextLoader
|
|
305
|
+
});
|
|
306
|
+
} catch (error) {
|
|
307
|
+
throw new BenchmarkTriggerError(`Invalid ActivityPub activity: ${error}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function asRecord(value, name) {
|
|
311
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) throw new BenchmarkTriggerError(`${name} must be an object.`);
|
|
312
|
+
return value;
|
|
313
|
+
}
|
|
314
|
+
function jsonResponse(body, status = 200) {
|
|
315
|
+
return new Response(JSON.stringify(body), {
|
|
316
|
+
status,
|
|
317
|
+
headers: { "Content-Type": "application/json" }
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
function serializeScopeMetrics(resourceMetrics) {
|
|
321
|
+
return resourceMetrics.scopeMetrics.map(serializeScope);
|
|
322
|
+
}
|
|
323
|
+
function serializeScope(scopeMetrics) {
|
|
324
|
+
return {
|
|
325
|
+
scope: {
|
|
326
|
+
name: scopeMetrics.scope.name,
|
|
327
|
+
version: scopeMetrics.scope.version
|
|
328
|
+
},
|
|
329
|
+
metrics: scopeMetrics.metrics.map(serializeMetric)
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function serializeMetric(metric) {
|
|
333
|
+
return {
|
|
334
|
+
name: metric.descriptor.name,
|
|
335
|
+
description: metric.descriptor.description,
|
|
336
|
+
unit: metric.descriptor.unit,
|
|
337
|
+
dataPointType: serializeDataPointType(metric.dataPointType),
|
|
338
|
+
dataPoints: metric.dataPoints.map((point) => ({
|
|
339
|
+
attributes: { ...point.attributes },
|
|
340
|
+
startTime: point.startTime,
|
|
341
|
+
endTime: point.endTime,
|
|
342
|
+
value: point.value
|
|
343
|
+
}))
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function serializeDataPointType(dataPointType) {
|
|
347
|
+
switch (dataPointType) {
|
|
348
|
+
case DataPointType.HISTOGRAM: return "histogram";
|
|
349
|
+
case DataPointType.EXPONENTIAL_HISTOGRAM: return "exponential_histogram";
|
|
350
|
+
case DataPointType.GAUGE: return "gauge";
|
|
351
|
+
case DataPointType.SUM: return "sum";
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
//#endregion
|
|
159
355
|
//#region src/federation/inbox.ts
|
|
160
356
|
async function routeActivity({ context: ctx, json, originalJson, normalizedActivity, ldSignatureVerified, activity, recipient, inboxListeners, inboxContextFactory, listenerInboxContextFactory, inboxErrorHandler, kv, kvPrefixes, queue, span, meterProvider, tracerProvider, idempotencyStrategy }) {
|
|
161
357
|
const logger = getLogger([
|
|
@@ -2085,6 +2281,7 @@ async function handleWebFingerInternal(request, { context, host, actorDispatcher
|
|
|
2085
2281
|
//#endregion
|
|
2086
2282
|
//#region src/federation/middleware.ts
|
|
2087
2283
|
const circuitBreakerCasWarningKvStores = /* @__PURE__ */ new WeakSet();
|
|
2284
|
+
let nextQueueDepthGaugeSourceId = 0;
|
|
2088
2285
|
const retryAfterHttpDate = /* @__PURE__ */ new RegExp("^(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), \\d{2} (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \\d{4} \\d{2}:\\d{2}:\\d{2} GMT|(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), \\d{2}-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\\d{2} \\d{2}:\\d{2}:\\d{2} GMT|(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun) (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (?: \\d|\\d{2}) \\d{2}:\\d{2}:\\d{2} \\d{4})$");
|
|
2089
2286
|
function parseRetryAfter(headers, now = Temporal.Now.instant()) {
|
|
2090
2287
|
const value = headers.get("Retry-After");
|
|
@@ -2113,6 +2310,54 @@ function parseRetryAfterDuration(durationLike) {
|
|
|
2113
2310
|
function clampNegativeDelay(delay) {
|
|
2114
2311
|
return delay.sign < 0 ? Temporal.Duration.from({ seconds: 0 }) : delay;
|
|
2115
2312
|
}
|
|
2313
|
+
function getBenchmarkRelaxations(allowPrivateAddress, signatureTimeWindow) {
|
|
2314
|
+
const relaxations = [];
|
|
2315
|
+
if (allowPrivateAddress) relaxations.push({
|
|
2316
|
+
protection: "private_address_checks",
|
|
2317
|
+
effect: "disabled",
|
|
2318
|
+
effectiveValue: true
|
|
2319
|
+
});
|
|
2320
|
+
if (signatureTimeWindow === false) relaxations.push({
|
|
2321
|
+
protection: "http_signature_time_window",
|
|
2322
|
+
effect: "disabled",
|
|
2323
|
+
effectiveValue: false,
|
|
2324
|
+
secureDefaultSeconds: 3600
|
|
2325
|
+
});
|
|
2326
|
+
else try {
|
|
2327
|
+
const seconds = Temporal.Duration.from(signatureTimeWindow).total({ unit: "seconds" });
|
|
2328
|
+
if (seconds !== 3600) relaxations.push({
|
|
2329
|
+
protection: "http_signature_time_window",
|
|
2330
|
+
effect: "changed",
|
|
2331
|
+
effectiveSeconds: seconds,
|
|
2332
|
+
secureDefaultSeconds: 3600
|
|
2333
|
+
});
|
|
2334
|
+
} catch {}
|
|
2335
|
+
return relaxations;
|
|
2336
|
+
}
|
|
2337
|
+
function formatBenchmarkRelaxations(relaxations) {
|
|
2338
|
+
if (relaxations.length < 1) return "no benchmark-only protections relaxed";
|
|
2339
|
+
return relaxations.map((relaxation) => {
|
|
2340
|
+
switch (relaxation.protection) {
|
|
2341
|
+
case "private_address_checks": return "private address checks disabled (allowPrivateAddress=true)";
|
|
2342
|
+
case "http_signature_time_window":
|
|
2343
|
+
if (relaxation.effect === "disabled") return `HTTP Signature time window disabled (signatureTimeWindow=false)`;
|
|
2344
|
+
return `HTTP Signature time window set to ${relaxation.effectiveSeconds}s (secure default: ${relaxation.secureDefaultSeconds}s)`;
|
|
2345
|
+
}
|
|
2346
|
+
}).join("; ");
|
|
2347
|
+
}
|
|
2348
|
+
function getBenchmarkTriggerOptions(benchmarkOptions) {
|
|
2349
|
+
const sinks = benchmarkOptions.triggerSinks?.map((sink) => {
|
|
2350
|
+
try {
|
|
2351
|
+
return new URL(sink).href;
|
|
2352
|
+
} catch {
|
|
2353
|
+
throw new TypeError("benchmarkMode.triggerSinks must contain only URLs.");
|
|
2354
|
+
}
|
|
2355
|
+
});
|
|
2356
|
+
return {
|
|
2357
|
+
sinks: sinks == null ? void 0 : new Set(sinks),
|
|
2358
|
+
allowUnsafeRecipients: benchmarkOptions.allowUnsafeTriggerRecipients === true
|
|
2359
|
+
};
|
|
2360
|
+
}
|
|
2116
2361
|
function maxDelay(first, second) {
|
|
2117
2362
|
return Temporal.Duration.compare(first, second) >= 0 ? first : second;
|
|
2118
2363
|
}
|
|
@@ -2149,8 +2394,10 @@ function isPermanentInboxParseError(error) {
|
|
|
2149
2394
|
}
|
|
2150
2395
|
/**
|
|
2151
2396
|
* Create a new {@link Federation} instance.
|
|
2152
|
-
* @param
|
|
2397
|
+
* @param options Parameters for initializing the instance.
|
|
2153
2398
|
* @returns A new {@link Federation} instance.
|
|
2399
|
+
* @throws {TypeError} If benchmark mode and `meterProvider` are both
|
|
2400
|
+
* specified.
|
|
2154
2401
|
* @since 0.10.0
|
|
2155
2402
|
*/
|
|
2156
2403
|
function createFederation(options) {
|
|
@@ -2184,8 +2431,31 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2184
2431
|
_meterProvider;
|
|
2185
2432
|
firstKnock;
|
|
2186
2433
|
inboxChallengePolicy;
|
|
2434
|
+
benchmarkMode;
|
|
2435
|
+
benchmarkMetricReader;
|
|
2436
|
+
benchmarkTriggerOptions;
|
|
2437
|
+
#queueDepthGaugeSourceId = `fedify-${(++nextQueueDepthGaugeSourceId).toString(36)}`;
|
|
2438
|
+
#queueDepthGaugeEntries = [];
|
|
2439
|
+
#queueDepthGaugeMeterProvider;
|
|
2187
2440
|
constructor(options) {
|
|
2188
2441
|
super();
|
|
2442
|
+
const benchmarkMode = options.benchmarkMode != null && options.benchmarkMode !== false;
|
|
2443
|
+
const benchmarkOptions = typeof options.benchmarkMode === "object" ? options.benchmarkMode : {};
|
|
2444
|
+
const hasCustomLoaderFactory = options.documentLoaderFactory != null || options.contextLoaderFactory != null;
|
|
2445
|
+
const allowPrivateAddress = options.allowPrivateAddress ?? (benchmarkMode && !hasCustomLoaderFactory ? true : false);
|
|
2446
|
+
const signatureTimeWindow = options.signatureTimeWindow ?? (benchmarkMode ? false : { hours: 1 });
|
|
2447
|
+
if (benchmarkMode && options.meterProvider != null) throw new TypeError("benchmarkMode requires Fedify to own the meterProvider; OpenTelemetry metric readers cannot be added after a MeterProvider is constructed.");
|
|
2448
|
+
if (benchmarkMode) {
|
|
2449
|
+
const relaxations = getBenchmarkRelaxations(allowPrivateAddress, signatureTimeWindow);
|
|
2450
|
+
const relaxationSummary = formatBenchmarkRelaxations(relaxations);
|
|
2451
|
+
getLogger([
|
|
2452
|
+
"fedify",
|
|
2453
|
+
"federation",
|
|
2454
|
+
"benchmark"
|
|
2455
|
+
]).warn(`Fedify benchmarkMode is enabled; ${relaxationSummary}. Benchmark endpoints are active and must not be used in production.`, { relaxations });
|
|
2456
|
+
}
|
|
2457
|
+
this.benchmarkMode = benchmarkMode;
|
|
2458
|
+
this.benchmarkTriggerOptions = benchmarkMode ? getBenchmarkTriggerOptions(benchmarkOptions) : {};
|
|
2189
2459
|
this.kv = options.kv;
|
|
2190
2460
|
this.kvPrefixes = {
|
|
2191
2461
|
activityIdempotence: ["_fedify", "activityIdempotence"],
|
|
@@ -2253,13 +2523,13 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2253
2523
|
}
|
|
2254
2524
|
this.router.trailingSlashInsensitive = options.trailingSlashInsensitive ?? false;
|
|
2255
2525
|
this._initializeRouter();
|
|
2256
|
-
if (options.allowPrivateAddress || options.userAgent != null) {
|
|
2526
|
+
if (options.allowPrivateAddress === true || options.userAgent != null) {
|
|
2257
2527
|
if (options.documentLoaderFactory != null) throw new TypeError("Cannot set documentLoaderFactory with allowPrivateAddress or userAgent options.");
|
|
2258
2528
|
if (options.contextLoaderFactory != null) throw new TypeError("Cannot set contextLoaderFactory with allowPrivateAddress or userAgent options.");
|
|
2259
2529
|
if (options.authenticatedDocumentLoaderFactory != null) throw new TypeError("Cannot set authenticatedDocumentLoaderFactory with allowPrivateAddress or userAgent options.");
|
|
2260
2530
|
}
|
|
2261
|
-
const {
|
|
2262
|
-
this.allowPrivateAddress = allowPrivateAddress
|
|
2531
|
+
const { userAgent } = options;
|
|
2532
|
+
this.allowPrivateAddress = allowPrivateAddress;
|
|
2263
2533
|
const userDocumentLoaderFactory = options.documentLoaderFactory;
|
|
2264
2534
|
const userContextLoaderFactory = options.contextLoaderFactory;
|
|
2265
2535
|
const userAuthFactory = options.authenticatedDocumentLoaderFactory;
|
|
@@ -2307,25 +2577,55 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2307
2577
|
this.userAgent = userAgent;
|
|
2308
2578
|
this.onOutboxError = options.onOutboxError;
|
|
2309
2579
|
this.permanentFailureStatusCodes = options.permanentFailureStatusCodes ?? [404, 410];
|
|
2310
|
-
this.signatureTimeWindow =
|
|
2580
|
+
this.signatureTimeWindow = signatureTimeWindow;
|
|
2311
2581
|
this.skipSignatureVerification = options.skipSignatureVerification ?? false;
|
|
2312
2582
|
this.inboxChallengePolicy = options.inboxChallengePolicy;
|
|
2313
2583
|
this.outboxRetryPolicy = options.outboxRetryPolicy ?? createExponentialBackoffPolicy();
|
|
2314
2584
|
this.inboxRetryPolicy = options.inboxRetryPolicy ?? createExponentialBackoffPolicy();
|
|
2315
2585
|
this.activityTransformers = options.activityTransformers ?? getDefaultActivityTransformers();
|
|
2316
2586
|
this._tracerProvider = options.tracerProvider;
|
|
2317
|
-
|
|
2587
|
+
if (benchmarkMode) {
|
|
2588
|
+
const benchmarkMetrics = createBenchmarkMeterProvider();
|
|
2589
|
+
this._meterProvider = benchmarkMetrics.meterProvider;
|
|
2590
|
+
this.benchmarkMetricReader = benchmarkMetrics.reader;
|
|
2591
|
+
} else this._meterProvider = options.meterProvider;
|
|
2592
|
+
this.#queueDepthGaugeEntries = [
|
|
2593
|
+
{
|
|
2594
|
+
role: "inbox",
|
|
2595
|
+
queue: this.inboxQueue
|
|
2596
|
+
},
|
|
2597
|
+
{
|
|
2598
|
+
role: "outbox",
|
|
2599
|
+
queue: this.outboxQueue
|
|
2600
|
+
},
|
|
2601
|
+
{
|
|
2602
|
+
role: "fanout",
|
|
2603
|
+
queue: this.fanoutQueue
|
|
2604
|
+
}
|
|
2605
|
+
];
|
|
2606
|
+
this.#registerQueueDepthGauge(this._meterProvider ?? metrics.getMeterProvider());
|
|
2318
2607
|
this.firstKnock = options.firstKnock;
|
|
2319
2608
|
}
|
|
2320
2609
|
get tracerProvider() {
|
|
2321
2610
|
return this._tracerProvider ?? trace.getTracerProvider();
|
|
2322
2611
|
}
|
|
2323
2612
|
get meterProvider() {
|
|
2324
|
-
|
|
2613
|
+
const meterProvider = this._meterProvider ?? metrics.getMeterProvider();
|
|
2614
|
+
this.#registerQueueDepthGauge(meterProvider);
|
|
2615
|
+
return meterProvider;
|
|
2616
|
+
}
|
|
2617
|
+
#registerQueueDepthGauge(meterProvider) {
|
|
2618
|
+
if (meterProvider === this.#queueDepthGaugeMeterProvider) return;
|
|
2619
|
+
registerQueueDepthGauge(meterProvider, this.#queueDepthGaugeEntries, { sourceId: this.#queueDepthGaugeSourceId });
|
|
2620
|
+
this.#queueDepthGaugeMeterProvider = meterProvider;
|
|
2325
2621
|
}
|
|
2326
2622
|
_initializeRouter() {
|
|
2327
2623
|
this.router.add("/.well-known/webfinger", "webfinger");
|
|
2328
2624
|
this.router.add("/.well-known/nodeinfo", "nodeInfoJrd");
|
|
2625
|
+
if (this.benchmarkMode) {
|
|
2626
|
+
this.router.add("/.well-known/fedify/bench/stats", "benchmarkStats");
|
|
2627
|
+
this.router.add("/.well-known/fedify/bench/trigger", "benchmarkTrigger");
|
|
2628
|
+
}
|
|
2329
2629
|
}
|
|
2330
2630
|
_getTracer() {
|
|
2331
2631
|
return this.tracerProvider.getTracer(name, version);
|
|
@@ -3337,6 +3637,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3337
3637
|
context,
|
|
3338
3638
|
nodeInfoDispatcher: this.nodeInfoDispatcher
|
|
3339
3639
|
});
|
|
3640
|
+
case "benchmarkStats": return await handleBenchmarkStats(request, this.benchmarkMetricReader);
|
|
3641
|
+
case "benchmarkTrigger": return await handleBenchmarkTrigger(request, context, this.benchmarkTriggerOptions);
|
|
3340
3642
|
}
|
|
3341
3643
|
if (request.method !== "POST" && !acceptsJsonLd(request)) {
|
|
3342
3644
|
metricState.endpoint = "not_acceptable";
|
|
@@ -3576,6 +3878,8 @@ function getEndpointCategory(routeName) {
|
|
|
3576
3878
|
case "liked": return "liked";
|
|
3577
3879
|
case "featured": return "featured";
|
|
3578
3880
|
case "featuredTags": return "featured_tags";
|
|
3881
|
+
case "benchmarkStats":
|
|
3882
|
+
case "benchmarkTrigger": return "benchmark";
|
|
3579
3883
|
default: return "not_found";
|
|
3580
3884
|
}
|
|
3581
3885
|
}
|
|
@@ -4646,4 +4950,4 @@ function getRequestId(request) {
|
|
|
4646
4950
|
return `req_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
4647
4951
|
}
|
|
4648
4952
|
//#endregion
|
|
4649
|
-
export {
|
|
4953
|
+
export { handleNodeInfo as _, OutboxContextImpl as a, autoIdAssigner as b, handleActor as c, handleInbox as d, handleObject as f, handleBenchmarkTrigger as g, respondWithObjectIfAcceptable as h, KvSpecDeterminer as i, handleCollection as l, respondWithObject as m, FederationImpl as n, createFederation as o, handleOutbox as p, InboxContextImpl as r, handleWebFinger as s, ContextImpl as t, handleCustomCollection as u, handleNodeInfoJrd as v, actorDehydrator as y };
|