Unverified Commit e0130819 authored by Hong Minhee's avatar Hong Minhee
Browse files

Fix JSR publishing by removing MockContext export

The MockContext class contained complex type dependencies that caused
JSR's type analyzer to hang indefinitely during the "processing" stage.
This commit removes MockContext from the public API exports.

Users who were using MockContext directly should migrate to using the
createContext(), createRequestContext(), or createInboxContext() helper
functions instead.

Breaking change: MockContext is no longer exported from @fedify/testing

Fixes https://github.com/fedify-dev/fedify/issues/468



Co-Authored-By: default avatarClaude <noreply@anthropic.com>
parent 49edbfcf
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -10,11 +10,13 @@ To be released.

### @fedify/testing

 -  Fixed JSR publishing hanging indefinitely at the *processing* stage.
    Removed all dependencies on *@opentelemetry/api* package to avoid type
    graph analysis issues in JSR when the package is used alongside
    `ResourceDescriptor` from *@fedify/fedify/webfinger*.  The `tracerProvider`
    fields now use `any` type instead of `TracerProvider`.  [[#468], [#470]]
 -  **Breaking change:** The `MockContext` class is no longer exported from
    the public API.  This was necessary to fix JSR publishing hanging
    indefinitely at the *processing* stage, as the class contained complex
    type dependencies that caused JSR's type analyzer to hang during
    processing.  If you were using `MockContext` directly, please use
    `createContext()`, `createRequestContext()`, or `createInboxContext()`
    functions instead.  [[#468], [#470]]

[#468]: https://github.com/fedify-dev/fedify/issues/468
[#470]: https://github.com/fedify-dev/fedify/pull/470
+58 −1
Original line number Diff line number Diff line
// deno-lint-ignore-file no-explicit-any
import type { Context, Federation } from "@fedify/fedify/federation";
import type {
  Context,
  Federation,
  InboxContext,
  RequestContext,
} from "@fedify/fedify/federation";
import { RouterError } from "@fedify/fedify/federation";
import {
  lookupObject as globalLookupObject,
@@ -122,3 +127,55 @@ export function createContext<TContextData>(
    }),
  };
}

/**
 * Creates a RequestContext for testing purposes.
 * @param args Partial RequestContext properties
 * @returns A RequestContext instance
 * @since 1.8.0
 */
export function createRequestContext<TContextData>(
  args: Partial<RequestContext<TContextData>> & {
    url: URL;
    data: TContextData;
    federation: Federation<TContextData>;
  },
): RequestContext<TContextData> {
  return {
    ...createContext(args),
    clone: args.clone ?? ((data) => createRequestContext({ ...args, data })),
    request: args.request ?? new Request(args.url),
    url: args.url,
    getActor: args.getActor ?? (() => Promise.resolve(null)),
    getObject: args.getObject ?? (() => Promise.resolve(null)),
    getSignedKey: args.getSignedKey ?? (() => Promise.resolve(null)),
    getSignedKeyOwner: args.getSignedKeyOwner ?? (() => Promise.resolve(null)),
    sendActivity: args.sendActivity ?? ((_params) => {
      throw new Error("Not implemented");
    }),
  };
}

/**
 * Creates an InboxContext for testing purposes.
 * @param args Partial InboxContext properties
 * @returns An InboxContext instance
 * @since 1.8.0
 */
export function createInboxContext<TContextData>(
  args: Partial<InboxContext<TContextData>> & {
    url?: URL;
    data: TContextData;
    recipient?: string | null;
    federation: Federation<TContextData>;
  },
): InboxContext<TContextData> {
  return {
    ...createContext(args),
    clone: args.clone ?? ((data) => createInboxContext({ ...args, data })),
    recipient: args.recipient ?? null,
    forwardActivity: args.forwardActivity ?? ((_params) => {
      throw new Error("Not implemented");
    }),
  };
}
+31 −31
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import type {
  Recipient,
  TraverseCollectionOptions,
} from "@fedify/fedify/vocab";
import type { ResourceDescriptor } from "@fedify/fedify/webfinger";
import { createContext } from "./context.ts";

// Re-export createContext for public API
@@ -42,9 +41,10 @@ export { createContext };

// Create a no-op tracer provider.
// We use `any` type instead of importing TracerProvider from @opentelemetry/api
// to avoid type graph analysis issues in JSR. When @opentelemetry/api types are
// imported alongside ResourceDescriptor from @fedify/fedify/webfinger, JSR's type
// analyzer hangs indefinitely during the "processing" stage.
// to avoid type graph analysis issues in JSR. When types from @opentelemetry/api
// are imported (either directly or indirectly through other @fedify modules like
// @fedify/fedify/webfinger which uses ResourceDescriptor), JSR's type analyzer
// hangs indefinitely during the "processing" stage.
// See: https://github.com/fedify-dev/fedify/issues/468
const noopTracerProvider: any = {
  getTracer: () => ({
@@ -511,40 +511,40 @@ export class MockFederation<TContextData> implements Federation<TContextData> {
    // deno-lint-ignore no-this-alias
    const mockFederation = this;

    // sendActivity implementation for mock contexts
    const sendActivity = (
      _sender: any,
      _recipients: any,
      activity: any,
      _options?: any,
    ): Promise<void> => {
      const queued = mockFederation.queueStarted;
      mockFederation.sentActivities.push({
        queued,
        queue: queued ? "outbox" : undefined,
        activity,
        sentOrder: ++mockFederation.sentCounter,
      });
      return Promise.resolve();
    };

    if (baseUrlOrRequest instanceof Request) {
      // For now, we'll use createRequestContext since MockContext doesn't support Request
      // But we need to ensure the sendActivity behavior is consistent
      return createRequestContext({
        url: new URL(baseUrlOrRequest.url),
        request: baseUrlOrRequest,
        data: contextData,
        federation: mockFederation as any,
        sendActivity: (async (
          sender: any,
          recipients: any,
          activity: any,
          options: any,
        ) => {
          // Create a temporary MockContext to use its sendActivity logic
          const tempContext = new MockContext({
            url: new URL(baseUrlOrRequest.url),
            data: contextData,
            federation: mockFederation as any,
          });
          await tempContext.sendActivity(
            sender,
            recipients,
            activity,
            options,
          );
        }) as any,
        sendActivity: sendActivity as any,
      });
    } else {
      return new MockContext({
      return {
        ...createContext({
          url: baseUrlOrRequest,
          data: contextData,
          federation: mockFederation as any,
      });
        }),
        sendActivity: sendActivity as any,
      } as Context<TContextData>;
    }
  }

@@ -963,7 +963,7 @@ export class MockContext<TContextData> implements Context<TContextData> {
  lookupWebFinger(
    _resource: URL | `acct:${string}@${string}` | string,
    _options?: any,
  ): Promise<ResourceDescriptor | null> {
  ): Promise<any> {
    return Promise.resolve(null);
  }

+6 −3
Original line number Diff line number Diff line
@@ -9,6 +9,9 @@
 */

export type { SentActivity } from "./mock.ts";
export { MockContext, MockFederation } from "./mock.ts";
export { mockDocumentLoader } from "./docloader.ts";
export { createContext } from "./context.ts";
export { MockFederation } from "./mock.ts";
export {
  createContext,
  createInboxContext,
  createRequestContext,
} from "./context.ts";