@fedify/fedify 2.3.0-dev.1158 → 2.3.0-dev.1172
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-B66L9i5E.mjs → builder-JoFBmqfM.mjs} +2 -2
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{deno-O_rwum1q.mjs → deno-Cb_y5qEi.mjs} +1 -1
- package/dist/{docloader-Ct8PhKFS.mjs → docloader-Bv4TW6eo.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +305 -3
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +80 -1
- package/dist/federation/middleware.test.mjs +20 -6
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{http-BoRhhcgB.mjs → http--aE0vk2u.mjs} +3 -3
- package/dist/{http-CFP8WMMv.js → http-C0XZv7iH.js} +92 -2
- package/dist/{http-DlPd_LYM.cjs → http-D_HNhC57.cjs} +115 -1
- package/dist/{key-DyATZSWG.mjs → key-Cl_bixZo.mjs} +2 -2
- package/dist/{kv-cache-BJo6COYN.cjs → kv-cache-CdOuPFgC.cjs} +1 -1
- package/dist/{kv-cache-DeJE8EeD.mjs → kv-cache-DQUblF4f.mjs} +1 -1
- package/dist/{kv-cache-dH0biV98.js → kv-cache-DsbVBK7Y.js} +1 -1
- package/dist/{ld-B8wjsKDJ.mjs → ld-xVq6y31b.mjs} +3 -3
- package/dist/{metrics-oMUWaw6W.mjs → metrics-CKticT28.mjs} +92 -2
- package/dist/{middleware-DwZ1ofL9.js → middleware-BSuEI4Qf.js} +318 -107
- package/dist/{middleware-BzOa0ncb.mjs → middleware-BmPIKmb4.mjs} +1 -1
- package/dist/{middleware-xtTRaiJL.mjs → middleware-DHM2Pjqf.mjs} +327 -116
- package/dist/{middleware-CcJyVEpv.cjs → middleware-hxnyAewn.cjs} +318 -107
- package/dist/mod.cjs +4 -4
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-BxjgK8PG.mjs → owner-DmU2qEh_.mjs} +2 -2
- package/dist/{proof-42Q9NiqN.mjs → proof-1XBgQ0Z0.mjs} +3 -3
- package/dist/{proof-B_6gAVQ2.js → proof-CmS6yxgt.js} +1 -1
- package/dist/{proof-CfttNzWW.cjs → proof-wm6UxUoM.cjs} +1 -1
- package/dist/{send-R1_K46CH.mjs → send-CmtB8w5D.mjs} +3 -3
- 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/proof.test.mjs +1 -1
- package/dist/{temporal-8kDX3E4q.mjs → temporal-DE9_a2nI.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 +6 -6
|
@@ -2,10 +2,10 @@ const { Temporal } = require("@js-temporal/polyfill");
|
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
const require_chunk = require("./chunk-DDcVe30Y.cjs");
|
|
4
4
|
const require_transformers = require("./transformers-NeAONrAq.cjs");
|
|
5
|
-
const require_http = require("./http-
|
|
6
|
-
const require_proof = require("./proof-
|
|
5
|
+
const require_http = require("./http-D_HNhC57.cjs");
|
|
6
|
+
const require_proof = require("./proof-wm6UxUoM.cjs");
|
|
7
7
|
const require_types = require("./types-KC4QAoxe.cjs");
|
|
8
|
-
const require_kv_cache = require("./kv-cache-
|
|
8
|
+
const require_kv_cache = require("./kv-cache-CdOuPFgC.cjs");
|
|
9
9
|
let _logtape_logtape = require("@logtape/logtape");
|
|
10
10
|
let _fedify_uri_template = require("@fedify/uri-template");
|
|
11
11
|
let _fedify_vocab = require("@fedify/vocab");
|
|
@@ -1212,6 +1212,33 @@ async function handleObject(request, { values, context, objectDispatcher, author
|
|
|
1212
1212
|
Vary: "Accept"
|
|
1213
1213
|
} });
|
|
1214
1214
|
}
|
|
1215
|
+
const BUILT_IN_COLLECTION_METRIC_KINDS = new Set([
|
|
1216
|
+
"inbox",
|
|
1217
|
+
"outbox",
|
|
1218
|
+
"following",
|
|
1219
|
+
"followers",
|
|
1220
|
+
"liked",
|
|
1221
|
+
"featured",
|
|
1222
|
+
"featured_tags"
|
|
1223
|
+
]);
|
|
1224
|
+
function getCollectionMetricKind(name) {
|
|
1225
|
+
const normalized = name.trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/\s+/g, "_");
|
|
1226
|
+
return BUILT_IN_COLLECTION_METRIC_KINDS.has(normalized) ? normalized : "custom";
|
|
1227
|
+
}
|
|
1228
|
+
function collectionAttributes(base, result, response) {
|
|
1229
|
+
return {
|
|
1230
|
+
...base,
|
|
1231
|
+
result,
|
|
1232
|
+
...response == null ? {} : { statusCode: response.status }
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
1236
|
+
const attrs = collectionAttributes(base, result, options.response);
|
|
1237
|
+
require_http.recordCollectionRequest(meterProvider, attrs);
|
|
1238
|
+
if (options.dispatchDurationMs != null) require_http.recordCollectionDispatchDuration(meterProvider, options.dispatchDurationMs, attrs);
|
|
1239
|
+
if (options.itemCount != null) require_http.recordCollectionPageItems(meterProvider, options.itemCount, attrs);
|
|
1240
|
+
if (options.totalItems != null) require_http.recordCollectionTotalItems(meterProvider, options.totalItems, attrs);
|
|
1241
|
+
}
|
|
1215
1242
|
/**
|
|
1216
1243
|
* Handles a collection request.
|
|
1217
1244
|
* @template TItem The type of items in the collection.
|
|
@@ -1222,36 +1249,118 @@ async function handleObject(request, { values, context, objectDispatcher, author
|
|
|
1222
1249
|
* @param parameters The parameters for handling the collection.
|
|
1223
1250
|
* @returns A promise that resolves to an HTTP response.
|
|
1224
1251
|
*/
|
|
1225
|
-
async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound }) {
|
|
1252
|
+
async function handleCollection(request, { name: name$1, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
|
|
1226
1253
|
const spanName = name$1.trim().replace(/\s+/g, "_");
|
|
1227
1254
|
tracerProvider = tracerProvider ?? _opentelemetry_api.trace.getTracerProvider();
|
|
1228
1255
|
const tracer = tracerProvider.getTracer(require_http.name, require_http.version);
|
|
1229
1256
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1257
|
+
const metricBase = {
|
|
1258
|
+
kind: getCollectionMetricKind(name$1),
|
|
1259
|
+
page: cursor != null,
|
|
1260
|
+
dispatcher: "built_in"
|
|
1261
|
+
};
|
|
1262
|
+
let dispatchDurationMs;
|
|
1263
|
+
let itemCount;
|
|
1264
|
+
let totalItemCount;
|
|
1265
|
+
const finish = (response, result) => {
|
|
1266
|
+
recordCollectionMetrics(meterProvider, metricBase, result, {
|
|
1267
|
+
response,
|
|
1268
|
+
dispatchDurationMs,
|
|
1269
|
+
itemCount,
|
|
1270
|
+
totalItems: totalItemCount
|
|
1271
|
+
});
|
|
1272
|
+
return response;
|
|
1273
|
+
};
|
|
1274
|
+
try {
|
|
1275
|
+
if (collectionCallbacks == null) return finish(await onNotFound(request), "not_found");
|
|
1276
|
+
let collection;
|
|
1277
|
+
const baseUri = uriGetter(identifier);
|
|
1278
|
+
if (cursor == null) {
|
|
1279
|
+
const firstCursor = await collectionCallbacks.firstCursor?.(context, identifier);
|
|
1280
|
+
const totalItems = filter == null ? await collectionCallbacks.counter?.(context, identifier) : void 0;
|
|
1281
|
+
totalItemCount = totalItems == null ? void 0 : Number(totalItems);
|
|
1282
|
+
if (firstCursor == null) {
|
|
1283
|
+
const itemsOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection ${spanName}`, {
|
|
1284
|
+
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
1285
|
+
attributes: {
|
|
1286
|
+
"activitypub.collection.id": baseUri.href,
|
|
1287
|
+
"activitypub.collection.type": _fedify_vocab.OrderedCollection.typeId.href
|
|
1288
|
+
}
|
|
1289
|
+
}, async (span) => {
|
|
1290
|
+
if (totalItemCount != null) span.setAttribute("activitypub.collection.total_items", totalItemCount);
|
|
1291
|
+
const started = performance.now();
|
|
1292
|
+
try {
|
|
1293
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, null, filter);
|
|
1294
|
+
dispatchDurationMs = require_http.getDurationMs(started);
|
|
1295
|
+
if (page == null) {
|
|
1296
|
+
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
1297
|
+
return await onNotFound(request);
|
|
1298
|
+
}
|
|
1299
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
1300
|
+
itemCount = items.length;
|
|
1301
|
+
span.setAttribute("fedify.collection.items", itemCount);
|
|
1302
|
+
return items;
|
|
1303
|
+
} catch (e) {
|
|
1304
|
+
if (dispatchDurationMs == null) dispatchDurationMs = require_http.getDurationMs(started);
|
|
1305
|
+
span.setStatus({
|
|
1306
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
1307
|
+
message: String(e)
|
|
1308
|
+
});
|
|
1309
|
+
throw e;
|
|
1310
|
+
} finally {
|
|
1311
|
+
span.end();
|
|
1312
|
+
}
|
|
1313
|
+
});
|
|
1314
|
+
if (itemsOrResponse instanceof Response) return finish(itemsOrResponse, "not_found");
|
|
1315
|
+
collection = new _fedify_vocab.OrderedCollection({
|
|
1316
|
+
id: baseUri,
|
|
1317
|
+
totalItems: totalItemCount ?? null,
|
|
1318
|
+
items: itemsOrResponse
|
|
1319
|
+
});
|
|
1320
|
+
} else {
|
|
1321
|
+
const lastCursor = await collectionCallbacks.lastCursor?.(context, identifier);
|
|
1322
|
+
const first = new URL(context.url);
|
|
1323
|
+
first.searchParams.set("cursor", firstCursor);
|
|
1324
|
+
let last = null;
|
|
1325
|
+
if (lastCursor != null) {
|
|
1326
|
+
last = new URL(context.url);
|
|
1327
|
+
last.searchParams.set("cursor", lastCursor);
|
|
1328
|
+
}
|
|
1329
|
+
collection = new _fedify_vocab.OrderedCollection({
|
|
1330
|
+
id: baseUri,
|
|
1331
|
+
totalItems: totalItemCount ?? null,
|
|
1332
|
+
first,
|
|
1333
|
+
last
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
} else {
|
|
1337
|
+
const uri = new URL(baseUri);
|
|
1338
|
+
uri.searchParams.set("cursor", cursor);
|
|
1339
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
1238
1340
|
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
1239
1341
|
attributes: {
|
|
1240
|
-
"activitypub.collection.id":
|
|
1241
|
-
"activitypub.collection.type": _fedify_vocab.
|
|
1342
|
+
"activitypub.collection.id": uri.href,
|
|
1343
|
+
"activitypub.collection.type": _fedify_vocab.OrderedCollectionPage.typeId.href,
|
|
1344
|
+
"fedify.collection.cursor": cursor
|
|
1242
1345
|
}
|
|
1243
1346
|
}, async (span) => {
|
|
1244
|
-
|
|
1347
|
+
const started = performance.now();
|
|
1245
1348
|
try {
|
|
1246
|
-
const page = await collectionCallbacks.dispatcher(context, identifier,
|
|
1349
|
+
const page = await collectionCallbacks.dispatcher(context, identifier, cursor, filter);
|
|
1350
|
+
dispatchDurationMs = require_http.getDurationMs(started);
|
|
1247
1351
|
if (page == null) {
|
|
1248
1352
|
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
1249
1353
|
return await onNotFound(request);
|
|
1250
1354
|
}
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
|
|
1355
|
+
const items = filterCollectionItems(page.items, name$1, filterPredicate);
|
|
1356
|
+
itemCount = items.length;
|
|
1357
|
+
span.setAttribute("fedify.collection.items", itemCount);
|
|
1358
|
+
return {
|
|
1359
|
+
...page,
|
|
1360
|
+
items
|
|
1361
|
+
};
|
|
1254
1362
|
} catch (e) {
|
|
1363
|
+
if (dispatchDurationMs == null) dispatchDurationMs = require_http.getDurationMs(started);
|
|
1255
1364
|
span.setStatus({
|
|
1256
1365
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
1257
1366
|
message: String(e)
|
|
@@ -1261,87 +1370,44 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
1261
1370
|
span.end();
|
|
1262
1371
|
}
|
|
1263
1372
|
});
|
|
1264
|
-
if (
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
} else {
|
|
1271
|
-
const lastCursor = await collectionCallbacks.lastCursor?.(context, identifier);
|
|
1272
|
-
const first = new URL(context.url);
|
|
1273
|
-
first.searchParams.set("cursor", firstCursor);
|
|
1274
|
-
let last = null;
|
|
1275
|
-
if (lastCursor != null) {
|
|
1276
|
-
last = new URL(context.url);
|
|
1277
|
-
last.searchParams.set("cursor", lastCursor);
|
|
1278
|
-
}
|
|
1279
|
-
collection = new _fedify_vocab.OrderedCollection({
|
|
1280
|
-
id: baseUri,
|
|
1281
|
-
totalItems: totalItems == null ? null : Number(totalItems),
|
|
1282
|
-
first,
|
|
1283
|
-
last
|
|
1284
|
-
});
|
|
1285
|
-
}
|
|
1286
|
-
} else {
|
|
1287
|
-
const uri = new URL(baseUri);
|
|
1288
|
-
uri.searchParams.set("cursor", cursor);
|
|
1289
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$1}`, {
|
|
1290
|
-
kind: _opentelemetry_api.SpanKind.SERVER,
|
|
1291
|
-
attributes: {
|
|
1292
|
-
"activitypub.collection.id": uri.href,
|
|
1293
|
-
"activitypub.collection.type": _fedify_vocab.OrderedCollectionPage.typeId.href,
|
|
1294
|
-
"fedify.collection.cursor": cursor
|
|
1373
|
+
if (pageOrResponse instanceof Response) return finish(pageOrResponse, "not_found");
|
|
1374
|
+
const { items, prevCursor, nextCursor } = pageOrResponse;
|
|
1375
|
+
let prev = null;
|
|
1376
|
+
if (prevCursor != null) {
|
|
1377
|
+
prev = new URL(context.url);
|
|
1378
|
+
prev.searchParams.set("cursor", prevCursor);
|
|
1295
1379
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
|
|
1301
|
-
return await onNotFound(request);
|
|
1302
|
-
}
|
|
1303
|
-
span.setAttribute("fedify.collection.items", page.items.length);
|
|
1304
|
-
return page;
|
|
1305
|
-
} catch (e) {
|
|
1306
|
-
span.setStatus({
|
|
1307
|
-
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
1308
|
-
message: String(e)
|
|
1309
|
-
});
|
|
1310
|
-
throw e;
|
|
1311
|
-
} finally {
|
|
1312
|
-
span.end();
|
|
1380
|
+
let next = null;
|
|
1381
|
+
if (nextCursor != null) {
|
|
1382
|
+
next = new URL(context.url);
|
|
1383
|
+
next.searchParams.set("cursor", nextCursor);
|
|
1313
1384
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1385
|
+
const partOf = new URL(context.url);
|
|
1386
|
+
partOf.searchParams.delete("cursor");
|
|
1387
|
+
collection = new _fedify_vocab.OrderedCollectionPage({
|
|
1388
|
+
id: uri,
|
|
1389
|
+
prev,
|
|
1390
|
+
next,
|
|
1391
|
+
items,
|
|
1392
|
+
partOf
|
|
1393
|
+
});
|
|
1321
1394
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
next = new URL(context.url);
|
|
1325
|
-
next.searchParams.set("cursor", nextCursor);
|
|
1395
|
+
if (collectionCallbacks.authorizePredicate != null) {
|
|
1396
|
+
if (!await collectionCallbacks.authorizePredicate(context, identifier)) return finish(await onUnauthorized(request), "unauthorized");
|
|
1326
1397
|
}
|
|
1327
|
-
const
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1398
|
+
const jsonLd = await collection.toJsonLd(context);
|
|
1399
|
+
return finish(new Response(JSON.stringify(jsonLd), { headers: {
|
|
1400
|
+
"Content-Type": "application/activity+json",
|
|
1401
|
+
Vary: "Accept"
|
|
1402
|
+
} }), "served");
|
|
1403
|
+
} catch (e) {
|
|
1404
|
+
recordCollectionMetrics(meterProvider, metricBase, "error", {
|
|
1405
|
+
dispatchDurationMs,
|
|
1406
|
+
itemCount,
|
|
1407
|
+
totalItems: totalItemCount
|
|
1335
1408
|
});
|
|
1409
|
+
throw e;
|
|
1336
1410
|
}
|
|
1337
|
-
if (collectionCallbacks.authorizePredicate != null) {
|
|
1338
|
-
if (!await collectionCallbacks.authorizePredicate(context, identifier)) return await onUnauthorized(request);
|
|
1339
|
-
}
|
|
1340
|
-
const jsonLd = await collection.toJsonLd(context);
|
|
1341
|
-
return new Response(JSON.stringify(jsonLd), { headers: {
|
|
1342
|
-
"Content-Type": "application/activity+json",
|
|
1343
|
-
Vary: "Accept"
|
|
1344
|
-
} });
|
|
1345
1411
|
}
|
|
1346
1412
|
/**
|
|
1347
1413
|
* Filters collection items based on the provided predicate.
|
|
@@ -2044,11 +2110,31 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2044
2110
|
* @since 1.8.0
|
|
2045
2111
|
*/
|
|
2046
2112
|
const handleCustomCollection = exceptWrapper(_handleCustomCollection);
|
|
2047
|
-
|
|
2113
|
+
const pendingCollectionMetricRecorders = /* @__PURE__ */ new WeakMap();
|
|
2114
|
+
function deferPendingCollectionMetrics(error, recorder) {
|
|
2115
|
+
if (error == null || typeof error !== "object" && typeof error !== "function") return false;
|
|
2116
|
+
pendingCollectionMetricRecorders.set(error, recorder);
|
|
2117
|
+
return true;
|
|
2118
|
+
}
|
|
2119
|
+
function recordDeferredPendingCollectionMetrics(error, result, response) {
|
|
2120
|
+
if (error == null || typeof error !== "object" && typeof error !== "function") return;
|
|
2121
|
+
const recorder = pendingCollectionMetricRecorders.get(error);
|
|
2122
|
+
pendingCollectionMetricRecorders.delete(error);
|
|
2123
|
+
recorder?.(result, response);
|
|
2124
|
+
}
|
|
2125
|
+
async function _handleCustomCollection(request, { name, values, context, tracerProvider, meterProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
2048
2126
|
verifyDefined(callbacks);
|
|
2049
2127
|
await authIfNeeded(context, values, callbacks);
|
|
2050
2128
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
2051
|
-
|
|
2129
|
+
const handler = new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, meterProvider, _fedify_vocab.Collection, _fedify_vocab.CollectionPage, filterPredicate).fetchCollection(cursor);
|
|
2130
|
+
try {
|
|
2131
|
+
const response = await handler.toJsonLd().then(respondAsActivity);
|
|
2132
|
+
handler.recordPendingCollectionMetrics("served", response);
|
|
2133
|
+
return response;
|
|
2134
|
+
} catch (e) {
|
|
2135
|
+
if (!deferPendingCollectionMetrics(e, (result, response) => handler.recordPendingCollectionMetrics(result, response))) handler.recordPendingCollectionMetrics("error");
|
|
2136
|
+
throw e;
|
|
2137
|
+
}
|
|
2052
2138
|
}
|
|
2053
2139
|
/**
|
|
2054
2140
|
* Handles an ordered collection request.
|
|
@@ -2062,11 +2148,19 @@ async function _handleCustomCollection(request, { name, values, context, tracerP
|
|
|
2062
2148
|
* @since 1.8.0
|
|
2063
2149
|
*/
|
|
2064
2150
|
const handleOrderedCollection = exceptWrapper(_handleOrderedCollection);
|
|
2065
|
-
async function _handleOrderedCollection(request, { name, values, context, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
2151
|
+
async function _handleOrderedCollection(request, { name, values, context, tracerProvider, meterProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
2066
2152
|
verifyDefined(callbacks);
|
|
2067
2153
|
await authIfNeeded(context, values, callbacks);
|
|
2068
2154
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
2069
|
-
|
|
2155
|
+
const handler = new CustomCollectionHandler(name, values, context, callbacks, tracerProvider, meterProvider, _fedify_vocab.OrderedCollection, _fedify_vocab.OrderedCollectionPage, filterPredicate).fetchCollection(cursor);
|
|
2156
|
+
try {
|
|
2157
|
+
const response = await handler.toJsonLd().then(respondAsActivity);
|
|
2158
|
+
handler.recordPendingCollectionMetrics("served", response);
|
|
2159
|
+
return response;
|
|
2160
|
+
} catch (e) {
|
|
2161
|
+
if (!deferPendingCollectionMetrics(e, (result, response) => handler.recordPendingCollectionMetrics(result, response))) handler.recordPendingCollectionMetrics("error");
|
|
2162
|
+
throw e;
|
|
2163
|
+
}
|
|
2070
2164
|
}
|
|
2071
2165
|
/**
|
|
2072
2166
|
* Handling custom collections with support for pagination and filtering.
|
|
@@ -2086,6 +2180,7 @@ var CustomCollectionHandler = class {
|
|
|
2086
2180
|
context;
|
|
2087
2181
|
callbacks;
|
|
2088
2182
|
tracerProvider;
|
|
2183
|
+
meterProvider;
|
|
2089
2184
|
Collection;
|
|
2090
2185
|
CollectionPage;
|
|
2091
2186
|
filterPredicate;
|
|
@@ -2113,6 +2208,7 @@ var CustomCollectionHandler = class {
|
|
|
2113
2208
|
*/
|
|
2114
2209
|
#dispatcher;
|
|
2115
2210
|
#collection = null;
|
|
2211
|
+
#pendingCollectionMetrics = [];
|
|
2116
2212
|
/**
|
|
2117
2213
|
* Creates a new CustomCollection instance.
|
|
2118
2214
|
* @param name The name of the collection.
|
|
@@ -2124,12 +2220,13 @@ var CustomCollectionHandler = class {
|
|
|
2124
2220
|
* @param CollectionPage The CollectionPage constructor.
|
|
2125
2221
|
* @param filterPredicate Optional filter predicate for items.
|
|
2126
2222
|
*/
|
|
2127
|
-
constructor(name$2, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), Collection, CollectionPage, filterPredicate) {
|
|
2223
|
+
constructor(name$2, values, context, callbacks, tracerProvider = _opentelemetry_api.trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
|
|
2128
2224
|
this.name = name$2;
|
|
2129
2225
|
this.values = values;
|
|
2130
2226
|
this.context = context;
|
|
2131
2227
|
this.callbacks = callbacks;
|
|
2132
2228
|
this.tracerProvider = tracerProvider;
|
|
2229
|
+
this.meterProvider = meterProvider;
|
|
2133
2230
|
this.Collection = Collection;
|
|
2134
2231
|
this.CollectionPage = CollectionPage;
|
|
2135
2232
|
this.filterPredicate = filterPredicate;
|
|
@@ -2182,10 +2279,12 @@ var CustomCollectionHandler = class {
|
|
|
2182
2279
|
const { prevCursor, nextCursor } = pages;
|
|
2183
2280
|
const partOf = new URL(id);
|
|
2184
2281
|
partOf.searchParams.delete("cursor");
|
|
2282
|
+
const items = this.filterItems(pages.items);
|
|
2283
|
+
this.recordPendingCollectionItemCount(true, items.length);
|
|
2185
2284
|
return {
|
|
2186
2285
|
id,
|
|
2187
2286
|
partOf,
|
|
2188
|
-
items
|
|
2287
|
+
items,
|
|
2189
2288
|
prev: this.appendToUrl(prevCursor),
|
|
2190
2289
|
next: this.appendToUrl(nextCursor)
|
|
2191
2290
|
};
|
|
@@ -2198,11 +2297,16 @@ var CustomCollectionHandler = class {
|
|
|
2198
2297
|
*/
|
|
2199
2298
|
async getProps(firstCursor) {
|
|
2200
2299
|
const lastCursor = await this.callbacks.lastCursor?.(this.context, this.values);
|
|
2300
|
+
const totalItems = await this.totalItems;
|
|
2301
|
+
if (totalItems != null) this.#pendingCollectionMetrics.push({
|
|
2302
|
+
page: false,
|
|
2303
|
+
totalItems: Number(totalItems)
|
|
2304
|
+
});
|
|
2201
2305
|
return {
|
|
2202
2306
|
id: this.#id,
|
|
2203
2307
|
first: this.appendToUrl(firstCursor),
|
|
2204
2308
|
last: this.appendToUrl(lastCursor),
|
|
2205
|
-
totalItems
|
|
2309
|
+
totalItems
|
|
2206
2310
|
};
|
|
2207
2311
|
}
|
|
2208
2312
|
/**
|
|
@@ -2212,10 +2316,12 @@ var CustomCollectionHandler = class {
|
|
|
2212
2316
|
async getPropsWithoutCursor() {
|
|
2213
2317
|
const totalItems = await this.totalItems;
|
|
2214
2318
|
const pages = await this.getPages({ totalItems });
|
|
2319
|
+
const items = this.filterItems(pages.items);
|
|
2320
|
+
this.recordPendingCollectionItemCount(false, items.length);
|
|
2215
2321
|
return {
|
|
2216
2322
|
id: this.#id,
|
|
2217
2323
|
totalItems,
|
|
2218
|
-
items
|
|
2324
|
+
items
|
|
2219
2325
|
};
|
|
2220
2326
|
}
|
|
2221
2327
|
/**
|
|
@@ -2250,12 +2356,24 @@ var CustomCollectionHandler = class {
|
|
|
2250
2356
|
* @returns A function that handles the span operation.
|
|
2251
2357
|
*/
|
|
2252
2358
|
spanPages = ({ totalItems = null, cursor = null }) => async (span) => {
|
|
2359
|
+
const pageMetricBase = this.metricBase(cursor !== null);
|
|
2360
|
+
const started = performance.now();
|
|
2253
2361
|
try {
|
|
2254
2362
|
if (totalItems !== null) span.setAttribute(this.ATTRS.TOTAL_ITEMS, totalItems);
|
|
2255
2363
|
const page = await this.dispatch(cursor);
|
|
2364
|
+
const durationMs = require_http.getDurationMs(started);
|
|
2256
2365
|
span.setAttribute(this.ATTRS.ITEMS, page.items.length);
|
|
2366
|
+
this.#pendingCollectionMetrics.push({
|
|
2367
|
+
page: pageMetricBase.page,
|
|
2368
|
+
dispatchDurationMs: durationMs,
|
|
2369
|
+
totalItems: totalItems == null ? void 0 : Number(totalItems)
|
|
2370
|
+
});
|
|
2257
2371
|
return page;
|
|
2258
2372
|
} catch (e) {
|
|
2373
|
+
this.#pendingCollectionMetrics.push({
|
|
2374
|
+
page: cursor !== null,
|
|
2375
|
+
dispatchDurationMs: require_http.getDurationMs(started)
|
|
2376
|
+
});
|
|
2259
2377
|
const message = e instanceof Error ? e.message : String(e);
|
|
2260
2378
|
span.setStatus({
|
|
2261
2379
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -2282,6 +2400,37 @@ var CustomCollectionHandler = class {
|
|
|
2282
2400
|
filterItems(items) {
|
|
2283
2401
|
return filterCollectionItems(items, this.name, this.filterPredicate);
|
|
2284
2402
|
}
|
|
2403
|
+
metricBase(page) {
|
|
2404
|
+
return {
|
|
2405
|
+
kind: "custom",
|
|
2406
|
+
page,
|
|
2407
|
+
dispatcher: "custom"
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
metricAttributes(page, result, response) {
|
|
2411
|
+
return collectionAttributes(this.metricBase(page), result, response);
|
|
2412
|
+
}
|
|
2413
|
+
recordPendingCollectionItemCount(page, itemCount) {
|
|
2414
|
+
for (let i = this.#pendingCollectionMetrics.length - 1; i >= 0; i--) {
|
|
2415
|
+
const measurement = this.#pendingCollectionMetrics[i];
|
|
2416
|
+
if (measurement.page === page && measurement.dispatchDurationMs != null && measurement.itemCount == null) {
|
|
2417
|
+
measurement.itemCount = itemCount;
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
this.#pendingCollectionMetrics.push({
|
|
2422
|
+
page,
|
|
2423
|
+
itemCount
|
|
2424
|
+
});
|
|
2425
|
+
}
|
|
2426
|
+
recordPendingCollectionMetrics(result, response) {
|
|
2427
|
+
for (const measurement of this.#pendingCollectionMetrics.splice(0)) {
|
|
2428
|
+
const attrs = this.metricAttributes(measurement.page, result, response);
|
|
2429
|
+
if (measurement.dispatchDurationMs != null) require_http.recordCollectionDispatchDuration(this.meterProvider, measurement.dispatchDurationMs, attrs);
|
|
2430
|
+
if (measurement.itemCount != null) require_http.recordCollectionPageItems(this.meterProvider, measurement.itemCount, attrs);
|
|
2431
|
+
if (measurement.totalItems != null) require_http.recordCollectionTotalItems(this.meterProvider, measurement.totalItems, attrs);
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2285
2434
|
/**
|
|
2286
2435
|
* Appends a cursor to the URL if it exists.
|
|
2287
2436
|
* @param cursor The cursor to append, or null/undefined.
|
|
@@ -2345,14 +2494,36 @@ var CustomCollectionHandler = class {
|
|
|
2345
2494
|
*/
|
|
2346
2495
|
function exceptWrapper(handler) {
|
|
2347
2496
|
return async (request, handlerParams) => {
|
|
2497
|
+
const page = new URL(request.url).searchParams.get("cursor") != null;
|
|
2498
|
+
const { meterProvider } = handlerParams;
|
|
2499
|
+
const metricBase = {
|
|
2500
|
+
kind: "custom",
|
|
2501
|
+
page,
|
|
2502
|
+
dispatcher: "custom"
|
|
2503
|
+
};
|
|
2348
2504
|
try {
|
|
2349
|
-
|
|
2505
|
+
const response = await handler(request, handlerParams);
|
|
2506
|
+
require_http.recordCollectionRequest(meterProvider, collectionAttributes(metricBase, "served", response));
|
|
2507
|
+
return response;
|
|
2350
2508
|
} catch (error) {
|
|
2351
2509
|
const { onNotFound, onUnauthorized } = handlerParams;
|
|
2352
2510
|
switch (error?.constructor) {
|
|
2353
|
-
case ItemsNotFoundError:
|
|
2354
|
-
|
|
2355
|
-
|
|
2511
|
+
case ItemsNotFoundError: {
|
|
2512
|
+
const response = await onNotFound(request);
|
|
2513
|
+
recordDeferredPendingCollectionMetrics(error, "not_found", response);
|
|
2514
|
+
require_http.recordCollectionRequest(meterProvider, collectionAttributes(metricBase, "not_found", response));
|
|
2515
|
+
return response;
|
|
2516
|
+
}
|
|
2517
|
+
case UnauthorizedError: {
|
|
2518
|
+
const response = await onUnauthorized(request);
|
|
2519
|
+
recordDeferredPendingCollectionMetrics(error, "unauthorized", response);
|
|
2520
|
+
require_http.recordCollectionRequest(meterProvider, collectionAttributes(metricBase, "unauthorized", response));
|
|
2521
|
+
return response;
|
|
2522
|
+
}
|
|
2523
|
+
default:
|
|
2524
|
+
recordDeferredPendingCollectionMetrics(error, "error");
|
|
2525
|
+
require_http.recordCollectionRequest(meterProvider, collectionAttributes(metricBase, "error"));
|
|
2526
|
+
throw error;
|
|
2356
2527
|
}
|
|
2357
2528
|
}
|
|
2358
2529
|
};
|
|
@@ -4029,7 +4200,15 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4029
4200
|
}
|
|
4030
4201
|
if (request.method !== "POST" && !acceptsJsonLd(request)) {
|
|
4031
4202
|
metricState.endpoint = "not_acceptable";
|
|
4032
|
-
|
|
4203
|
+
const response = await onNotAcceptable(request);
|
|
4204
|
+
const collectionRoute = getCollectionMetricRoute(routeName);
|
|
4205
|
+
if (collectionRoute != null) require_http.recordCollectionRequest(this._meterProvider, {
|
|
4206
|
+
...collectionRoute,
|
|
4207
|
+
page: url.searchParams.get("cursor") != null,
|
|
4208
|
+
result: "not_acceptable",
|
|
4209
|
+
statusCode: response.status
|
|
4210
|
+
});
|
|
4211
|
+
return response;
|
|
4033
4212
|
}
|
|
4034
4213
|
switch (routeName) {
|
|
4035
4214
|
case "actor":
|
|
@@ -4090,6 +4269,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4090
4269
|
context,
|
|
4091
4270
|
collectionCallbacks: this.outboxCallbacks,
|
|
4092
4271
|
tracerProvider: this.tracerProvider,
|
|
4272
|
+
meterProvider: this._meterProvider,
|
|
4093
4273
|
onUnauthorized,
|
|
4094
4274
|
onNotFound
|
|
4095
4275
|
});
|
|
@@ -4101,6 +4281,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4101
4281
|
context,
|
|
4102
4282
|
collectionCallbacks: this.inboxCallbacks,
|
|
4103
4283
|
tracerProvider: this.tracerProvider,
|
|
4284
|
+
meterProvider: this._meterProvider,
|
|
4104
4285
|
onUnauthorized,
|
|
4105
4286
|
onNotFound
|
|
4106
4287
|
});
|
|
@@ -4140,6 +4321,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4140
4321
|
context,
|
|
4141
4322
|
collectionCallbacks: this.followingCallbacks,
|
|
4142
4323
|
tracerProvider: this.tracerProvider,
|
|
4324
|
+
meterProvider: this._meterProvider,
|
|
4143
4325
|
onUnauthorized,
|
|
4144
4326
|
onNotFound
|
|
4145
4327
|
});
|
|
@@ -4163,6 +4345,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4163
4345
|
filterPredicate: baseUrl != null ? ((i) => (i instanceof URL ? i.href : i.id?.href ?? "").startsWith(baseUrl)) : void 0,
|
|
4164
4346
|
collectionCallbacks: this.followersCallbacks,
|
|
4165
4347
|
tracerProvider: this.tracerProvider,
|
|
4348
|
+
meterProvider: this._meterProvider,
|
|
4166
4349
|
onUnauthorized,
|
|
4167
4350
|
onNotFound
|
|
4168
4351
|
});
|
|
@@ -4174,6 +4357,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4174
4357
|
context,
|
|
4175
4358
|
collectionCallbacks: this.likedCallbacks,
|
|
4176
4359
|
tracerProvider: this.tracerProvider,
|
|
4360
|
+
meterProvider: this._meterProvider,
|
|
4177
4361
|
onUnauthorized,
|
|
4178
4362
|
onNotFound
|
|
4179
4363
|
});
|
|
@@ -4184,6 +4368,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4184
4368
|
context,
|
|
4185
4369
|
collectionCallbacks: this.featuredCallbacks,
|
|
4186
4370
|
tracerProvider: this.tracerProvider,
|
|
4371
|
+
meterProvider: this._meterProvider,
|
|
4187
4372
|
onUnauthorized,
|
|
4188
4373
|
onNotFound
|
|
4189
4374
|
});
|
|
@@ -4194,6 +4379,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4194
4379
|
context,
|
|
4195
4380
|
collectionCallbacks: this.featuredTagsCallbacks,
|
|
4196
4381
|
tracerProvider: this.tracerProvider,
|
|
4382
|
+
meterProvider: this._meterProvider,
|
|
4197
4383
|
onUnauthorized,
|
|
4198
4384
|
onNotFound
|
|
4199
4385
|
});
|
|
@@ -4206,6 +4392,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4206
4392
|
values: route.values,
|
|
4207
4393
|
collectionCallbacks: callbacks,
|
|
4208
4394
|
tracerProvider: this.tracerProvider,
|
|
4395
|
+
meterProvider: this._meterProvider,
|
|
4209
4396
|
onUnauthorized,
|
|
4210
4397
|
onNotFound
|
|
4211
4398
|
});
|
|
@@ -4219,6 +4406,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4219
4406
|
values: route.values,
|
|
4220
4407
|
collectionCallbacks: callbacks,
|
|
4221
4408
|
tracerProvider: this.tracerProvider,
|
|
4409
|
+
meterProvider: this._meterProvider,
|
|
4222
4410
|
onUnauthorized,
|
|
4223
4411
|
onNotFound
|
|
4224
4412
|
});
|
|
@@ -4251,6 +4439,29 @@ function getEndpointCategory(routeName) {
|
|
|
4251
4439
|
default: return "not_found";
|
|
4252
4440
|
}
|
|
4253
4441
|
}
|
|
4442
|
+
function getCollectionMetricRoute(routeName) {
|
|
4443
|
+
switch (routeName) {
|
|
4444
|
+
case "inbox":
|
|
4445
|
+
case "outbox":
|
|
4446
|
+
case "following":
|
|
4447
|
+
case "followers":
|
|
4448
|
+
case "liked":
|
|
4449
|
+
case "featured": return {
|
|
4450
|
+
kind: routeName,
|
|
4451
|
+
dispatcher: "built_in"
|
|
4452
|
+
};
|
|
4453
|
+
case "featuredTags": return {
|
|
4454
|
+
kind: "featured_tags",
|
|
4455
|
+
dispatcher: "built_in"
|
|
4456
|
+
};
|
|
4457
|
+
case "collection":
|
|
4458
|
+
case "orderedCollection": return {
|
|
4459
|
+
kind: "custom",
|
|
4460
|
+
dispatcher: "custom"
|
|
4461
|
+
};
|
|
4462
|
+
default: return;
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4254
4465
|
const FANOUT_THRESHOLD = 5;
|
|
4255
4466
|
var ContextImpl = class ContextImpl {
|
|
4256
4467
|
url;
|
package/dist/mod.cjs
CHANGED
|
@@ -4,11 +4,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
4
4
|
require("./chunk-DDcVe30Y.cjs");
|
|
5
5
|
const require_transformers = require("./transformers-NeAONrAq.cjs");
|
|
6
6
|
require("./compat/mod.cjs");
|
|
7
|
-
const require_http = require("./http-
|
|
8
|
-
const require_middleware = require("./middleware-
|
|
9
|
-
const require_proof = require("./proof-
|
|
7
|
+
const require_http = require("./http-D_HNhC57.cjs");
|
|
8
|
+
const require_middleware = require("./middleware-hxnyAewn.cjs");
|
|
9
|
+
const require_proof = require("./proof-wm6UxUoM.cjs");
|
|
10
10
|
const require_types = require("./types-KC4QAoxe.cjs");
|
|
11
|
-
const require_kv_cache = require("./kv-cache-
|
|
11
|
+
const require_kv_cache = require("./kv-cache-CdOuPFgC.cjs");
|
|
12
12
|
const require_federation_mod = require("./federation/mod.cjs");
|
|
13
13
|
require("./nodeinfo/mod.cjs");
|
|
14
14
|
require("./runtime/mod.cjs");
|