Commit a628d046 authored by ChanHaeng Lee's avatar ChanHaeng Lee
Browse files
parent 9e7caef3
Loading
Loading
Loading
Loading
+74 −1
Original line number Diff line number Diff line
import { assertEquals, assertExists } from "@std/assert";
import { assertEquals, assertExists, assertThrows } from "@std/assert";
import { parseSemVer } from "../nodeinfo/semver.ts";
import type { Protocol } from "../nodeinfo/types.ts";
import { test } from "../testing/mod.ts";
@@ -215,4 +215,77 @@ test("FederationBuilder", async (t) => {
      assertEquals(personRoute?.values.id, "abc");
    },
  );

  await t.step(
    "should handle symbol names uniquely in custom collection dispatchers",
    async () => {
      const builder = createFederationBuilder<string>();
      const kv = new MemoryKvStore();

      // Create two unnamed symbols
      const unnamedSymbol1 = Symbol();
      const unnamedSymbol2 = Symbol();
      const namedSymbol1 = Symbol.for("");
      const namedSymbol2 = Symbol.for("");
      const strId = String(unnamedSymbol1);

      const dispatcher = (_ctx: unknown, _params: unknown) => ({
        items: [],
      });

      // Test that different unnamed symbols are treated as different
      builder.setCollectionDispatcher(
        unnamedSymbol1,
        Note,
        "/unnamed-symbol1/{id}",
        dispatcher,
      );

      // Test that using the same symbol twice throws an error
      assertThrows(
        () => {
          builder.setCollectionDispatcher(
            unnamedSymbol1,
            Note,
            "/unnamed-symbol1-duplicate/{id}",
            dispatcher,
          );
        },
        Error,
        "Collection dispatcher for Symbol() already set.",
      );

      // Test that using a different symbol works
      builder.setCollectionDispatcher(
        unnamedSymbol2,
        Note,
        "/unnamed-symbol2/{id}",
        dispatcher,
      );
      // Test that using same named symbol twice with a different name throws an error
      builder.setCollectionDispatcher(
        namedSymbol1,
        Note,
        "/named-symbol/{id}",
        dispatcher,
      );
      assertThrows(
        () => {
          builder.setCollectionDispatcher(
            namedSymbol2,
            Note,
            "/named-symbol/{id}",
            dispatcher,
          );
        },
      );
      // Test that using string ID stringified from an unnamed symbol works
      builder.setCollectionDispatcher(
        strId,
        Note,
        "/string-id/{id}",
        dispatcher,
      );
    },
  );
});
+27 −3
Original line number Diff line number Diff line
@@ -114,6 +114,11 @@ export class FederationBuilderImpl<TContextData>
    >
  >;

  /**
   * Symbol registry for unique identification of unnamed symbols.
   */
  #symbolRegistry = new Map<symbol, string>();

  constructor() {
    this.router = new Router();
    this.objectCallbacks = {};
@@ -1264,17 +1269,18 @@ export class FederationBuilderImpl<TContextData>
    RequestContext<TContextData>,
    TContextData
  > {
    const routeName = `${collectionType}:${String(name)}`;
    const strName = String(name);
    const routeName = `${collectionType}:${this.#uniqueCollectionId(name)}`;
    if (this.router.has(routeName)) {
      throw new RouterError(
        `Collection dispatcher for ${String(name)} already set.`,
        `Collection dispatcher for ${strName} already set.`,
      );
    }

    // Check if identifier is already used in collectionCallbacks
    if (this.collectionCallbacks[name] != null) {
      throw new RouterError(
        `Collection dispatcher for ${String(name)} already set.`,
        `Collection dispatcher for ${strName} already set.`,
      );
    }

@@ -1342,6 +1348,24 @@ export class FederationBuilderImpl<TContextData>
    };
    return setters;
  }

  /**
   * Converts a name (string or symbol) to a unique string identifier.
   * For symbols, generates and caches a UUID if not already present.
   * For strings, returns the string as-is.
   * @param name The name to convert to a unique identifier
   * @returns A unique string identifier
   */
  #uniqueCollectionId(name: string | symbol): string {
    if (typeof name === "string") return name;
    // Check if symbol already has a unique ID
    if (!this.#symbolRegistry.has(name)) {
      // Generate a new UUID for this symbol
      this.#symbolRegistry.set(name, crypto.randomUUID());
    }

    return this.#symbolRegistry.get(name)!;
  }
}

/**