@fedify/fedify 1.8.1-pr.334.1193 → 1.8.1-pr.339.1221
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/{actor-CeBMq8qR.js → actor-C_fB23SK.js} +1 -1
- package/dist/{actor-BxYrc06V.js → actor-D-gppdfb.js} +179 -179
- package/dist/{authdocloader-mGQvrIQ2.js → authdocloader-B2hkRlHV.js} +3 -3
- package/dist/{authdocloader-D64rqKxU.js → authdocloader-C4tzFZqI.js} +3 -3
- package/dist/{builder-BMWyrhEH.js → builder-D8tC_vfI.js} +74 -4
- package/dist/{client-CTC5x_Sz.js → client-Bk-YQuxz.js} +1 -1
- package/dist/compat/mod.d.ts +3 -3
- package/dist/compat/transformers.test.js +16 -16
- package/dist/{context-B6mUZhs_.d.ts → context-Csbv_Ssv.d.ts} +215 -2
- package/dist/{docloader-BU0Mbf3M.js → docloader-CN5x_D5w.js} +1 -1
- package/dist/{esm-LMB9p-G5.js → esm-B-Jb47LY.js} +1 -1
- package/dist/federation/builder.test.js +25 -6
- package/dist/federation/collection.test.js +3 -3
- package/dist/federation/handler.test.js +327 -17
- package/dist/federation/inbox.test.js +4 -4
- package/dist/federation/keycache.test.js +4 -4
- package/dist/federation/kv.test.js +3 -3
- package/dist/federation/middleware.test.js +49 -18
- package/dist/federation/mod.d.ts +3 -3
- package/dist/federation/mod.js +10 -10
- package/dist/federation/mq.test.js +3 -3
- package/dist/federation/retry.test.js +3 -3
- package/dist/federation/router.test.js +3 -3
- package/dist/federation/send.test.js +10 -10
- package/dist/{http-D1uoUH4N.d.ts → http-BL6S1G0j.d.ts} +1 -1
- package/dist/{http-D3g0NXG1.js → http-BN-AfxHv.js} +2 -2
- package/dist/{http-CYR3mIVn.js → http-CX9EBYil.js} +3 -3
- package/dist/{inbox-CKssCQNk.js → inbox-B-guAC2t.js} +1 -1
- package/dist/{key-CuNvhgVd.js → key-BsFs0hRJ.js} +4 -4
- package/dist/{key-BBZcKCrH.js → key-CDER1nPf.js} +2 -2
- package/dist/{key-CmOXs0Mq.js → key-DBpUT6eL.js} +3 -3
- package/dist/{key-YOEsvep6.js → key-wEgiBcf4.js} +2 -2
- package/dist/{keycache-DGObidvq.js → keycache-CzNY9D-R.js} +1 -1
- package/dist/{keys-CPhbsrsX.js → keys-DyrWvTVk.js} +1 -1
- package/dist/{ld-D8ugSU-x.js → ld-Bij-eGOh.js} +2 -2
- package/dist/{lookup-rBByGTyy.js → lookup-BnVbBDao.js} +1 -1
- package/dist/{lookup-B0_qPExk.js → lookup-Dvnw2uak.js} +1 -1
- package/dist/{middleware-B_To0NZ3.js → middleware-BdCHqVyf.js} +615 -10
- package/dist/middleware-BylQejY9.js +17 -0
- package/dist/{middleware-u2WBeCjB.js → middleware-CRHRYKzd.js} +549 -14
- package/dist/middleware-Cruz4Ju6.js +26 -0
- package/dist/{mod-0L5jhGYM.d.ts → mod-D8-liXFY.d.ts} +1 -1
- package/dist/{mod-D9qE4iHP.d.ts → mod-Dc_fDCtK.d.ts} +1 -1
- package/dist/{mod-BCl7t-Ka.d.ts → mod-j0OCtlRW.d.ts} +1 -1
- package/dist/mod.d.ts +6 -6
- package/dist/mod.js +10 -10
- package/dist/nodeinfo/client.test.js +5 -5
- package/dist/nodeinfo/handler.test.js +16 -16
- package/dist/nodeinfo/mod.js +2 -2
- package/dist/nodeinfo/semver.test.js +3 -3
- package/dist/nodeinfo/types.test.js +3 -3
- package/dist/{owner-D1TBvEbO.js → owner-DaDx2G2T.js} +2 -2
- package/dist/{proof-CUsFh6B-.js → proof-B7EUMoa_.js} +3 -3
- package/dist/{proof-CyWfFsKS.js → proof-BY0M6tMI.js} +2 -2
- package/dist/runtime/authdocloader.test.js +9 -9
- package/dist/runtime/docloader.test.js +4 -4
- package/dist/runtime/key.test.js +5 -5
- package/dist/runtime/langstr.test.js +3 -3
- package/dist/runtime/mod.d.ts +2 -2
- package/dist/runtime/mod.js +6 -6
- package/dist/runtime/multibase/multibase.test.js +3 -3
- package/dist/runtime/url.test.js +3 -3
- package/dist/{send-CrjrTnXW.js → send-DfVJ7u7H.js} +2 -2
- package/dist/sig/http.test.js +8 -8
- package/dist/sig/key.test.js +6 -6
- package/dist/sig/ld.test.js +7 -7
- package/dist/sig/mod.d.ts +2 -2
- package/dist/sig/mod.js +6 -6
- package/dist/sig/owner.test.js +7 -7
- package/dist/sig/proof.test.js +7 -7
- package/dist/testing/docloader.test.js +3 -3
- package/dist/testing/mod.d.ts +212 -0
- package/dist/testing/mod.js +3 -3
- package/dist/{testing-CROcCUCq.js → testing-CxPA9ooV.js} +4 -3
- package/dist/{type-DGlR8Urb.js → type-BclCS6EM.js} +179 -179
- package/dist/{types-DZdBK266.js → types-aPGcTfd2.js} +1 -1
- package/dist/vocab/actor.test.js +5 -5
- package/dist/vocab/lookup.test.js +4 -4
- package/dist/vocab/mod.js +4 -4
- package/dist/vocab/type.test.js +3 -3
- package/dist/vocab/vocab.test.js +4 -4
- package/dist/{vocab-BLQ-_oLb.js → vocab-BgH1bkzj.js} +3 -3
- package/dist/webfinger/handler.test.js +16 -16
- package/dist/webfinger/lookup.test.js +4 -4
- package/dist/webfinger/mod.js +2 -2
- package/dist/x/cfworkers.test.js +3 -3
- package/dist/x/hono.d.ts +2 -2
- package/dist/x/sveltekit.d.ts +2 -2
- package/package.json +1 -1
- package/dist/middleware-DbDzHrt7.js +0 -17
- package/dist/middleware-JUbAKlS5.js +0 -26
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
|
|
5
5
|
import { getDefaultActivityTransformers } from "./transformers-ghwJuzGY.js";
|
|
6
|
-
import { deno_default, getDocumentLoader, kvCache } from "./docloader-
|
|
7
|
-
import { Activity, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId } from "./actor-
|
|
8
|
-
import { lookupWebFinger } from "./lookup-
|
|
9
|
-
import { exportJwk, importJwk, validateCryptoKey } from "./key-
|
|
10
|
-
import { doubleKnock, verifyRequest } from "./http-
|
|
11
|
-
import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-
|
|
12
|
-
import { getNodeInfo, nodeInfoToJson } from "./types-
|
|
13
|
-
import { getAuthenticatedDocumentLoader } from "./authdocloader-
|
|
14
|
-
import { lookupObject, traverseCollection } from "./vocab-
|
|
6
|
+
import { deno_default, getDocumentLoader, kvCache } from "./docloader-CN5x_D5w.js";
|
|
7
|
+
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId } from "./actor-D-gppdfb.js";
|
|
8
|
+
import { lookupWebFinger } from "./lookup-BnVbBDao.js";
|
|
9
|
+
import { exportJwk, importJwk, validateCryptoKey } from "./key-CDER1nPf.js";
|
|
10
|
+
import { doubleKnock, verifyRequest } from "./http-CX9EBYil.js";
|
|
11
|
+
import { detachSignature, doesActorOwnKey, getKeyOwner, hasSignature, signJsonLd, signObject, verifyJsonLd, verifyObject } from "./proof-B7EUMoa_.js";
|
|
12
|
+
import { getNodeInfo, nodeInfoToJson } from "./types-aPGcTfd2.js";
|
|
13
|
+
import { getAuthenticatedDocumentLoader } from "./authdocloader-B2hkRlHV.js";
|
|
14
|
+
import { lookupObject, traverseCollection } from "./vocab-BgH1bkzj.js";
|
|
15
15
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
16
16
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
17
17
|
import { encodeHex } from "byte-encodings/hex";
|
|
@@ -306,13 +306,21 @@ var FederationBuilderImpl = class {
|
|
|
306
306
|
inboxListeners;
|
|
307
307
|
inboxErrorHandler;
|
|
308
308
|
sharedInboxKeyDispatcher;
|
|
309
|
+
collectionTypeIds;
|
|
310
|
+
collectionCallbacks;
|
|
311
|
+
/**
|
|
312
|
+
* Symbol registry for unique identification of unnamed symbols.
|
|
313
|
+
*/
|
|
314
|
+
#symbolRegistry = /* @__PURE__ */ new Map();
|
|
309
315
|
constructor() {
|
|
310
316
|
this.router = new Router$1();
|
|
311
317
|
this.objectCallbacks = {};
|
|
312
318
|
this.objectTypeIds = {};
|
|
319
|
+
this.collectionCallbacks = {};
|
|
320
|
+
this.collectionTypeIds = {};
|
|
313
321
|
}
|
|
314
322
|
async build(options) {
|
|
315
|
-
const { FederationImpl: FederationImpl$1 } = await import("./middleware-
|
|
323
|
+
const { FederationImpl: FederationImpl$1 } = await import("./middleware-BylQejY9.js");
|
|
316
324
|
const f = new FederationImpl$1(options);
|
|
317
325
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
318
326
|
f.router = this.router.clone();
|
|
@@ -756,6 +764,68 @@ var FederationBuilderImpl = class {
|
|
|
756
764
|
};
|
|
757
765
|
return setters;
|
|
758
766
|
}
|
|
767
|
+
setCollectionDispatcher(name, ...args) {
|
|
768
|
+
return this.#setCustomCollectionDispatcher(name, "collection", ...args);
|
|
769
|
+
}
|
|
770
|
+
setOrderedCollectionDispatcher(name, ...args) {
|
|
771
|
+
return this.#setCustomCollectionDispatcher(name, "orderedCollection", ...args);
|
|
772
|
+
}
|
|
773
|
+
#setCustomCollectionDispatcher(name, collectionType, itemType, path, dispatcher) {
|
|
774
|
+
const strName = String(name);
|
|
775
|
+
const routeName = `${collectionType}:${this.#uniqueCollectionId(name)}`;
|
|
776
|
+
if (this.router.has(routeName)) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
|
|
777
|
+
if (this.collectionCallbacks[name] != null) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
|
|
778
|
+
const variables = this.router.add(path, routeName);
|
|
779
|
+
if (variables.size < 1) throw new RouterError("Path for collection dispatcher must have at least one variable.");
|
|
780
|
+
const callbacks = { dispatcher };
|
|
781
|
+
this.collectionCallbacks[name] = callbacks;
|
|
782
|
+
this.collectionTypeIds[name] = itemType;
|
|
783
|
+
const setters = {
|
|
784
|
+
setCounter(counter) {
|
|
785
|
+
callbacks.counter = counter;
|
|
786
|
+
return setters;
|
|
787
|
+
},
|
|
788
|
+
setFirstCursor(cursor) {
|
|
789
|
+
callbacks.firstCursor = cursor;
|
|
790
|
+
return setters;
|
|
791
|
+
},
|
|
792
|
+
setLastCursor(cursor) {
|
|
793
|
+
callbacks.lastCursor = cursor;
|
|
794
|
+
return setters;
|
|
795
|
+
},
|
|
796
|
+
authorize(predicate) {
|
|
797
|
+
callbacks.authorizePredicate = predicate;
|
|
798
|
+
return setters;
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
return setters;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Get the URL path for a custom collection.
|
|
805
|
+
* If the collection is not registered, returns null.
|
|
806
|
+
* @typeParam TParam The parameter names of the requested URL.
|
|
807
|
+
* @param {string | symbol} name The name of the custom collection.
|
|
808
|
+
* @param {TParam} values The values to fill in the URL parameters.
|
|
809
|
+
* @returns {string | null} The URL path for the custom collection, or null if not registered.
|
|
810
|
+
*/
|
|
811
|
+
getCollectionPath(name, values) {
|
|
812
|
+
if (!(name in this.collectionCallbacks)) return null;
|
|
813
|
+
const routeName = this.#uniqueCollectionId(name);
|
|
814
|
+
const path = this.router.build(`collection:${routeName}`, values) ?? this.router.build(`orderedCollection:${routeName}`, values);
|
|
815
|
+
return path;
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Converts a name (string or symbol) to a unique string identifier.
|
|
819
|
+
* For symbols, generates and caches a UUID if not already present.
|
|
820
|
+
* For strings, returns the string as-is.
|
|
821
|
+
* @param name The name to convert to a unique identifier
|
|
822
|
+
* @returns A unique string identifier
|
|
823
|
+
*/
|
|
824
|
+
#uniqueCollectionId(name) {
|
|
825
|
+
if (typeof name === "string") return name;
|
|
826
|
+
if (!this.#symbolRegistry.has(name)) this.#symbolRegistry.set(name, crypto.randomUUID());
|
|
827
|
+
return this.#symbolRegistry.get(name);
|
|
828
|
+
}
|
|
759
829
|
};
|
|
760
830
|
/**
|
|
761
831
|
* Creates a new {@link FederationBuilder} instance.
|
|
@@ -914,6 +984,13 @@ function acceptsJsonLd(request) {
|
|
|
914
984
|
if (types[0] === "text/html" || types[0] === "application/xhtml+xml") return false;
|
|
915
985
|
return types.includes("application/activity+json") || types.includes("application/ld+json") || types.includes("application/json");
|
|
916
986
|
}
|
|
987
|
+
/**
|
|
988
|
+
* Handles an actor request.
|
|
989
|
+
* @typeParam TContextData The context data to pass to the context.
|
|
990
|
+
* @param request The HTTP request.
|
|
991
|
+
* @param parameters The parameters for handling the actor.
|
|
992
|
+
* @returns A promise that resolves to an HTTP response.
|
|
993
|
+
*/
|
|
917
994
|
async function handleActor(request, { identifier, context: context$1, actorDispatcher, authorizePredicate, onNotFound, onNotAcceptable, onUnauthorized }) {
|
|
918
995
|
const logger$1 = getLogger([
|
|
919
996
|
"fedify",
|
|
@@ -957,6 +1034,13 @@ async function handleActor(request, { identifier, context: context$1, actorDispa
|
|
|
957
1034
|
Vary: "Accept"
|
|
958
1035
|
} });
|
|
959
1036
|
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Handles an object request.
|
|
1039
|
+
* @typeParam TContextData The context data to pass to the context.
|
|
1040
|
+
* @param request The HTTP request.
|
|
1041
|
+
* @param parameters The parameters for handling the object.
|
|
1042
|
+
* @returns A promise that resolves to an HTTP response.
|
|
1043
|
+
*/
|
|
960
1044
|
async function handleObject(request, { values, context: context$1, objectDispatcher, authorizePredicate, onNotFound, onNotAcceptable, onUnauthorized }) {
|
|
961
1045
|
if (objectDispatcher == null) return await onNotFound(request);
|
|
962
1046
|
const object = await objectDispatcher(context$1, values);
|
|
@@ -989,6 +1073,16 @@ async function handleObject(request, { values, context: context$1, objectDispatc
|
|
|
989
1073
|
Vary: "Accept"
|
|
990
1074
|
} });
|
|
991
1075
|
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Handles a collection request.
|
|
1078
|
+
* @typeParam TItem The type of items in the collection.
|
|
1079
|
+
* @typeParam TContext The type of the context, extending {@link RequestContext}.
|
|
1080
|
+
* @typeParam TContextData The context data to pass to the `TContext`.
|
|
1081
|
+
* @typeParam TFilter The type of the filter.
|
|
1082
|
+
* @param request The HTTP request.
|
|
1083
|
+
* @param parameters The parameters for handling the collection.
|
|
1084
|
+
* @returns A promise that resolves to an HTTP response.
|
|
1085
|
+
*/
|
|
992
1086
|
async function handleCollection(request, { name, identifier, uriGetter, filter, filterPredicate, context: context$1, collectionCallbacks, tracerProvider, onUnauthorized, onNotFound, onNotAcceptable }) {
|
|
993
1087
|
const spanName = name.trim().replace(/\s+/g, "_");
|
|
994
1088
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
@@ -1130,6 +1224,14 @@ async function handleCollection(request, { name, identifier, uriGetter, filter,
|
|
|
1130
1224
|
Vary: "Accept"
|
|
1131
1225
|
} });
|
|
1132
1226
|
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Filters collection items based on the provided predicate.
|
|
1229
|
+
* @typeParam TItem The type of items to filter.
|
|
1230
|
+
* @param items The items to filter.
|
|
1231
|
+
* @param collectionName The name of the collection for logging purposes.
|
|
1232
|
+
* @param filterPredicate Optional predicate function to filter items.
|
|
1233
|
+
* @returns The filtered items as Objects, Links, or URLs.
|
|
1234
|
+
*/
|
|
1133
1235
|
function filterCollectionItems(items, collectionName, filterPredicate) {
|
|
1134
1236
|
const result = [];
|
|
1135
1237
|
let logged = false;
|
|
@@ -1153,6 +1255,13 @@ function filterCollectionItems(items, collectionName, filterPredicate) {
|
|
|
1153
1255
|
}
|
|
1154
1256
|
return result;
|
|
1155
1257
|
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Handles an inbox request for ActivityPub activities.
|
|
1260
|
+
* @typeParam TContextData The context data to pass to the context.
|
|
1261
|
+
* @param request The HTTP request.
|
|
1262
|
+
* @param options The parameters for handling the inbox.
|
|
1263
|
+
* @returns A promise that resolves to an HTTP response.
|
|
1264
|
+
*/
|
|
1156
1265
|
async function handleInbox(request, options) {
|
|
1157
1266
|
const tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
|
|
1158
1267
|
const tracer = tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
@@ -1174,6 +1283,14 @@ async function handleInbox(request, options) {
|
|
|
1174
1283
|
}
|
|
1175
1284
|
});
|
|
1176
1285
|
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Internal function for handling inbox requests with detailed processing.
|
|
1288
|
+
* @typeParam TContextData The context data to pass to the context.
|
|
1289
|
+
* @param request The HTTP request.
|
|
1290
|
+
* @param options The parameters for handling the inbox.
|
|
1291
|
+
* @param span The OpenTelemetry span for tracing.
|
|
1292
|
+
* @returns A promise that resolves to an HTTP response.
|
|
1293
|
+
*/
|
|
1177
1294
|
async function handleInboxInternal(request, { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, tracerProvider }, span) {
|
|
1178
1295
|
const logger$1 = getLogger([
|
|
1179
1296
|
"fedify",
|
|
@@ -1404,6 +1521,447 @@ async function handleInboxInternal(request, { recipient, context: ctx, inboxCont
|
|
|
1404
1521
|
});
|
|
1405
1522
|
}
|
|
1406
1523
|
/**
|
|
1524
|
+
* Handles a custom collection request.
|
|
1525
|
+
* @typeParam TItem The type of items in the collection.
|
|
1526
|
+
* @typeParam TParams The parameter names of the requested URL.
|
|
1527
|
+
* @typeParam TContext The type of the context, extending {@link RequestContext}.
|
|
1528
|
+
* @typeParam TContextData The context data to pass to the `TContext`.
|
|
1529
|
+
* @param request The HTTP request.
|
|
1530
|
+
* @param handleParams Parameters for handling the collection.
|
|
1531
|
+
* @returns A promise that resolves to an HTTP response.
|
|
1532
|
+
* @since 1.8.0
|
|
1533
|
+
*/
|
|
1534
|
+
const handleCustomCollection = exceptWrapper(_handleCustomCollection);
|
|
1535
|
+
async function _handleCustomCollection(request, { name, values, context: context$1, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
1536
|
+
verifyDefined(callbacks);
|
|
1537
|
+
verifyJsonLdRequest(request);
|
|
1538
|
+
await authIfNeeded(context$1, values, callbacks);
|
|
1539
|
+
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1540
|
+
return await new CustomCollectionHandler(name, values, context$1, callbacks, tracerProvider, Collection, CollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Handles an ordered collection request.
|
|
1544
|
+
* @typeParam TItem The type of items in the collection.
|
|
1545
|
+
* @typeParam TParams The parameter names of the requested URL.
|
|
1546
|
+
* @typeParam TContext The type of the context, extending {@link RequestContext}.
|
|
1547
|
+
* @typeParam TContextData The context data to pass to the `TContext`.
|
|
1548
|
+
* @param request The HTTP request.
|
|
1549
|
+
* @param handleParams Parameters for handling the collection.
|
|
1550
|
+
* @returns A promise that resolves to an HTTP response.
|
|
1551
|
+
* @since 1.8.0
|
|
1552
|
+
*/
|
|
1553
|
+
const handleOrderedCollection = exceptWrapper(_handleOrderedCollection);
|
|
1554
|
+
async function _handleOrderedCollection(request, { name, values, context: context$1, tracerProvider, collectionCallbacks: callbacks, filterPredicate }) {
|
|
1555
|
+
verifyDefined(callbacks);
|
|
1556
|
+
verifyJsonLdRequest(request);
|
|
1557
|
+
await authIfNeeded(context$1, values, callbacks);
|
|
1558
|
+
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
1559
|
+
return await new CustomCollectionHandler(name, values, context$1, callbacks, tracerProvider, OrderedCollection, OrderedCollectionPage, filterPredicate).fetchCollection(cursor).toJsonLd().then(respondAsActivity);
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Handling custom collections with support for pagination and filtering.
|
|
1563
|
+
* The main flow is on `getCollection`, `dispatch`.
|
|
1564
|
+
*
|
|
1565
|
+
* @typeParam TItem The type of items in the collection.
|
|
1566
|
+
* @typeParam TParams The parameter names of the requested URL.
|
|
1567
|
+
* @typeParam TContext The type of the context. {@link Context} or {@link RequestContext}.
|
|
1568
|
+
* @typeParam TContextData The context data to pass to the `TContext`.
|
|
1569
|
+
* @typeParam TCollection The type of the collection, extending {@link Collection}.
|
|
1570
|
+
* @typeParam TCollectionPage The type of the collection page, extending {@link CollectionPage}.
|
|
1571
|
+
* @since 1.8.0
|
|
1572
|
+
*/
|
|
1573
|
+
var CustomCollectionHandler = class {
|
|
1574
|
+
/**
|
|
1575
|
+
* The tracer for telemetry.
|
|
1576
|
+
* @type {Tracer}
|
|
1577
|
+
*/
|
|
1578
|
+
#tracer;
|
|
1579
|
+
/**
|
|
1580
|
+
* The ID of the collection.
|
|
1581
|
+
* @type {URL}
|
|
1582
|
+
*/
|
|
1583
|
+
#id;
|
|
1584
|
+
/**
|
|
1585
|
+
* Store total count of items in the collection.
|
|
1586
|
+
* Use `this.totalItems` to access the total items count.
|
|
1587
|
+
* It is a promise because it may require an asynchronous operation to count items.
|
|
1588
|
+
* @type {Promise<number | null> | undefined}
|
|
1589
|
+
*/
|
|
1590
|
+
#totalItems = void 0;
|
|
1591
|
+
/**
|
|
1592
|
+
* The first cursor for pagination.
|
|
1593
|
+
* It is a promise because it may require an asynchronous operation to get the first cursor.
|
|
1594
|
+
* @type {Promise<string | null> | undefined}
|
|
1595
|
+
*/
|
|
1596
|
+
#dispatcher;
|
|
1597
|
+
#collection = null;
|
|
1598
|
+
/**
|
|
1599
|
+
* Creates a new CustomCollection instance.
|
|
1600
|
+
* @param {string} name The name of the collection.
|
|
1601
|
+
* @param {TParams} values The parameter values for the collection.
|
|
1602
|
+
* @param {TContext} context The request context.
|
|
1603
|
+
* @param {CustomCollectionCallbacks} callbacks The collection callbacks.
|
|
1604
|
+
* @param {TracerProvider} tracerProvider The tracer provider for telemetry.
|
|
1605
|
+
* @param {ConstructorWithTypeId<TCollection>} Collection The Collection constructor.
|
|
1606
|
+
* @param {ConstructorWithTypeId<TCollectionPage>} CollectionPage The CollectionPage constructor.
|
|
1607
|
+
* @param {(item: TItem) => boolean} filterPredicate Optional filter predicate for items.
|
|
1608
|
+
*/
|
|
1609
|
+
constructor(name, values, context$1, callbacks, tracerProvider = trace.getTracerProvider(), Collection$1, CollectionPage$1, filterPredicate) {
|
|
1610
|
+
this.name = name;
|
|
1611
|
+
this.values = values;
|
|
1612
|
+
this.context = context$1;
|
|
1613
|
+
this.callbacks = callbacks;
|
|
1614
|
+
this.tracerProvider = tracerProvider;
|
|
1615
|
+
this.Collection = Collection$1;
|
|
1616
|
+
this.CollectionPage = CollectionPage$1;
|
|
1617
|
+
this.filterPredicate = filterPredicate;
|
|
1618
|
+
this.name = this.name.trim().replace(/\s+/g, "_");
|
|
1619
|
+
this.#tracer = this.tracerProvider.getTracer(deno_default.name, deno_default.version);
|
|
1620
|
+
this.#id = new URL(this.context.url);
|
|
1621
|
+
this.#dispatcher = callbacks.dispatcher.bind(callbacks);
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Converts the collection to JSON-LD format.
|
|
1625
|
+
* @returns A promise that resolves to the JSON-LD representation.
|
|
1626
|
+
*/
|
|
1627
|
+
async toJsonLd() {
|
|
1628
|
+
return (await this.collection).toJsonLd(this.context);
|
|
1629
|
+
}
|
|
1630
|
+
/**
|
|
1631
|
+
* Fetches the collection with optional cursor for pagination.
|
|
1632
|
+
* This method is defined for method chaining and to show processing flow properly.
|
|
1633
|
+
* So it is no problem to call `toJsonLd` directly on the instance.
|
|
1634
|
+
* @param cursor The cursor for pagination, or null for the first page.
|
|
1635
|
+
* @returns The CustomCollection instance for method chaining.
|
|
1636
|
+
*/
|
|
1637
|
+
fetchCollection(cursor = null) {
|
|
1638
|
+
this.#collection = this.getCollection(cursor);
|
|
1639
|
+
return this;
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Gets the collection or collection page based on the cursor.
|
|
1643
|
+
* @param {string | null} cursor The cursor for pagination, or null for the main collection.
|
|
1644
|
+
* @returns {Promise<TCollection | TCollectionPage>} A promise that resolves to a Collection or CollectionPage.
|
|
1645
|
+
*/
|
|
1646
|
+
async getCollection(cursor = null) {
|
|
1647
|
+
if (cursor !== null) {
|
|
1648
|
+
const props$1 = await this.getPageProps(cursor);
|
|
1649
|
+
return new this.CollectionPage(props$1);
|
|
1650
|
+
}
|
|
1651
|
+
const firstCursor = await this.firstCursor;
|
|
1652
|
+
const props = typeof firstCursor === "string" ? await this.getProps(firstCursor) : await this.getPropsWithoutCursor();
|
|
1653
|
+
return new this.Collection(props);
|
|
1654
|
+
}
|
|
1655
|
+
/**
|
|
1656
|
+
* Gets the properties for a collection page.
|
|
1657
|
+
* Returns the page properties including items, previous and next cursors.
|
|
1658
|
+
* @param {string} cursor The cursor for the page.
|
|
1659
|
+
* @returns A promise that resolves to the page properties.
|
|
1660
|
+
*/
|
|
1661
|
+
async getPageProps(cursor) {
|
|
1662
|
+
const id = this.#id;
|
|
1663
|
+
const pages = await this.getPages({ cursor });
|
|
1664
|
+
const { prevCursor, nextCursor } = pages;
|
|
1665
|
+
const partOf = new URL(id);
|
|
1666
|
+
partOf.searchParams.delete("cursor");
|
|
1667
|
+
return {
|
|
1668
|
+
id,
|
|
1669
|
+
partOf,
|
|
1670
|
+
items: this.filterItems(pages.items),
|
|
1671
|
+
prev: this.appendToUrl(prevCursor),
|
|
1672
|
+
next: this.appendToUrl(nextCursor)
|
|
1673
|
+
};
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Gets the properties for a collection with cursors.
|
|
1677
|
+
* Returns the first cursor and last cursor as URL, along with total items count.
|
|
1678
|
+
* @param {string} firstCursor The first cursor for pagination.
|
|
1679
|
+
* @returns A promise that resolves to the collection properties.
|
|
1680
|
+
*/
|
|
1681
|
+
async getProps(firstCursor) {
|
|
1682
|
+
const lastCursor = await this.callbacks.lastCursor?.(this.context, this.values);
|
|
1683
|
+
return {
|
|
1684
|
+
id: this.#id,
|
|
1685
|
+
first: this.appendToUrl(firstCursor),
|
|
1686
|
+
last: this.appendToUrl(lastCursor),
|
|
1687
|
+
totalItems: await this.totalItems
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
/**
|
|
1691
|
+
* Gets the properties for a collection of all items and the count.
|
|
1692
|
+
* @returns A promise that resolves to the collection properties.
|
|
1693
|
+
*/
|
|
1694
|
+
async getPropsWithoutCursor() {
|
|
1695
|
+
const totalItems = await this.totalItems;
|
|
1696
|
+
const pages = await this.getPages({ totalItems });
|
|
1697
|
+
return {
|
|
1698
|
+
id: this.#id,
|
|
1699
|
+
totalItems,
|
|
1700
|
+
items: this.filterItems(pages.items)
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Gets a page of items from the collection.
|
|
1705
|
+
* Wraps the dispatcher in a span for telemetry.
|
|
1706
|
+
* @param options Options for getting the page, including cursor and total items.
|
|
1707
|
+
* @returns A promise that resolves to the page items.
|
|
1708
|
+
*/
|
|
1709
|
+
async getPages({ cursor = null, totalItems = null }) {
|
|
1710
|
+
return await this.#tracer.startActiveSpan(`${this.ATTRS.DISPATCH_COLLECTION} ${this.name}`, this.spanOptions(SpanKind.SERVER, cursor), this.spanPages({
|
|
1711
|
+
cursor,
|
|
1712
|
+
totalItems
|
|
1713
|
+
}));
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Creates span options for telemetry.
|
|
1717
|
+
* @param {SpanKind} kind The span kind.
|
|
1718
|
+
* @param {string | null} cursor The optional cursor value.
|
|
1719
|
+
* @returns {SpanOptions}The span options.
|
|
1720
|
+
*/
|
|
1721
|
+
spanOptions = (kind, cursor) => ({
|
|
1722
|
+
kind,
|
|
1723
|
+
attributes: {
|
|
1724
|
+
[this.ATTRS.ID]: this.#id.href,
|
|
1725
|
+
[this.ATTRS.TYPE]: this.Collection.typeId.href,
|
|
1726
|
+
...cursor ? { [this.ATTRS.CURSOR]: cursor } : {}
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1729
|
+
/**
|
|
1730
|
+
* Creates a function to wrap the dispatcher so tracing can be applied.
|
|
1731
|
+
* @param params Parameters including cursor and total items.
|
|
1732
|
+
* @returns {(span: Span) => Promise<PageItems<TItem>>} A function that handles the span operation.
|
|
1733
|
+
*/
|
|
1734
|
+
spanPages = ({ totalItems = null, cursor = null }) => async (span) => {
|
|
1735
|
+
try {
|
|
1736
|
+
if (totalItems !== null) span.setAttribute(this.ATTRS.TOTAL_ITEMS, totalItems);
|
|
1737
|
+
const page = await this.dispatch(cursor);
|
|
1738
|
+
span.setAttribute(this.ATTRS.ITEMS, page.items.length);
|
|
1739
|
+
return page;
|
|
1740
|
+
} catch (e) {
|
|
1741
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
1742
|
+
span.setStatus({
|
|
1743
|
+
code: SpanStatusCode.ERROR,
|
|
1744
|
+
message
|
|
1745
|
+
});
|
|
1746
|
+
throw e;
|
|
1747
|
+
} finally {
|
|
1748
|
+
span.end();
|
|
1749
|
+
}
|
|
1750
|
+
};
|
|
1751
|
+
/**
|
|
1752
|
+
* Dispatches the collection request to get items.
|
|
1753
|
+
* @param {string | null} cursor The cursor for pagination, or null for the first page.
|
|
1754
|
+
* @returns {Promise<PageItems<TItem>>} A promise that resolves to the page items.
|
|
1755
|
+
*/
|
|
1756
|
+
async dispatch(cursor = null) {
|
|
1757
|
+
return await this.#dispatcher(this.context, this.values, cursor) ?? new ItemsNotFoundError().throw();
|
|
1758
|
+
}
|
|
1759
|
+
/**
|
|
1760
|
+
* Filters the items in the collection.
|
|
1761
|
+
* @param {TItem[]} items The items to filter.
|
|
1762
|
+
* @returns {(Object | Link | URL)[]} The filtered items.
|
|
1763
|
+
*/
|
|
1764
|
+
filterItems(items) {
|
|
1765
|
+
return filterCollectionItems(items, this.name, this.filterPredicate);
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Appends a cursor to the URL if it exists.
|
|
1769
|
+
* @param {string | null | undefined} cursor The cursor to append, or null/undefined.
|
|
1770
|
+
* @returns The URL with cursor appended, or null if cursor is null/undefined.
|
|
1771
|
+
*/
|
|
1772
|
+
appendToUrl(cursor) {
|
|
1773
|
+
return appendCursorIfExists(this.context.url, cursor);
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Gets the stored collection or collection page.
|
|
1777
|
+
* @returns {Promise<TCollection | TCollectionPage>} A promise that resolves to
|
|
1778
|
+
the collection or collection page.
|
|
1779
|
+
*/
|
|
1780
|
+
get collection() {
|
|
1781
|
+
if (this.#collection === null) this.#collection = this.getCollection();
|
|
1782
|
+
return this.#collection;
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* Gets the total number of items in the collection.
|
|
1786
|
+
* @returns {Promise<number | null>} A promise that
|
|
1787
|
+
resolves to the total items count, or null if not available.
|
|
1788
|
+
*/
|
|
1789
|
+
get totalItems() {
|
|
1790
|
+
if (this.#totalItems === void 0) this.totalItems = this.callbacks.counter?.(this.context, this.values);
|
|
1791
|
+
return this.#totalItems;
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* Sets the total number of items in the collection.
|
|
1795
|
+
* @param value The total items count or a promise that resolves to it.
|
|
1796
|
+
*/
|
|
1797
|
+
set totalItems(value) {
|
|
1798
|
+
const toNumber = (value$1) => value$1 == null ? null : Number(value$1);
|
|
1799
|
+
this.#totalItems = value instanceof Promise ? value.then(toNumber) : Promise.resolve(toNumber(value));
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* Gets the first cursor for pagination.
|
|
1803
|
+
* @returns {Promise<string | null>} A promise that resolves to the first cursor,
|
|
1804
|
+
or null if not available.
|
|
1805
|
+
*/
|
|
1806
|
+
get firstCursor() {
|
|
1807
|
+
const cursor = this.callbacks.firstCursor?.(this.context, this.values);
|
|
1808
|
+
return Promise.resolve(cursor ?? null);
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Attribute constants for telemetry spans.
|
|
1812
|
+
*/
|
|
1813
|
+
ATTRS = {
|
|
1814
|
+
DISPATCH_COLLECTION: "activitypub.dispatch_collection",
|
|
1815
|
+
CURSOR: "fedify.collection.cursor",
|
|
1816
|
+
ID: "activitypub.collection.id",
|
|
1817
|
+
ITEMS: "fedify.collection.items",
|
|
1818
|
+
TOTAL_ITEMS: "activitypub.collection.total_items",
|
|
1819
|
+
TYPE: "activitypub.collection.type"
|
|
1820
|
+
};
|
|
1821
|
+
};
|
|
1822
|
+
/**
|
|
1823
|
+
* A wrapper function that catches specific errors and handles them appropriately.
|
|
1824
|
+
* @typeParam TParams The type of parameters that extend ErrorHandlers.
|
|
1825
|
+
* @param handler The handler function to wrap.
|
|
1826
|
+
* @returns A wrapped handler function that catches and handles specific errors.
|
|
1827
|
+
* @since 1.8.0
|
|
1828
|
+
*/
|
|
1829
|
+
function exceptWrapper(handler) {
|
|
1830
|
+
return async (request, handlerParams) => {
|
|
1831
|
+
try {
|
|
1832
|
+
return await handler(request, handlerParams);
|
|
1833
|
+
} catch (error) {
|
|
1834
|
+
const { onNotFound, onNotAcceptable, onUnauthorized } = handlerParams;
|
|
1835
|
+
switch (error?.constructor) {
|
|
1836
|
+
case ItemsNotFoundError: return await onNotFound(request);
|
|
1837
|
+
case NotAcceptableError: return await onNotAcceptable(request);
|
|
1838
|
+
case UnauthorizedError: return await onUnauthorized(request);
|
|
1839
|
+
default: throw error;
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
/**
|
|
1845
|
+
* Verifies that a value is defined (not undefined).
|
|
1846
|
+
* @typeParam T The type of the value, excluding undefined.
|
|
1847
|
+
* @param callbacks The value to verify.
|
|
1848
|
+
* @throws {ItemsNotFoundError} If the value is undefined.
|
|
1849
|
+
* @since 1.8.0
|
|
1850
|
+
*/
|
|
1851
|
+
const verifyDefined = (callbacks) => {
|
|
1852
|
+
if (callbacks === void 0) throw new ItemsNotFoundError();
|
|
1853
|
+
};
|
|
1854
|
+
/**
|
|
1855
|
+
* Verifies that a request accepts JSON-LD content type.
|
|
1856
|
+
* @param request The HTTP request to verify.
|
|
1857
|
+
* @throws {NotAcceptableError} If the request doesn't accept JSON-LD.
|
|
1858
|
+
* @since 1.8.0
|
|
1859
|
+
*/
|
|
1860
|
+
const verifyJsonLdRequest = (request) => {
|
|
1861
|
+
if (!acceptsJsonLd(request)) throw new NotAcceptableError();
|
|
1862
|
+
};
|
|
1863
|
+
/**
|
|
1864
|
+
* Performs authorization if needed based on the authorization predicate.
|
|
1865
|
+
* @typeParam TContextData The context data type.
|
|
1866
|
+
* @param {RequestContext<TContextData>} context The request context.
|
|
1867
|
+
* @param {Record<string, string>} values The parameter values.
|
|
1868
|
+
* @param options Options containing the authorization predicate.
|
|
1869
|
+
* @throws {UnauthorizedError} If authorization fails.
|
|
1870
|
+
* @since 1.8.0
|
|
1871
|
+
*/
|
|
1872
|
+
const authIfNeeded = async (context$1, values, { authorizePredicate: authorize = void 0 }) => {
|
|
1873
|
+
if (authorize === void 0) return;
|
|
1874
|
+
const key = (await context$1.getSignedKey())?.clone({}, warning.key) ?? null;
|
|
1875
|
+
const keyOwner = (await context$1.getSignedKeyOwner())?.clone({}, warning.keyOwner) ?? null;
|
|
1876
|
+
if (!await authorize(context$1, values, key, keyOwner)) throw new UnauthorizedError();
|
|
1877
|
+
};
|
|
1878
|
+
/** Warning messages for `authIfNeeded`. */
|
|
1879
|
+
const warning = {
|
|
1880
|
+
key: { $warning: {
|
|
1881
|
+
category: [
|
|
1882
|
+
"fedify",
|
|
1883
|
+
"federation",
|
|
1884
|
+
"collection"
|
|
1885
|
+
],
|
|
1886
|
+
message: "The third parameter of AuthorizePredicate is deprecated in favor of RequestContext.getSignedKey() method. The third parameter will be removed in a future release."
|
|
1887
|
+
} },
|
|
1888
|
+
keyOwner: { $warning: {
|
|
1889
|
+
category: [
|
|
1890
|
+
"fedify",
|
|
1891
|
+
"federation",
|
|
1892
|
+
"collection"
|
|
1893
|
+
],
|
|
1894
|
+
message: "The fourth parameter of AuthorizePredicate is deprecated in favor of RequestContext.getSignedKeyOwner() method. The fourth parameter will be removed in a future release."
|
|
1895
|
+
} }
|
|
1896
|
+
};
|
|
1897
|
+
/**
|
|
1898
|
+
* Appends a cursor parameter to a URL if the cursor exists.
|
|
1899
|
+
* @typeParam Cursor The type of the cursor (string, null, or undefined).
|
|
1900
|
+
* @param {URL} url The base URL to append the cursor to.
|
|
1901
|
+
* @param {string | null | undefined} cursor The cursor value to append.
|
|
1902
|
+
* @returns The URL with cursor appended if cursor is a string, null otherwise.
|
|
1903
|
+
* @since 1.8.0
|
|
1904
|
+
*/
|
|
1905
|
+
const appendCursorIfExists = (url, cursor) => {
|
|
1906
|
+
if (cursor === null || cursor === void 0) return null;
|
|
1907
|
+
const copied = new URL(url);
|
|
1908
|
+
copied.searchParams.set("cursor", cursor);
|
|
1909
|
+
return copied;
|
|
1910
|
+
};
|
|
1911
|
+
/**
|
|
1912
|
+
* Creates an HTTP response for ActivityPub data.
|
|
1913
|
+
* @param {unknown} data The data to serialize as JSON-LD.
|
|
1914
|
+
* @returns {Response} An HTTP response with the data as ActivityPub JSON.
|
|
1915
|
+
* @since 1.8.0
|
|
1916
|
+
*/
|
|
1917
|
+
const respondAsActivity = (data) => new Response(JSON.stringify(data), { headers: {
|
|
1918
|
+
"Content-Type": "application/activity+json",
|
|
1919
|
+
Vary: "Accept"
|
|
1920
|
+
} });
|
|
1921
|
+
/**
|
|
1922
|
+
* Base class for handler errors.
|
|
1923
|
+
* @since 1.8.0
|
|
1924
|
+
*/
|
|
1925
|
+
var HandlerError = class extends Error {
|
|
1926
|
+
constructor(message) {
|
|
1927
|
+
super(message);
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Throws this error.
|
|
1931
|
+
* @returns Never returns, always throws.
|
|
1932
|
+
*/
|
|
1933
|
+
throw() {
|
|
1934
|
+
throw this;
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
/**
|
|
1938
|
+
* Error thrown when items are not found in a collection.
|
|
1939
|
+
* @since 1.8.0
|
|
1940
|
+
*/
|
|
1941
|
+
var ItemsNotFoundError = class extends HandlerError {
|
|
1942
|
+
constructor() {
|
|
1943
|
+
super("Items not found in the collection.");
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
/**
|
|
1947
|
+
* Error thrown when the request is not acceptable (e.g., wrong content type).
|
|
1948
|
+
* @since 1.8.0
|
|
1949
|
+
*/
|
|
1950
|
+
var NotAcceptableError = class extends HandlerError {
|
|
1951
|
+
constructor() {
|
|
1952
|
+
super("The request is not acceptable.");
|
|
1953
|
+
}
|
|
1954
|
+
};
|
|
1955
|
+
/**
|
|
1956
|
+
* Error thrown when access to a collection is unauthorized.
|
|
1957
|
+
* @since 1.8.0
|
|
1958
|
+
*/
|
|
1959
|
+
var UnauthorizedError = class extends HandlerError {
|
|
1960
|
+
constructor() {
|
|
1961
|
+
super("Unauthorized access to the collection.");
|
|
1962
|
+
}
|
|
1963
|
+
};
|
|
1964
|
+
/**
|
|
1407
1965
|
* Responds with the given object in JSON-LD format.
|
|
1408
1966
|
*
|
|
1409
1967
|
* @param object The object to respond with.
|
|
@@ -2599,6 +3157,34 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2599
3157
|
onNotFound,
|
|
2600
3158
|
onNotAcceptable
|
|
2601
3159
|
});
|
|
3160
|
+
case "collection": {
|
|
3161
|
+
const name = route.name.replace(/^collection:/, "");
|
|
3162
|
+
const callbacks = this.collectionCallbacks[name];
|
|
3163
|
+
return await handleCustomCollection(request, {
|
|
3164
|
+
name,
|
|
3165
|
+
context: context$1,
|
|
3166
|
+
values: route.values,
|
|
3167
|
+
collectionCallbacks: callbacks,
|
|
3168
|
+
tracerProvider: this.tracerProvider,
|
|
3169
|
+
onUnauthorized,
|
|
3170
|
+
onNotFound,
|
|
3171
|
+
onNotAcceptable
|
|
3172
|
+
});
|
|
3173
|
+
}
|
|
3174
|
+
case "orderedCollection": {
|
|
3175
|
+
const name = route.name.replace(/^orderedCollection:/, "");
|
|
3176
|
+
const callbacks = this.collectionCallbacks[name];
|
|
3177
|
+
return await handleOrderedCollection(request, {
|
|
3178
|
+
name,
|
|
3179
|
+
context: context$1,
|
|
3180
|
+
values: route.values,
|
|
3181
|
+
collectionCallbacks: callbacks,
|
|
3182
|
+
tracerProvider: this.tracerProvider,
|
|
3183
|
+
onUnauthorized,
|
|
3184
|
+
onNotFound,
|
|
3185
|
+
onNotAcceptable
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
2602
3188
|
default: {
|
|
2603
3189
|
const response = onNotFound(request);
|
|
2604
3190
|
return response instanceof Promise ? await response : response;
|
|
@@ -2739,6 +3325,11 @@ var ContextImpl = class ContextImpl {
|
|
|
2739
3325
|
if (path == null) throw new RouterError("No featured tags collection path registered.");
|
|
2740
3326
|
return new URL(path, this.canonicalOrigin);
|
|
2741
3327
|
}
|
|
3328
|
+
getCollectionUri(name, values) {
|
|
3329
|
+
const path = this.federation.getCollectionPath(name, values);
|
|
3330
|
+
if (path === null) throw new RouterError(`No collection dispatcher registered for "${String(name)}".`);
|
|
3331
|
+
return new URL(path, this.canonicalOrigin);
|
|
3332
|
+
}
|
|
2742
3333
|
parseUri(uri) {
|
|
2743
3334
|
if (uri == null) return null;
|
|
2744
3335
|
if (uri.origin !== this.origin && uri.origin !== this.canonicalOrigin) return null;
|
|
@@ -2826,6 +3417,20 @@ var ContextImpl = class ContextImpl {
|
|
|
2826
3417
|
return identifier;
|
|
2827
3418
|
}
|
|
2828
3419
|
};
|
|
3420
|
+
const collectionTypes = ["collection", "orderedCollection"];
|
|
3421
|
+
const collectionRegex = /* @__PURE__ */ new RegExp(`^(${collectionTypes.join("|")}):(.*)$`);
|
|
3422
|
+
const match = route.name.match(collectionRegex);
|
|
3423
|
+
if (match !== null) {
|
|
3424
|
+
const [, type, name] = match;
|
|
3425
|
+
const cls = this.federation.collectionTypeIds[name];
|
|
3426
|
+
return {
|
|
3427
|
+
type,
|
|
3428
|
+
name,
|
|
3429
|
+
class: cls,
|
|
3430
|
+
typeId: cls.typeId,
|
|
3431
|
+
values: route.values
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
2829
3434
|
return null;
|
|
2830
3435
|
}
|
|
2831
3436
|
async getActorKeyPairs(identifier) {
|