Commit fa77bff1 authored by Jiwon Kwon's avatar Jiwon Kwon
Browse files

Remove ParamPath types in collectionDispatcher

parent e5a14ec8
Loading
Loading
Loading
Loading
+27 −23
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ import type {
  FederationOptions,
  InboxListenerSetters,
  ObjectCallbackSetters,
  ParamsKeyPath,
  Rfc6570Expression,
} from "./federation.ts";
import type {
  CollectionCallbacks,
@@ -110,7 +110,7 @@ export class FederationBuilderImpl<TContextData>
    string | symbol,
    CustomCollectionCallbacks<
      Object,
      Record<string, string>,
      string,
      RequestContext<TContextData>,
      TContextData
    >
@@ -1208,21 +1208,22 @@ export class FederationBuilderImpl<TContextData>

  setCollectionDispatcher<
    TObject extends Object,
    TParams extends Record<string, string>,
    TParam extends string,
  >(
    name: string | symbol,
    ...args: [
      ConstructorWithTypeId<TObject>,
      ParamsKeyPath<TParams>,
      // deno-lint-ignore no-explicit-any
      (new (...args: any[]) => TObject) & { typeId: URL },
      `${string}${Rfc6570Expression<TParam>}${string}`,
      CustomCollectionDispatcher<
        TObject,
        TParams,
        TParam,
        RequestContext<TContextData>,
        TContextData
      >,
    ]
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    RequestContext<TContextData>,
    TContextData
  > {
@@ -1235,21 +1236,22 @@ export class FederationBuilderImpl<TContextData>

  setOrderedCollectionDispatcher<
    TObject extends Object,
    TParams extends Record<string, string>,
    TParam extends string,
  >(
    name: string | symbol,
    ...args: [
      ConstructorWithTypeId<TObject>,
      ParamsKeyPath<TParams>,
      // deno-lint-ignore no-explicit-any
      (new (...args: any[]) => TObject) & { typeId: URL },
      `${string}${Rfc6570Expression<TParam>}${string}`,
      CustomCollectionDispatcher<
        TObject,
        TParams,
        TParam,
        RequestContext<TContextData>,
        TContextData
      >,
    ]
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    RequestContext<TContextData>,
    TContextData
  > {
@@ -1259,22 +1261,24 @@ export class FederationBuilderImpl<TContextData>
      ...args,
    );
  }

  #setCustomCollectionDispatcher<
    TObject extends Object,
    TParams extends Record<string, string>,
    TParam extends string,
  >(
    name: string | symbol,
    collectionType: "collection" | "orderedCollection",
    itemType: ConstructorWithTypeId<TObject>,
    path: ParamsKeyPath<TParams>,
    // deno-lint-ignore no-explicit-any
    itemType: (new (...args: any[]) => TObject) & { typeId: URL },
    path: `${string}${Rfc6570Expression<TParam>}${string}`,
    dispatcher: CustomCollectionDispatcher<
      TObject,
      TParams,
      TParam,
      RequestContext<TContextData>,
      TContextData
    >,
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    RequestContext<TContextData>,
    TContextData
  > {
@@ -1302,7 +1306,7 @@ export class FederationBuilderImpl<TContextData>

    const callbacks: CustomCollectionCallbacks<
      TObject,
      TParams,
      TParam,
      RequestContext<TContextData>,
      TContextData
    > = { dispatcher };
@@ -1312,13 +1316,13 @@ export class FederationBuilderImpl<TContextData>
    this.collectionTypeIds[name] = itemType;

    const setters: CustomCollectionCallbackSetters<
      TParams,
      TParam,
      RequestContext<TContextData>,
      TContextData
    > = {
      setCounter(
        counter: CustomCollectionCounter<
          TParams,
          TParam,
          TContextData
        >,
      ) {
@@ -1327,7 +1331,7 @@ export class FederationBuilderImpl<TContextData>
      },
      setFirstCursor(
        cursor: CustomCollectionCursor<
          TParams,
          TParam,
          RequestContext<TContextData>,
          TContextData
        >,
@@ -1337,7 +1341,7 @@ export class FederationBuilderImpl<TContextData>
      },
      setLastCursor(
        cursor: CustomCollectionCursor<
          TParams,
          TParam,
          RequestContext<TContextData>,
          TContextData
        >,
@@ -1348,7 +1352,7 @@ export class FederationBuilderImpl<TContextData>
      authorize(
        predicate: ObjectAuthorizePredicate<
          TContextData,
          keyof TParams & string
          keyof TParam & string
        >,
      ) {
        callbacks.authorizePredicate = predicate;
+6 −6
Original line number Diff line number Diff line
@@ -304,12 +304,12 @@ export type ObjectAuthorizePredicate<TContextData, TParam extends string> = (
 */
export type CustomCollectionDispatcher<
  TItem,
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends Context<TContextData>,
  TContextData,
> = (
  context: TContext,
  values: TParams,
  values: Record<TParam, string>,
  cursor: string | null,
) => PageItems<TItem> | null | Promise<PageItems<TItem> | null>;

@@ -323,11 +323,11 @@ export type CustomCollectionDispatcher<
 * @since 1.8.0
 */
export type CustomCollectionCounter<
  TParams extends Record<string, string>,
  TParam extends string,
  TContextData,
> = (
  context: RequestContext<TContextData>,
  values: TParams,
  values: Record<TParam, string>,
) => number | bigint | null | Promise<number | bigint | null>;

/**
@@ -343,10 +343,10 @@ export type CustomCollectionCounter<
 * @since 1.8.0
 */
export type CustomCollectionCursor<
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends Context<TContextData>,
  TContextData,
> = (
  context: TContext,
  values: TParams,
  values: Record<TParam, string>,
) => string | null | Promise<string | null>;
+23 −101
Original line number Diff line number Diff line
@@ -457,7 +457,7 @@ export interface Federatable<TContextData> {
    inboxPath: `${string}{identifier}${string}` | `${string}{handle}${string}`,
    sharedInboxPath?: string,
  ): InboxListenerSetters<TContextData>;
  /**
  /** ß
   * Registers a collection of objects dispatcher.
   *
   * @template TContextData The context data to pass to the {@link Context}.
@@ -471,21 +471,19 @@ export interface Federatable<TContextData> {
   *             The path must have one or more variables.
   * @param dispatcher A collection dispatcher callback to register.
   */
  setCollectionDispatcher<
    TObject extends Object,
    TParams extends Record<string, string>,
  >(
  setCollectionDispatcher<TObject extends Object, TParam extends string>(
    name: string | symbol,
    itemType: ConstructorWithTypeId<TObject>,
    path: ParamsKeyPath<TParams>,
    // deno-lint-ignore no-explicit-any
    itemType: (new (...args: any[]) => TObject) & { typeId: URL },
    path: `${string}${Rfc6570Expression<TParam>}${string}`,
    dispatcher: CustomCollectionDispatcher<
      TObject,
      TParams,
      TParam,
      RequestContext<TContextData>,
      TContextData
    >,
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    RequestContext<TContextData>,
    TContextData
  >;
@@ -506,19 +504,20 @@ export interface Federatable<TContextData> {
   */
  setOrderedCollectionDispatcher<
    TObject extends Object,
    TParams extends Record<string, string>,
    TParam extends string,
  >(
    name: string | symbol,
    itemType: ConstructorWithTypeId<TObject>,
    path: ParamsKeyPath<TParams>,
    // deno-lint-ignore no-explicit-any
    itemType: (new (...args: any[]) => TObject) & { typeId: URL },
    path: `${string}${Rfc6570Expression<TParam>}${string}`,
    dispatcher: CustomCollectionDispatcher<
      TObject,
      TParams,
      TParam,
      RequestContext<TContextData>,
      TContextData
    >,
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    RequestContext<TContextData>,
    TContextData
  >;
@@ -1035,14 +1034,14 @@ export interface FederationFetchOptions<TContextData> {
/**
 * Additional settings for a custom collection dispatcher.
 *
 * @template TParams The type of the parameters in the URL path.
 * @template TParam The type of the parameters in the URL path.
 * @template TContext The type of the context.  {@link Context} or
 *                     {@link RequestContext}.
 * @template TContextData The context data to pass to the {@link Context}.
 * @template TFilter The type of filter for the collection.
 */
export interface CustomCollectionCallbackSetters<
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends Context<TContextData>,
  TContextData,
> {
@@ -1053,11 +1052,11 @@ export interface CustomCollectionCallbackSetters<
   */
  setCounter(
    counter: CustomCollectionCounter<
      TParams,
      TParam,
      TContextData
    >,
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    TContext,
    TContextData
  >;
@@ -1069,12 +1068,12 @@ export interface CustomCollectionCallbackSetters<
   */
  setFirstCursor(
    cursor: CustomCollectionCursor<
      TParams,
      TParam,
      TContext,
      TContextData
    >,
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    TContext,
    TContextData
  >;
@@ -1086,12 +1085,12 @@ export interface CustomCollectionCallbackSetters<
   */
  setLastCursor(
    cursor: CustomCollectionCursor<
      TParams,
      TParam,
      TContext,
      TContextData
    >,
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    TContext,
    TContextData
  >;
@@ -1105,7 +1104,7 @@ export interface CustomCollectionCallbackSetters<
  authorize(
    predicate: ObjectAuthorizePredicate<TContextData, string>,
  ): CustomCollectionCallbackSetters<
    TParams,
    TParam,
    TContext,
    TContextData
  >;
@@ -1120,47 +1119,6 @@ export interface CustomCollectionCallbackSetters<
export type ConstructorWithTypeId<TObject extends Object> =
  // deno-lint-ignore no-explicit-any
  (new (...args: any[]) => TObject) & { typeId: URL };

/**
 * Represents a path from the key of parameter objects.
 * @param Params - A record of parameters where keys are parameter names and
 *                 values are their string representations.
 * @returns A string representing the path with all parameters.
 * @example
 * ```ts
 * type UserPostPath = ParamsKeyPath<{ userId: string; postId: string }>;
 * let userPostPath: UserPostPath;
 * // userPostPath = "/posts/{postId}"; // invalid - does not contain `{userId}`
 * // userPostPath = "/users/{userId}"; // invalid - does not contain `{postId}`
 * userPostPath = "/users/{userId}/posts/{postId}"; // valid
 * userPostPath = "/posts/{postId}/users/{userId}"; // valid
 * ```
 */
export type ParamsKeyPath<Params extends Record<string, string>> =
  & ParamPath<Extract<keyof Params, string>>
  & string;

/**
 * Represents a path with multiple parameters.
 * All permutations of the parameters are included in the union type.
 * The path must have all parameters in the form of `{paramName}`.
 * @param Params - A union of parameter names.
 * @returns A string representing the path with all parameters.
 * @example
 * ```ts
 * type UserPostPath = ParamsPath<"userId" | "postId">;
 * // = `${string}{userId}${string}` & `${string}{postId}${string}`
 * // =
 * //  | `${string}{userId}${string}{postId}${string}`
 * //  | `${string}{postId}${string}{userId}${string}`
 * let userPostPath: UserPostPath;
 * userPostPath = "/users/posts"; // ❌ invalid
 * userPostPath = "/users/{userId}"; // ❌ invalid
 * userPostPath = "/posts/{postId}"; // ❌ invalid
 * userPostPath = "/users/{userId}/posts/{postId}"; // ✅ valid
 * userPostPath = "/posts/{postId}/users/{userId}"; // ✅ valid
 */
type ParamsPath<Params extends string> = UnionToIntersection<ParamPath<Params>>;
/**
 * Defines a union of all valid RFC 6570 URI Template expressions for a given
 * parameter name.
@@ -1189,7 +1147,7 @@ type ParamsPath<Params extends string> = UnionToIntersection<ParamPath<Params>>;
 * ```
 * @see {@link https://tools.ietf.org/html/rfc6570} for the full specification.
 */
type Rfc6570Expression<Param extends string> =
export type Rfc6570Expression<Param extends string> =
  | `{${Param}}`
  | `{+${Param}}`
  | `{#${Param}}`
@@ -1198,39 +1156,3 @@ type Rfc6570Expression<Param extends string> =
  | `{;${Param}}`
  | `{?${Param}}`
  | `{&${Param}}`;
/**
 * Represents a path with a single parameter.
 * The path must have at least one of the parameters in the form of `{paramName}`.
 * @param Param - The name of the parameter.
 * @returns A string representing the path with the parameter.
 * @example
 * ```ts
 * type UserPostPath = ParamPath<"userId" | "postId">;
 * // = `${string}{userId}${string}` | `${string}{postId}${string}`
 * let userPostPath: UserPostPath;
 * userPostPath = "/users/posts"; // ❌ invalid
 * userPostPath = "/users/{userId}"; // ✅ valid
 * userPostPath = "/posts/{postId}"; // ✅ valid
 * userPostPath = "/users/{userId}/posts/{postId}"; // ✅ valid
 * userPostPath = "/posts/{postId}/users/{userId}"; // ✅ valid
 */
type ParamPath<Param extends string> = `${string}${Rfc6570Expression<
  Param
>}${string}`;
/**
 * Converts union types to intersection types.
 *
 * @template U - The union type to convert.
 * @returns The intersection type of the union.
 * @example
 * ```ts
 * type A = { a: string };
 * type B = { b: number };
 * type AorB = A | B;
 * type AandB = UnionToIntersection<AorB>;
 * // AandB = { a: string; b: number }
 */
type UnionToIntersection<U> =
  (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void)
    ? I
    : never;
+5 −5
Original line number Diff line number Diff line
@@ -1543,7 +1543,7 @@ test("handleCustomCollection()", async () => {
  // Mock dispatcher similar to collection dispatcher pattern
  const dispatcher: CustomCollectionDispatcher<
    Create,
    Record<string, string>,
    string,
    RequestContext<void>,
    void
  > = (
@@ -1568,13 +1568,13 @@ test("handleCustomCollection()", async () => {
    return { items };
  };

  const counter: CustomCollectionCounter<Record<string, string>, void> = (
  const counter: CustomCollectionCounter<string, void> = (
    _ctx: RequestContext<void>,
    values: Record<string, string>,
  ) => values.handle === "someone" ? 3 : null;

  const firstCursor: CustomCollectionCursor<
    Record<string, string>,
    string,
    RequestContext<void>,
    void
  > = (
@@ -1583,7 +1583,7 @@ test("handleCustomCollection()", async () => {
  ) => values.handle === "someone" ? "0" : null;

  const lastCursor: CustomCollectionCursor<
    Record<string, string>,
    string,
    RequestContext<void>,
    void
  > = (
@@ -1593,7 +1593,7 @@ test("handleCustomCollection()", async () => {

  const callbacks: CustomCollectionCallbacks<
    Create,
    Record<string, string>,
    string,
    RequestContext<void>,
    void
  > = {
+23 −23
Original line number Diff line number Diff line
@@ -862,14 +862,14 @@ async function handleInboxInternal<TContextData>(
/**
 * Callbacks for handling a custom collection.
 * @template TItem The type of items in the collection.
 * @template TParams The parameter names of the requested URL.
 * @template TParam The parameter names of the requested URL.
 * @template TContext The type of the context. {@link Context} or {@link RequestContext}.
 * @template TContextData The context data to pass to the `TContext`.
 * @since 1.8.0
 */
export interface CustomCollectionCallbacks<
  TItem,
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends Context<TContextData>,
  TContextData,
> {
@@ -878,7 +878,7 @@ export interface CustomCollectionCallbacks<
   */
  dispatcher: CustomCollectionDispatcher<
    TItem,
    TParams,
    TParam,
    TContext,
    TContextData
  >;
@@ -886,24 +886,24 @@ export interface CustomCollectionCallbacks<
  /**
   * A callback that counts the number of items in a custom collection.
   */
  counter?: CustomCollectionCounter<TParams, TContextData>;
  counter?: CustomCollectionCounter<TParam, TContextData>;

  /**
   * A callback that returns the first cursor for a custom collection.
   */
  firstCursor?: CustomCollectionCursor<TParams, TContext, TContextData>;
  firstCursor?: CustomCollectionCursor<TParam, TContext, TContextData>;

  /**
   * A callback that returns the last cursor for a custom collection.
   */
  lastCursor?: CustomCollectionCursor<TParams, TContext, TContextData>;
  lastCursor?: CustomCollectionCursor<TParam, TContext, TContextData>;

  /**
   * A callback that determines if a request is authorized to access the custom collection.
   */
  authorizePredicate?: ObjectAuthorizePredicate<
    TContextData,
    keyof TParams & string
    keyof TParam & string
  >;
}

@@ -917,17 +917,17 @@ export interface CustomCollectionCallbacks<
 */
export interface CustomCollectionHandlerParameters<
  TItem,
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends RequestContext<TContextData>,
  TContextData,
> extends ErrorHandlers {
  name: string;
  values: TParams;
  values: Record<TParam, string>;
  filterPredicate?: (item: TItem) => boolean;
  context: TContext;
  collectionCallbacks?: CustomCollectionCallbacks<
    TItem,
    TParams,
    TParam,
    TContext,
    TContextData
  >;
@@ -937,7 +937,7 @@ export interface CustomCollectionHandlerParameters<
/**
 * Handles a custom collection request.
 * @template TItem The type of items in the collection.
 * @template TParams The parameter names of the requested URL.
 * @template TParam The parameter names of the requested URL.
 * @template TContext The type of the context, extending {@link RequestContext}.
 * @template TContextData The context data to pass to the `TContext`.
 * @param request The HTTP request.
@@ -947,21 +947,21 @@ export interface CustomCollectionHandlerParameters<
 */
export const handleCustomCollection: <
  TItem extends URL | Object | Link | Recipient,
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends RequestContext<TContextData>,
  TContextData,
>(
  request: Request,
  handleParams: CustomCollectionHandlerParameters<
    TItem,
    TParams,
    TParam,
    TContext,
    TContextData
  >,
) => Promise<Response> = exceptWrapper(_handleCustomCollection);
async function _handleCustomCollection<
  TItem extends URL | Object | Link | Recipient,
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends RequestContext<TContextData>,
  TContextData,
>(
@@ -975,7 +975,7 @@ async function _handleCustomCollection<
    filterPredicate,
  }: CustomCollectionHandlerParameters<
    TItem,
    TParams,
    TParam,
    TContext,
    TContextData
  >,
@@ -1011,21 +1011,21 @@ async function _handleCustomCollection<
 */
export const handleOrderedCollection: <
  TItem extends URL | Object | Link | Recipient,
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends RequestContext<TContextData>,
  TContextData,
>(
  request: Request,
  handleParams: CustomCollectionHandlerParameters<
    TItem,
    TParams,
    TParam,
    TContext,
    TContextData
  >,
) => Promise<Response> = exceptWrapper(_handleOrderedCollection);
async function _handleOrderedCollection<
  TItem extends URL | Object | Link | Recipient,
  TParams extends Record<string, string>,
  TParam extends string,
  TContext extends RequestContext<TContextData>,
  TContextData,
>(
@@ -1039,7 +1039,7 @@ async function _handleOrderedCollection<
    filterPredicate,
  }: CustomCollectionHandlerParameters<
    TItem,
    TParams,
    TParam,
    TContext,
    TContextData
  >,
@@ -1076,7 +1076,7 @@ async function _handleOrderedCollection<
 */
class CustomCollectionHandler<
  TItem extends URL | Object | Link | Recipient,
  TParams extends Record<string, string>,
  TParam extends string,
  TContextData,
  TContext extends RequestContext<TContextData>,
  TCollection extends Collection,
@@ -1106,7 +1106,7 @@ class CustomCollectionHandler<
   */
  #dispatcher: CustomCollectionDispatcher<
    TItem,
    TParams,
    TParam,
    TContext,
    TContextData
  >;
@@ -1125,11 +1125,11 @@ class CustomCollectionHandler<
   */
  constructor(
    private readonly name: string,
    private readonly values: TParams,
    private readonly values: Record<TParam, string>,
    private readonly context: TContext,
    private readonly callbacks: CustomCollectionCallbacks<
      TItem,
      TParams,
      TParam,
      TContext,
      TContextData
    >,
Loading