Commit 1e42cead authored by ChanHaeng Lee's avatar ChanHaeng Lee
Browse files

Implement custom collection handling

parent 1dfed920
Loading
Loading
Loading
Loading
+88 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import {
  handleCollection,
  handleInbox,
  handleObject,
  handleOrderedCollection,
} from "./handler.ts";
import { routeActivity } from "./inbox.ts";
import { KvKeyCache } from "./keycache.ts";
@@ -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;
@@ -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) {
@@ -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;
  }

+2 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ export function createContext<TContextData>(
    getNodeInfoUri,
    getActorUri,
    getObjectUri,
    getCollectionUri,
    getOutboxUri,
    getInboxUri,
    getFollowingUri,
@@ -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,