Loading fedify/federation/middleware.ts +88 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import { handleCollection, handleInbox, handleObject, handleOrderedCollection, } from "./handler.ts"; import { routeActivity } from "./inbox.ts"; import { KvKeyCache } from "./keycache.ts"; Loading Loading @@ -1464,6 +1465,44 @@ export class FederationImpl<TContextData> onNotFound, onNotAcceptable, }); case "collection": { const name = route.name.replace(/^collection:/, ""); const callbacks = this.collectionCallbacks[name]; return await handleOrderedCollection< URL | Object | Link | Recipient, Record<string, string>, RequestContext<TContextData>, TContextData >(request, { name, context, values: route.values, collectionCallbacks: callbacks, tracerProvider: this.tracerProvider, onUnauthorized, onNotFound, onNotAcceptable, }); } case "orderedCollection": { const name = route.name.replace(/^orderedCollection:/, ""); const callbacks = this.collectionCallbacks[name]; return await handleOrderedCollection< URL | Object | Link | Recipient, Record<string, string>, RequestContext<TContextData>, TContextData >(request, { name, context, values: route.values, collectionCallbacks: callbacks, tracerProvider: this.tracerProvider, onUnauthorized, onNotFound, onNotAcceptable, }); } default: { const response = onNotFound(request); return response instanceof Promise ? await response : response; Loading Loading @@ -1688,6 +1727,37 @@ export class ContextImpl<TContextData> implements Context<TContextData> { return new URL(path, this.canonicalOrigin); } getCollectionUri<TParam extends Record<string, string>>( name: string | symbol, values: TParam, ): URL { // Check if it's a custom collection const customCallbacks = this.federation.collectionCallbacks[name]; if (customCallbacks != null) { // For custom collections, use collection: or orderedCollection: prefix const collectionRouteName = `collection:${String(name)}`; const orderedCollectionRouteName = `orderedCollection:${String(name)}`; let path = this.federation.router.build(collectionRouteName, values); if (path == null) { path = this.federation.router.build(orderedCollectionRouteName, values); } if (path == null) { throw new RouterError( `No collection dispatcher registered for ${String(name)}.`, ); } return new URL(path, this.canonicalOrigin); } // Fall back to built-in collections (for backward compatibility) throw new RouterError( `No collection dispatcher registered for ${String(name)}.`, ); } parseUri(uri: URL | null): ParseUriResult | null { if (uri == null) return null; if (uri.origin !== this.origin && uri.origin !== this.canonicalOrigin) { Loading Loading @@ -1817,6 +1887,24 @@ export class ContextImpl<TContextData> implements Context<TContextData> { }, }; } const collectionRegex = /^(orderedC|c)ollection:(.*)$/; const match = route.name.match(collectionRegex) as null | [ unknown, "collection" | "orderedCollection", string, ]; if (match !== null) { const [, type, name] = match; const cls = this.federation.collectionTypeIds[name]; return { type, name, class: cls, typeId: cls.typeId, values: route.values, }; } return null; } Loading fedify/testing/context.ts +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ export function createContext<TContextData>( getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, Loading Loading @@ -66,6 +67,7 @@ export function createContext<TContextData>( getNodeInfoUri: getNodeInfoUri ?? throwRouteError, getActorUri: getActorUri ?? throwRouteError, getObjectUri: getObjectUri ?? throwRouteError, getCollectionUri: getCollectionUri ?? throwRouteError, getOutboxUri: getOutboxUri ?? throwRouteError, getInboxUri: getInboxUri ?? throwRouteError, getFollowingUri: getFollowingUri ?? throwRouteError, Loading Loading
fedify/federation/middleware.ts +88 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import { handleCollection, handleInbox, handleObject, handleOrderedCollection, } from "./handler.ts"; import { routeActivity } from "./inbox.ts"; import { KvKeyCache } from "./keycache.ts"; Loading Loading @@ -1464,6 +1465,44 @@ export class FederationImpl<TContextData> onNotFound, onNotAcceptable, }); case "collection": { const name = route.name.replace(/^collection:/, ""); const callbacks = this.collectionCallbacks[name]; return await handleOrderedCollection< URL | Object | Link | Recipient, Record<string, string>, RequestContext<TContextData>, TContextData >(request, { name, context, values: route.values, collectionCallbacks: callbacks, tracerProvider: this.tracerProvider, onUnauthorized, onNotFound, onNotAcceptable, }); } case "orderedCollection": { const name = route.name.replace(/^orderedCollection:/, ""); const callbacks = this.collectionCallbacks[name]; return await handleOrderedCollection< URL | Object | Link | Recipient, Record<string, string>, RequestContext<TContextData>, TContextData >(request, { name, context, values: route.values, collectionCallbacks: callbacks, tracerProvider: this.tracerProvider, onUnauthorized, onNotFound, onNotAcceptable, }); } default: { const response = onNotFound(request); return response instanceof Promise ? await response : response; Loading Loading @@ -1688,6 +1727,37 @@ export class ContextImpl<TContextData> implements Context<TContextData> { return new URL(path, this.canonicalOrigin); } getCollectionUri<TParam extends Record<string, string>>( name: string | symbol, values: TParam, ): URL { // Check if it's a custom collection const customCallbacks = this.federation.collectionCallbacks[name]; if (customCallbacks != null) { // For custom collections, use collection: or orderedCollection: prefix const collectionRouteName = `collection:${String(name)}`; const orderedCollectionRouteName = `orderedCollection:${String(name)}`; let path = this.federation.router.build(collectionRouteName, values); if (path == null) { path = this.federation.router.build(orderedCollectionRouteName, values); } if (path == null) { throw new RouterError( `No collection dispatcher registered for ${String(name)}.`, ); } return new URL(path, this.canonicalOrigin); } // Fall back to built-in collections (for backward compatibility) throw new RouterError( `No collection dispatcher registered for ${String(name)}.`, ); } parseUri(uri: URL | null): ParseUriResult | null { if (uri == null) return null; if (uri.origin !== this.origin && uri.origin !== this.canonicalOrigin) { Loading Loading @@ -1817,6 +1887,24 @@ export class ContextImpl<TContextData> implements Context<TContextData> { }, }; } const collectionRegex = /^(orderedC|c)ollection:(.*)$/; const match = route.name.match(collectionRegex) as null | [ unknown, "collection" | "orderedCollection", string, ]; if (match !== null) { const [, type, name] = match; const cls = this.federation.collectionTypeIds[name]; return { type, name, class: cls, typeId: cls.typeId, values: route.values, }; } return null; } Loading
fedify/testing/context.ts +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ export function createContext<TContextData>( getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, Loading Loading @@ -66,6 +67,7 @@ export function createContext<TContextData>( getNodeInfoUri: getNodeInfoUri ?? throwRouteError, getActorUri: getActorUri ?? throwRouteError, getObjectUri: getObjectUri ?? throwRouteError, getCollectionUri: getCollectionUri ?? throwRouteError, getOutboxUri: getOutboxUri ?? throwRouteError, getInboxUri: getInboxUri ?? throwRouteError, getFollowingUri: getFollowingUri ?? throwRouteError, Loading