Unverified Commit 49edbfcf authored by Hong Minhee's avatar Hong Minhee
Browse files

Fix JSR publishing hang by removing @opentelemetry/api dependency

Removed all dependencies on @opentelemetry/api package from @fedify/testing
to resolve JSR publishing issues. When @opentelemetry/api types were imported
alongside ResourceDescriptor from @fedify/fedify/webfinger, JSR's type graph
analyzer would hang indefinitely during the "processing" stage.

Changes:

- Removed @opentelemetry/api from package.json dependencies
- Removed @opentelemetry/api from deno.json imports
- Removed @opentelemetry/api from tsdown.config.ts external list
- Replaced TracerProvider type with `any` in mock.ts and context.ts
- Implemented no-op tracer provider inline to avoid external dependency
- Added detailed comments explaining the workaround
- Added deno-lint-ignore-file directives for no-explicit-any
- Moved createRequestContext and createInboxContext from context.ts to mock.ts
- Updated CHANGES.md with fix details

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



Co-Authored-By: default avatarClaude <noreply@anthropic.com>
parent 1e16969f
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -8,6 +8,17 @@ Version 1.8.14

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]]

[#468]: https://github.com/fedify-dev/fedify/issues/468
[#470]: https://github.com/fedify-dev/fedify/pull/470

### @fedify/cli

 -  Fixed `fedify` command failing on Windows with `PermissionDenied` error
+0 −3
Original line number Diff line number Diff line
@@ -5,9 +5,6 @@
  "exports": {
    ".": "./src/mod.ts"
  },
  "imports": {
    "@opentelemetry/api": "npm:@opentelemetry/api@^1.9.0"
  },
  "exclude": [
    "dist",
    "node_modules",
+0 −3
Original line number Diff line number Diff line
@@ -47,9 +47,6 @@
  "peerDependencies": {
    "@fedify/fedify": "workspace:^"
  },
  "dependencies": {
    "@opentelemetry/api": "^1.9.0"
  },
  "devDependencies": {
    "@js-temporal/polyfill": "catalog:",
    "@std/assert": "catalog:",
+16 −48
Original line number Diff line number Diff line
import type {
  Context,
  Federation,
  InboxContext,
  RequestContext,
} from "@fedify/fedify/federation";
// deno-lint-ignore-file no-explicit-any
import type { Context, Federation } from "@fedify/fedify/federation";
import { RouterError } from "@fedify/fedify/federation";
import {
  lookupObject as globalLookupObject,
  traverseCollection as globalTraverseCollection,
} from "@fedify/fedify/vocab";
import { lookupWebFinger as globalLookupWebFinger } from "@fedify/fedify/webfinger";
import { trace } from "@opentelemetry/api";
import { mockDocumentLoader } from "./docloader.ts";

// 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.
// See: https://github.com/fedify-dev/fedify/issues/468
const noopTracerProvider: any = {
  getTracer: () => ({
    startActiveSpan: () => undefined as any,
    startSpan: () => undefined as any,
  }),
};

// NOTE: Copied from @fedify/fedify/testing/context.ts

export function createContext<TContextData>(
@@ -64,7 +72,7 @@ export function createContext<TContextData>(
    hostname: url.hostname,
    documentLoader: documentLoader ?? mockDocumentLoader,
    contextLoader: contextLoader ?? mockDocumentLoader,
    tracerProvider: tracerProvider ?? trace.getTracerProvider(),
    tracerProvider: tracerProvider ?? noopTracerProvider,
    clone: clone ?? ((data) => createContext({ ...values, data })),
    getNodeInfoUri: getNodeInfoUri ?? throwRouteError,
    getActorUri: getActorUri ?? throwRouteError,
@@ -114,43 +122,3 @@ export function createContext<TContextData>(
    }),
  };
}

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");
    }),
  };
}

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");
    }),
  };
}
+73 −6
Original line number Diff line number Diff line
@@ -35,8 +35,23 @@ import type {
  TraverseCollectionOptions,
} from "@fedify/fedify/vocab";
import type { ResourceDescriptor } from "@fedify/fedify/webfinger";
import { trace, type TracerProvider } from "@opentelemetry/api";
import { createInboxContext, createRequestContext } from "./context.ts";
import { createContext } from "./context.ts";

// Re-export createContext for public API
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.
// See: https://github.com/fedify-dev/fedify/issues/468
const noopTracerProvider: any = {
  getTracer: () => ({
    startActiveSpan: () => undefined as any,
    startSpan: () => undefined as any,
  }),
};

/**
 * Helper function to expand URI templates with values.
@@ -54,6 +69,58 @@ function expandUriTemplate(
  });
}

/**
 * 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");
    }),
  };
}

/**
 * Represents a sent activity with metadata about how it was sent.
 * @since 1.8.0
@@ -176,7 +243,7 @@ export class MockFederation<TContextData> implements Federation<TContextData> {
    private options: {
      contextData?: TContextData;
      origin?: string;
      tracerProvider?: TracerProvider;
      tracerProvider?: any;
    } = {},
  ) {
    this.contextData = options.contextData;
@@ -628,7 +695,7 @@ export class MockContext<TContextData> implements Context<TContextData> {
  readonly federation: Federation<TContextData>;
  readonly documentLoader: DocumentLoader;
  readonly contextLoader: DocumentLoader;
  readonly tracerProvider: TracerProvider;
  readonly tracerProvider: any;

  private sentActivities: Array<{
    sender: any;
@@ -643,7 +710,7 @@ export class MockContext<TContextData> implements Context<TContextData> {
      federation: Federation<TContextData>;
      documentLoader?: DocumentLoader;
      contextLoader?: DocumentLoader;
      tracerProvider?: TracerProvider;
      tracerProvider?: any;
    },
  ) {
    const url = options.url ?? new URL("https://example.com");
@@ -660,7 +727,7 @@ export class MockContext<TContextData> implements Context<TContextData> {
      documentUrl: url,
    }));
    this.contextLoader = options.contextLoader ?? this.documentLoader;
    this.tracerProvider = options.tracerProvider ?? trace.getTracerProvider();
    this.tracerProvider = options.tracerProvider ?? noopTracerProvider;
  }

  clone(data: TContextData): Context<TContextData> {
Loading