Unverified Commit 1c2cf440 authored by Hong Minhee's avatar Hong Minhee
Browse files

Merge tag '1.8.14' into 1.9-maintenance

Fedify 1.8.14
parents 78b4d251 82240877
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -8,6 +8,21 @@ Version 1.9.1

To be released.

### @fedify/testing

 -  Fixed JSR publishing hanging indefinitely at the *processing* stage.
    The issue was caused by TypeScript function overload signatures in
    `MockContext` and `MockFederation` classes that triggered a bug in JSR's
    type analyzer.  All method overloads have been removed and simplified to
    use `any` types where necessary.  [[#468], [#470]]

### @fedify/cli

 -  Fixed `fedify` command failing on Windows with `PermissionDenied` error
    when trying to locate or execute package managers during initialization.
    The CLI now properly handles _\*.cmd_ and _\*.bat_ files on Windows by
    invoking them through `cmd /c`.  [[#463]]


Version 1.9.0
-------------
@@ -298,6 +313,32 @@ Released on October 14, 2025.
    CommonJS-based Node.js applications.  [[#429], [#431]]


Version 1.8.14
--------------

Released on October 19, 2025.

### @fedify/testing

 -  Fixed JSR publishing hanging indefinitely at the *processing* stage.
    The issue was caused by TypeScript function overload signatures in
    `MockContext` and `MockFederation` classes that triggered a bug in JSR's
    type analyzer.  All method overloads have been removed and simplified to
    use `any` types where necessary.  [[#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
    when trying to locate or execute package managers during initialization.
    The CLI now properly handles _\*.cmd_ and _\*.bat_ files on Windows by
    invoking them through `cmd /c`.  [[#463]]

[#463]: https://github.com/fedify-dev/fedify/issues/463


Version 1.8.13
--------------

+0 −10
Original line number Diff line number Diff line
@@ -4838,16 +4838,6 @@
          "jsr:@std/assert@^1.0.13",
          "npm:@sveltejs/kit@2"
        ]
      },
      "packages/testing": {
        "dependencies": [
          "npm:@opentelemetry/api@^1.9.0"
        ],
        "packageJson": {
          "dependencies": [
            "npm:@opentelemetry/api@^1.9.0"
          ]
        }
      }
    }
  }
+35 −37
Original line number Diff line number Diff line
@@ -230,23 +230,22 @@ await federation.receiveActivity(activity);
console.log("Sent activities:", federation.sentActivities);
~~~~

### `MockContext`
### Creating mock contexts

The `MockContext` class provides a mock implementation of the `Context`
interface that tracks sent activities and provides mock implementations of
URI generation methods:
You can create mock contexts using `MockFederation.createContext()` method,
which provides a mock implementation of the `Context` interface that tracks
sent activities and provides mock implementations of URI generation methods:

~~~~ typescript twoslash
import { MockContext, MockFederation } from "@fedify/testing";
import { MockFederation } from "@fedify/testing";
import { Create, Note, Person } from "@fedify/fedify/vocab";

// Create a mock federation and context
const federation = new MockFederation<{ userId: string }>();
const context = new MockContext({
  url: new URL("https://example.com"),
  data: { userId: "test-user" },
  federation: federation
});
const context = federation.createContext(
  new URL("https://example.com"),
  { userId: "test-user" }
);

// Send an activity
const activity = new Create({
@@ -274,11 +273,12 @@ console.log("Federation sent activities:", federation.sentActivities);

### Testing URI generation

`MockContext` provides mock implementations of all URI generation methods
that work with the paths configured in your `MockFederation`:
Mock contexts created with `MockFederation.createContext()` provide mock
implementations of all URI generation methods that work with the paths
configured in your `MockFederation`:

~~~~ typescript twoslash
import { MockContext, MockFederation } from "@fedify/testing";
import { MockFederation } from "@fedify/testing";
import { Note } from "@fedify/fedify/vocab";

const federation = new MockFederation();
@@ -303,37 +303,36 @@ console.log(context.getObjectUri(Note, { id: "123" })); // https://example.com/n

### Tracking sent activities

Both `MockFederation` and `MockContext` track sent activities with detailed
Both `MockFederation` and mock contexts track sent activities with detailed
metadata:

~~~~ typescript twoslash
// @noErrors: 2554
import { MockContext, MockFederation } from "@fedify/testing";
import { MockFederation } from "@fedify/testing";

const federation = new MockFederation();
const context = new MockContext({
  federation,
  url: new URL("https://example.com/"),
  data: undefined,
});
const context = federation.createContext(
  new URL("https://example.com/"),
  undefined
);

// Send some activities...
await context.sendActivity(/* ... */);

// Check federation-level tracking
federation.sentActivities.forEach(sent => {
for (const sent of federation.sentActivities) {
  console.log("Activity:", sent.activity.id);
  console.log("Queued:", sent.queued);
  console.log("Queue type:", sent.queue);
  console.log("Send order:", sent.sentOrder);
});
}

// Check context-level tracking
context.getSentActivities().forEach(sent => {
for (const sent of context.getSentActivities()) {
  console.log("Sender:", sent.sender);
  console.log("Recipients:", sent.recipients);
  console.log("Activity:", sent.activity);
});
}
~~~~

### Simulating queue processing
@@ -342,7 +341,7 @@ You can test queue-based activity processing by starting the mock queue:

~~~~ typescript twoslash
// @noErrors: 2554
import { MockContext, MockFederation } from "@fedify/testing";
import { MockFederation } from "@fedify/testing";

const federation = new MockFederation();

@@ -350,11 +349,10 @@ const federation = new MockFederation();
await federation.startQueue({ contextData: { userId: "test" } });

// Now sent activities will be marked as queued
const context = new MockContext({
  federation,
  url: new URL("https://example.com/"),
  data: { userId: "test" },
})
const context = federation.createContext(
  new URL("https://example.com/"),
  { userId: "test" }
);
await context.sendActivity(/* ... */);

// Check if activities were queued
@@ -364,16 +362,16 @@ console.log("Queued activities:", queued.length);

### Resetting mock state

Both mock classes provide `reset()` methods to clear tracked activities:
Both `MockFederation` and mock contexts provide `reset()` methods to clear
tracked activities:

~~~~ typescript twoslash
import { MockContext, MockFederation } from "@fedify/testing";
import { MockFederation } from "@fedify/testing";
const federation = new MockFederation();
const context = new MockContext({
  federation,
  url: new URL("https://example.com/"),
  data: undefined,
});
const context = federation.createContext(
  new URL("https://example.com/"),
  undefined
);
// ---cut-before---
// Clear all sent activities
federation.reset();
+5 −0
Original line number Diff line number Diff line
@@ -51,10 +51,15 @@ async function pack(os: OS, arch: Arch): Promise<void> {
  }
}

const osFilter = Deno.env.get("OS")?.toLowerCase();
const archFilter = Deno.env.get("ARCH")?.toLowerCase();

const promises: Promise<void>[] = [];
for (const osKey in triplets) {
  const os = osKey as OS;
  if (osFilter != null && osFilter !== os) continue;
  for (const arch in triplets[os]) {
    if (archFilter != null && archFilter !== arch) continue;
    const promise = pack(os, arch as Arch);
    promises.push(promise);
  }
+42 −18
Original line number Diff line number Diff line
@@ -1521,7 +1521,12 @@ async function isCommandAvailable(
      "The command {command} failed with the error: {error}",
      { command: checkCommand, error },
    );
    if (error instanceof Deno.errors.NotFound) return false;
    if (
      error instanceof Deno.errors.NotFound ||
      error instanceof Deno.errors.PermissionDenied
    ) {
      return false;
    }
    throw error;
  }
}
@@ -1538,11 +1543,13 @@ async function locatePackageManager(
  }
  if (Deno.build.os !== "windows") return undefined;
  const cmd: [string, ...string[]] = [
    "cmd",
    "/c",
    packageManagers[pm].checkCommand[0] + ".cmd",
    ...packageManagers[pm].checkCommand.slice(1),
  ];
  if (await isCommandAvailable({ ...packageManagers[pm], checkCommand: cmd })) {
    return cmd[0];
    return cmd[2];
  }
  return undefined;
}
@@ -1569,7 +1576,24 @@ async function addDependencies(
      }`
    );
  if (deps.length < 1) return;
  const cmd = new Deno.Command(
  const cmd =
    runtime === "node" && packageManagerLocations[pm]?.match(/\.cmd$/i)
      ? new Deno.Command(
        "cmd",
        {
          args: [
            "/c",
            `${packageManagerLocations[pm]} add ${
              dev ? (pm === "yarn" ? "--dev" : "--save-dev") : ""
            } ${uniqueArray(deps).join(" ")}`,
          ],
          cwd: dir,
          stdin: "inherit",
          stdout: "inherit",
          stderr: "inherit",
        },
      )
      : new Deno.Command(
        runtime === "node" ? (packageManagerLocations[pm] ?? pm) : runtime,
        {
          args: [
Loading