Loading .github/workflows/build.yaml +13 −10 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - run: deno task test --coverage=.cov --junit-path=.test-report.xml env: RUST_BACKTRACE: ${{ runner.debug }} Loading Loading @@ -124,7 +124,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading Loading @@ -181,7 +181,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading @@ -207,7 +207,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading @@ -230,7 +230,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - run: deno task hooks:pre-commit release-test: Loading @@ -248,7 +248,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading Loading @@ -283,7 +283,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading Loading @@ -332,7 +332,7 @@ jobs: working-directory: ${{ github.workspace }}/fedify/ - run: | pnpm install pnpm pack --recursive pnpm pack --recursive --filter='!./examples/**' if [[ "$GITHUB_REF_TYPE" != tag ]]; then rm fedify-cli-*.tgz fi Loading Loading @@ -426,6 +426,7 @@ jobs: | @fedify/nestjs | ${{ steps.versioning.outputs.version }} | | [npm][npm:@fedify/nestjs] | | @fedify/postgres | ${{ steps.versioning.outputs.version }} | [JSR][jsr:@fedify/postgres] | [npm][npm:@fedify/postgres] | | @fedify/redis | ${{ steps.versioning.outputs.version }} | [JSR][jsr:@fedify/redis] | [npm][npm:@fedify/redis] | | @fedify/testing | ${{ steps.versioning.outputs.version }} | [JSR][jsr:@fedify/testing] | [npm][npm:@fedify/testing] | [jsr:@fedify/fedify]: https://jsr.io/@fedify/fedify@${{ steps.versioning.outputs.version }} [npm:@fedify/fedify]: https://www.npmjs.com/package/@fedify/fedify/v/${{ steps.versioning.outputs.short_version }} Loading @@ -441,6 +442,8 @@ jobs: [npm:@fedify/postgres]: https://www.npmjs.com/package/@fedify/postgres/v/${{ steps.versioning.outputs.short_version }} [jsr:@fedify/redis]: https://jsr.io/@fedify/redis@${{ steps.versioning.outputs.version }} [npm:@fedify/redis]: https://www.npmjs.com/package/@fedify/redis/v/${{ steps.versioning.outputs.short_version }} [jsr:@fedify/testing]: https://jsr.io/@fedify/testing@${{ steps.versioning.outputs.version }} [npm:@fedify/testing]: https://www.npmjs.com/package/@fedify/testing/v/${{ steps.versioning.outputs.short_version }} pr-number: ${{ github.event.pull_request.number }} comment-tag: publish Loading @@ -461,7 +464,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - run: deno task codegen working-directory: ${{ github.workspace }}/fedify/ - uses: denoland/deployctl@v1 Loading Loading @@ -492,7 +495,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading CHANGES.md +62 −19 Original line number Diff line number Diff line Loading @@ -63,15 +63,6 @@ the versioning. - Added `LookupWebFingerOptions.maxRedirection` option. [[#248], [#281] by Lee ByeongJun] - Optimized `doubleKnock()` function to avoid multiple request body clones during redirects. The request body is now read once and reused throughout the entire operation, preventing potential `TypeError: unusable` errors and improving performance. [[#300] by Fabien O'Carroll] - Added `SignRequestOptions.body` option. - Added `DoubleKnockOptions.body` option. - Updated internal signing functions to accept pre-read body buffers. - Added `fedify webfinger` command. This command allows users to look up WebFinger information for a given resource. [[#260], [#278] by ChanHaeng Lee] Loading @@ -82,14 +73,17 @@ the versioning. in the WebFinger request. - The `--allow-private-address` or `-p` option allows looking up WebFinger information for private addresses (e.g., `localhost`). - The `--max-redirection` option allows uses to specify the maximum number of redirects to follow when performing WebFinger lookups. [[#311], [#328] by KeunHyeong Park] - Added `--dry-run` option to `fedify init` command. This option allows users to preview what files and configurations would be created without actually creating them. [[#263], [#298] by Lee ByeongJun] - Fixed a bug where the `fedify node` command had failed to correctly render the favicon in terminal emulators that do not support 24-bit colors. [[#168], [#282], [#304] by Hyeonseo Kim] - Fixed a bug where the `fedify nodeinfo` command (was `fedify node`) had failed to correctly render the favicon in terminal emulators that do not support 24-bit colors. [[#168], [#282], [#304] by Hyeonseo Kim] - Supported NestJS integration with the `@fedify/nestjs` package. [[#269], [#309] by Jaeyeol Lee] Loading @@ -97,18 +91,43 @@ the versioning. - Added `@fedify/nestjs` package. - Added `FedifyModule` for integrating Fedify into NestJS applications. - Supported `KvStore` using SQLite with the `@fedify/sqlite` package, compatible with Bun, Deno and Node.js. [[#274], [#318] By An Subin] - Added `SqliteKvStore`, implementing `KvStore` using SQLite with the `@fedify/sqlite` package. Compatible with Bun, Deno, and Node.js. [[#274], [#318] by An Subin] - Added `@fedify/sqlite` package. - Added `SqliteKvStore`, SQLite implementation of KvStore. - Added `SqliteKvStore`, a SQLite implementation of `KvStore`. - Added `-o`/`--output` option to `fedify lookup` command. This option allows users to save retrieved lookup results to specified path. [[#261], [#321] by Jiwon Kwon] - Added `fedify nodeinfo` command, and deprecated `fedify node` command in favor of `fedify nodeinfo`. [[#267], [#331] by Hyeonseo Kim] - Added custom collection dispatchers. [[#310], [#332] by ChanHaeng Lee] - Added `CustomCollectionDispatcher`, `CustomCollectionCounter`, and `CustomCollectionCursor` types for custom collection dispatching. - Added `CustomCollectionCallbackSetters` type for setting custom collection callbacks. - Added `CustomCollectionHandler` class and `handleCustomCollection()` and `handleOrderedCollection()` functions to process custom collections. - Added `setCollectionDispatcher()` and `setOrderedCollectionDispatcher()` methods to the `Federatable` interface. Implemented in `FederationBuilderImpl` class. - Added `getCollectionUri()` method to the `Context` interface. - Added utility types `ConstructorWithTypeId` and `ParamsKeyPath` for custom collection dispatchers. [#168]: https://github.com/fedify-dev/fedify/issues/168 [#197]: https://github.com/fedify-dev/fedify/issues/197 [#248]: https://github.com/fedify-dev/fedify/issues/248 [#260]: https://github.com/fedify-dev/fedify/issues/260 [#261]: https://github.com/fedify-dev/fedify/issues/261 [#262]: https://github.com/fedify-dev/fedify/issues/262 [#263]: https://github.com/fedify-dev/fedify/issues/263 [#267]: https://github.com/fedify-dev/fedify/issues/267 [#269]: https://github.com/fedify-dev/fedify/issues/269 [#278]: https://github.com/fedify-dev/fedify/pull/278 [#281]: https://github.com/fedify-dev/fedify/pull/281 Loading @@ -116,11 +135,35 @@ the versioning. [#283]: https://github.com/fedify-dev/fedify/pull/283 [#285]: https://github.com/fedify-dev/fedify/pull/285 [#298]: https://github.com/fedify-dev/fedify/pull/298 [#300]: https://github.com/fedify-dev/fedify/pull/300 [#304]: https://github.com/fedify-dev/fedify/issues/304 [#309]: https://github.com/fedify-dev/fedify/pull/309 [#274]: https://github.com/fedify-dev/fedify/issues/274 [#318]: https://github.com/fedify-dev/fedify/pull/318 [#310]: https://github.com/fedify-dev/fedify/issues/310 [#311]: https://github.com/fedify-dev/fedify/issues/311 [#321]: https://github.com/fedify-dev/fedify/pull/321 [#328]: https://github.com/fedify-dev/fedify/pull/328 [#331]: https://github.com/fedify-dev/fedify/pull/331 [#332]: https://github.com/fedify-dev/fedify/pull/332 Version 1.7.7 ------------- Released on July 28, 2025. - Optimized `doubleKnock()` function to avoid multiple request body clones during redirects. The request body is now read once and reused throughout the entire operation, preventing potential `TypeError: unusable` errors and improving performance. [[#300], [#335] by Fabien O'Carroll] - Added `SignRequestOptions.body` option. - Added `DoubleKnockOptions.body` option. - Updated internal signing functions to accept pre-read body buffers. [#300]: https://github.com/fedify-dev/fedify/pull/300 [#335]: https://github.com/fedify-dev/fedify/pull/335 Version 1.7.6 Loading cli/deno.json +1 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ "@jimp/core": "npm:@jimp/core@^1.6.0", "@jimp/wasm-webp": "npm:@jimp/wasm-webp@^1.6.0", "@poppanator/http-constants": "npm:@poppanator/http-constants@^1.1.1", "@std/assert": "jsr:@std/assert@^1.0.13", "@std/dotenv": "jsr:@std/dotenv@^0.225.2", "@std/assert": "jsr:@std/assert@^1.0.0", "@std/semver": "jsr:@std/semver@^1.0.5", Loading cli/init.test.ts +78 −31 Original line number Diff line number Diff line Loading @@ -150,37 +150,6 @@ Deno.test("init --dry-run shows command for framework initialization", async () } }); Deno.test("init without --dry-run creates actual files", async () => { const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-actual-project"); try { // Run without --dry-run const result = await runInit([ projectDir, "--runtime", "deno", ]); // Should not show dry-run header assertEquals(result.output.includes("DRY RUN MODE"), false); // Verify files were actually created assertEquals( await exists(projectDir), true, "Project directory should be created", ); assertEquals(await exists(join(projectDir, "federation.ts")), true); assertEquals(await exists(join(projectDir, "logging.ts")), true); assertEquals(await exists(join(projectDir, "main.ts")), true); assertEquals(await exists(join(projectDir, "deno.json")), true); assertEquals(await exists(join(projectDir, ".env")), true); } finally { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init --dry-run fails on non-empty directory", async () => { const testDir = await Deno.makeTempDir(); Loading Loading @@ -251,3 +220,81 @@ Deno.test("init --dry-run shows dev dependencies for Node.js", async () => { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init - check version for AMQP package", async () => { const amqpData = await Deno.readTextFile( join(import.meta.dirname!, "../amqp/deno.json"), ); const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-amqp-project"); try { const result = await runInit([ projectDir, "--dry-run", "--runtime", "deno", "--message-queue", "amqp", ]); assertStringIncludes( result.output, `@fedify/amqp@${JSON.parse(amqpData).version.trim()}`, ); assertEquals(await exists(projectDir), false); } finally { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init - check version for Redis package", async () => { const redisData = await Deno.readTextFile( join(import.meta.dirname!, "../redis/deno.json"), ); const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-redis-project"); try { const result = await runInit([ projectDir, "--dry-run", "--runtime", "deno", "--kv-store", "redis", ]); assertStringIncludes( result.output, `@fedify/redis@${JSON.parse(redisData).version.trim()}`, ); assertEquals(await exists(projectDir), false); } finally { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init - check version for Postgres package", async () => { const postgresData = await Deno.readTextFile( join(import.meta.dirname!, "../postgres/deno.json"), ); const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-postgres-project"); try { const result = await runInit([ projectDir, "--dry-run", "--runtime", "deno", "--kv-store", "postgres", ]); assertStringIncludes( result.output, `@fedify/postgres@${JSON.parse(postgresData).version.trim()}`, ); assertEquals(await exists(projectDir), false); } finally { await Deno.remove(testDir, { recursive: true }); } }); cli/init.ts +24 −26 Original line number Diff line number Diff line Loading @@ -5,9 +5,17 @@ import { getLogger } from "@logtape/logtape"; import { stringify } from "@std/dotenv/stringify"; import { exists } from "@std/fs"; import { basename, dirname, join, normalize } from "@std/path"; import { format, greaterThan, parse } from "@std/semver"; import metadata from "./deno.json" with { type: "json" }; const packagesMetaData: Record<`@fedify/${string}`, string> = { "@fedify/fedify": metadata.version, "@fedify/redis": metadata.version, "@fedify/postgres": metadata.version, "@fedify/amqp": metadata.version, "@fedify/express": metadata.version, "@fedify/h3": metadata.version, }; const logger = getLogger(["fedify", "cli", "init"]); type Runtime = "deno" | "bun" | "node"; Loading Loading @@ -306,7 +314,7 @@ Then, try look up an actor from your server: init: (projectName, runtime, pm) => ({ dependencies: { express: "^4.19.2", "@fedify/express": "^0.2.1", "@fedify/express": getLatestVersion("@fedify/express"), ...(runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", Loading Loading @@ -392,7 +400,7 @@ Then, try look up an actor from your server: ".", ], dependencies: { "@fedify/h3": "^0.1.2", "@fedify/h3": getLatestVersion("@fedify/h3"), }, federationFile: "server/federation.ts", loggingFile: "server/logging.ts", Loading Loading @@ -449,7 +457,7 @@ const kvStores: Record<KvStore, KvStoreDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.2.1", "@fedify/redis": getLatestVersion("@fedify/redis"), "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisKvStore"], ioredis: ["Redis"] }, Loading @@ -465,7 +473,7 @@ const kvStores: Record<KvStore, KvStoreDescription> = { postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.2.0", "@fedify/postgres": getLatestVersion("@fedify/postgres"), "npm:postgres": "^3.4.5", }, imports: { "@fedify/postgres": ["PostgresKvStore"], postgres: "postgres" }, Loading Loading @@ -504,7 +512,7 @@ const messageQueues: Record<MessageQueue, MessageQueueDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.2.1", "@fedify/redis": getLatestVersion("@fedify/redis"), "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisMessageQueue"], ioredis: ["Redis"] }, Loading @@ -520,7 +528,7 @@ const messageQueues: Record<MessageQueue, MessageQueueDescription> = { postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.2.0", "@fedify/postgres": getLatestVersion("@fedify/postgres"), "npm:postgres": "^3.4.5", }, imports: { Loading @@ -539,7 +547,7 @@ const messageQueues: Record<MessageQueue, MessageQueueDescription> = { amqp: { label: "AMQP (e.g., RabbitMQ)", dependencies: { "@fedify/amqp": "^0.1.0", "@fedify/amqp": getLatestVersion("@fedify/amqp"), "npm:amqplib": "^0.10.4", }, devDependencies: { Loading Loading @@ -1069,7 +1077,7 @@ await configure({ } } const dependencies: Record<string, string> = { "@fedify/fedify": `^${await getLatestFedifyVersion(metadata.version)}`, "@fedify/fedify": getLatestVersion("@fedify/fedify"), "@logtape/logtape": "^0.8.2", ...initializer.dependencies, ...kvStoreDesc?.dependencies, Loading Loading @@ -1489,25 +1497,15 @@ async function addDependencies( } } async function getLatestFedifyVersion(version: string): Promise<string> { const response = await fetch("https://jsr.io/@fedify/fedify/meta.json", { headers: { Accept: "application/json", }, }); // deno-lint-ignore no-explicit-any const result = await response.json() as any; let maxVersion = parse("0.0.0"); for (const v in result.versions) { if (v === version) return version; else if (result.versions[v].yanked) continue; const semVer = parse(v); if (semVer.prerelease != null && semVer.prerelease.length > 0) continue; if (greaterThan(semVer, maxVersion)) maxVersion = semVer; function getLatestVersion(packageName: `@fedify/${string}`): string { const version = packagesMetaData[packageName]; if (!version) { throw new Error( `Version for package "${packageName}" not found in local metadata.`, ); } return format(maxVersion); return version; } async function rewriteJsonFile( path: string, // deno-lint-ignore no-explicit-any Loading Loading
.github/workflows/build.yaml +13 −10 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - run: deno task test --coverage=.cov --junit-path=.test-report.xml env: RUST_BACKTRACE: ${{ runner.debug }} Loading Loading @@ -124,7 +124,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading Loading @@ -181,7 +181,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading @@ -207,7 +207,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading @@ -230,7 +230,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - run: deno task hooks:pre-commit release-test: Loading @@ -248,7 +248,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading Loading @@ -283,7 +283,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading Loading @@ -332,7 +332,7 @@ jobs: working-directory: ${{ github.workspace }}/fedify/ - run: | pnpm install pnpm pack --recursive pnpm pack --recursive --filter='!./examples/**' if [[ "$GITHUB_REF_TYPE" != tag ]]; then rm fedify-cli-*.tgz fi Loading Loading @@ -426,6 +426,7 @@ jobs: | @fedify/nestjs | ${{ steps.versioning.outputs.version }} | | [npm][npm:@fedify/nestjs] | | @fedify/postgres | ${{ steps.versioning.outputs.version }} | [JSR][jsr:@fedify/postgres] | [npm][npm:@fedify/postgres] | | @fedify/redis | ${{ steps.versioning.outputs.version }} | [JSR][jsr:@fedify/redis] | [npm][npm:@fedify/redis] | | @fedify/testing | ${{ steps.versioning.outputs.version }} | [JSR][jsr:@fedify/testing] | [npm][npm:@fedify/testing] | [jsr:@fedify/fedify]: https://jsr.io/@fedify/fedify@${{ steps.versioning.outputs.version }} [npm:@fedify/fedify]: https://www.npmjs.com/package/@fedify/fedify/v/${{ steps.versioning.outputs.short_version }} Loading @@ -441,6 +442,8 @@ jobs: [npm:@fedify/postgres]: https://www.npmjs.com/package/@fedify/postgres/v/${{ steps.versioning.outputs.short_version }} [jsr:@fedify/redis]: https://jsr.io/@fedify/redis@${{ steps.versioning.outputs.version }} [npm:@fedify/redis]: https://www.npmjs.com/package/@fedify/redis/v/${{ steps.versioning.outputs.short_version }} [jsr:@fedify/testing]: https://jsr.io/@fedify/testing@${{ steps.versioning.outputs.version }} [npm:@fedify/testing]: https://www.npmjs.com/package/@fedify/testing/v/${{ steps.versioning.outputs.short_version }} pr-number: ${{ github.event.pull_request.number }} comment-tag: publish Loading @@ -461,7 +464,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - run: deno task codegen working-directory: ${{ github.workspace }}/fedify/ - uses: denoland/deployctl@v1 Loading Loading @@ -492,7 +495,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - uses: denoland/setup-deno@v2 with: deno-version: "2.4.1" # FIXME: https://github.com/fedify-dev/fedify/issues/303 deno-version: v2.x - uses: pnpm/action-setup@v4 with: version: 10 Loading
CHANGES.md +62 −19 Original line number Diff line number Diff line Loading @@ -63,15 +63,6 @@ the versioning. - Added `LookupWebFingerOptions.maxRedirection` option. [[#248], [#281] by Lee ByeongJun] - Optimized `doubleKnock()` function to avoid multiple request body clones during redirects. The request body is now read once and reused throughout the entire operation, preventing potential `TypeError: unusable` errors and improving performance. [[#300] by Fabien O'Carroll] - Added `SignRequestOptions.body` option. - Added `DoubleKnockOptions.body` option. - Updated internal signing functions to accept pre-read body buffers. - Added `fedify webfinger` command. This command allows users to look up WebFinger information for a given resource. [[#260], [#278] by ChanHaeng Lee] Loading @@ -82,14 +73,17 @@ the versioning. in the WebFinger request. - The `--allow-private-address` or `-p` option allows looking up WebFinger information for private addresses (e.g., `localhost`). - The `--max-redirection` option allows uses to specify the maximum number of redirects to follow when performing WebFinger lookups. [[#311], [#328] by KeunHyeong Park] - Added `--dry-run` option to `fedify init` command. This option allows users to preview what files and configurations would be created without actually creating them. [[#263], [#298] by Lee ByeongJun] - Fixed a bug where the `fedify node` command had failed to correctly render the favicon in terminal emulators that do not support 24-bit colors. [[#168], [#282], [#304] by Hyeonseo Kim] - Fixed a bug where the `fedify nodeinfo` command (was `fedify node`) had failed to correctly render the favicon in terminal emulators that do not support 24-bit colors. [[#168], [#282], [#304] by Hyeonseo Kim] - Supported NestJS integration with the `@fedify/nestjs` package. [[#269], [#309] by Jaeyeol Lee] Loading @@ -97,18 +91,43 @@ the versioning. - Added `@fedify/nestjs` package. - Added `FedifyModule` for integrating Fedify into NestJS applications. - Supported `KvStore` using SQLite with the `@fedify/sqlite` package, compatible with Bun, Deno and Node.js. [[#274], [#318] By An Subin] - Added `SqliteKvStore`, implementing `KvStore` using SQLite with the `@fedify/sqlite` package. Compatible with Bun, Deno, and Node.js. [[#274], [#318] by An Subin] - Added `@fedify/sqlite` package. - Added `SqliteKvStore`, SQLite implementation of KvStore. - Added `SqliteKvStore`, a SQLite implementation of `KvStore`. - Added `-o`/`--output` option to `fedify lookup` command. This option allows users to save retrieved lookup results to specified path. [[#261], [#321] by Jiwon Kwon] - Added `fedify nodeinfo` command, and deprecated `fedify node` command in favor of `fedify nodeinfo`. [[#267], [#331] by Hyeonseo Kim] - Added custom collection dispatchers. [[#310], [#332] by ChanHaeng Lee] - Added `CustomCollectionDispatcher`, `CustomCollectionCounter`, and `CustomCollectionCursor` types for custom collection dispatching. - Added `CustomCollectionCallbackSetters` type for setting custom collection callbacks. - Added `CustomCollectionHandler` class and `handleCustomCollection()` and `handleOrderedCollection()` functions to process custom collections. - Added `setCollectionDispatcher()` and `setOrderedCollectionDispatcher()` methods to the `Federatable` interface. Implemented in `FederationBuilderImpl` class. - Added `getCollectionUri()` method to the `Context` interface. - Added utility types `ConstructorWithTypeId` and `ParamsKeyPath` for custom collection dispatchers. [#168]: https://github.com/fedify-dev/fedify/issues/168 [#197]: https://github.com/fedify-dev/fedify/issues/197 [#248]: https://github.com/fedify-dev/fedify/issues/248 [#260]: https://github.com/fedify-dev/fedify/issues/260 [#261]: https://github.com/fedify-dev/fedify/issues/261 [#262]: https://github.com/fedify-dev/fedify/issues/262 [#263]: https://github.com/fedify-dev/fedify/issues/263 [#267]: https://github.com/fedify-dev/fedify/issues/267 [#269]: https://github.com/fedify-dev/fedify/issues/269 [#278]: https://github.com/fedify-dev/fedify/pull/278 [#281]: https://github.com/fedify-dev/fedify/pull/281 Loading @@ -116,11 +135,35 @@ the versioning. [#283]: https://github.com/fedify-dev/fedify/pull/283 [#285]: https://github.com/fedify-dev/fedify/pull/285 [#298]: https://github.com/fedify-dev/fedify/pull/298 [#300]: https://github.com/fedify-dev/fedify/pull/300 [#304]: https://github.com/fedify-dev/fedify/issues/304 [#309]: https://github.com/fedify-dev/fedify/pull/309 [#274]: https://github.com/fedify-dev/fedify/issues/274 [#318]: https://github.com/fedify-dev/fedify/pull/318 [#310]: https://github.com/fedify-dev/fedify/issues/310 [#311]: https://github.com/fedify-dev/fedify/issues/311 [#321]: https://github.com/fedify-dev/fedify/pull/321 [#328]: https://github.com/fedify-dev/fedify/pull/328 [#331]: https://github.com/fedify-dev/fedify/pull/331 [#332]: https://github.com/fedify-dev/fedify/pull/332 Version 1.7.7 ------------- Released on July 28, 2025. - Optimized `doubleKnock()` function to avoid multiple request body clones during redirects. The request body is now read once and reused throughout the entire operation, preventing potential `TypeError: unusable` errors and improving performance. [[#300], [#335] by Fabien O'Carroll] - Added `SignRequestOptions.body` option. - Added `DoubleKnockOptions.body` option. - Updated internal signing functions to accept pre-read body buffers. [#300]: https://github.com/fedify-dev/fedify/pull/300 [#335]: https://github.com/fedify-dev/fedify/pull/335 Version 1.7.6 Loading
cli/deno.json +1 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ "@jimp/core": "npm:@jimp/core@^1.6.0", "@jimp/wasm-webp": "npm:@jimp/wasm-webp@^1.6.0", "@poppanator/http-constants": "npm:@poppanator/http-constants@^1.1.1", "@std/assert": "jsr:@std/assert@^1.0.13", "@std/dotenv": "jsr:@std/dotenv@^0.225.2", "@std/assert": "jsr:@std/assert@^1.0.0", "@std/semver": "jsr:@std/semver@^1.0.5", Loading
cli/init.test.ts +78 −31 Original line number Diff line number Diff line Loading @@ -150,37 +150,6 @@ Deno.test("init --dry-run shows command for framework initialization", async () } }); Deno.test("init without --dry-run creates actual files", async () => { const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-actual-project"); try { // Run without --dry-run const result = await runInit([ projectDir, "--runtime", "deno", ]); // Should not show dry-run header assertEquals(result.output.includes("DRY RUN MODE"), false); // Verify files were actually created assertEquals( await exists(projectDir), true, "Project directory should be created", ); assertEquals(await exists(join(projectDir, "federation.ts")), true); assertEquals(await exists(join(projectDir, "logging.ts")), true); assertEquals(await exists(join(projectDir, "main.ts")), true); assertEquals(await exists(join(projectDir, "deno.json")), true); assertEquals(await exists(join(projectDir, ".env")), true); } finally { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init --dry-run fails on non-empty directory", async () => { const testDir = await Deno.makeTempDir(); Loading Loading @@ -251,3 +220,81 @@ Deno.test("init --dry-run shows dev dependencies for Node.js", async () => { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init - check version for AMQP package", async () => { const amqpData = await Deno.readTextFile( join(import.meta.dirname!, "../amqp/deno.json"), ); const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-amqp-project"); try { const result = await runInit([ projectDir, "--dry-run", "--runtime", "deno", "--message-queue", "amqp", ]); assertStringIncludes( result.output, `@fedify/amqp@${JSON.parse(amqpData).version.trim()}`, ); assertEquals(await exists(projectDir), false); } finally { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init - check version for Redis package", async () => { const redisData = await Deno.readTextFile( join(import.meta.dirname!, "../redis/deno.json"), ); const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-redis-project"); try { const result = await runInit([ projectDir, "--dry-run", "--runtime", "deno", "--kv-store", "redis", ]); assertStringIncludes( result.output, `@fedify/redis@${JSON.parse(redisData).version.trim()}`, ); assertEquals(await exists(projectDir), false); } finally { await Deno.remove(testDir, { recursive: true }); } }); Deno.test("init - check version for Postgres package", async () => { const postgresData = await Deno.readTextFile( join(import.meta.dirname!, "../postgres/deno.json"), ); const testDir = await Deno.makeTempDir(); const projectDir = join(testDir, "test-postgres-project"); try { const result = await runInit([ projectDir, "--dry-run", "--runtime", "deno", "--kv-store", "postgres", ]); assertStringIncludes( result.output, `@fedify/postgres@${JSON.parse(postgresData).version.trim()}`, ); assertEquals(await exists(projectDir), false); } finally { await Deno.remove(testDir, { recursive: true }); } });
cli/init.ts +24 −26 Original line number Diff line number Diff line Loading @@ -5,9 +5,17 @@ import { getLogger } from "@logtape/logtape"; import { stringify } from "@std/dotenv/stringify"; import { exists } from "@std/fs"; import { basename, dirname, join, normalize } from "@std/path"; import { format, greaterThan, parse } from "@std/semver"; import metadata from "./deno.json" with { type: "json" }; const packagesMetaData: Record<`@fedify/${string}`, string> = { "@fedify/fedify": metadata.version, "@fedify/redis": metadata.version, "@fedify/postgres": metadata.version, "@fedify/amqp": metadata.version, "@fedify/express": metadata.version, "@fedify/h3": metadata.version, }; const logger = getLogger(["fedify", "cli", "init"]); type Runtime = "deno" | "bun" | "node"; Loading Loading @@ -306,7 +314,7 @@ Then, try look up an actor from your server: init: (projectName, runtime, pm) => ({ dependencies: { express: "^4.19.2", "@fedify/express": "^0.2.1", "@fedify/express": getLatestVersion("@fedify/express"), ...(runtime === "node" ? { "@dotenvx/dotenvx": "^1.14.1", Loading Loading @@ -392,7 +400,7 @@ Then, try look up an actor from your server: ".", ], dependencies: { "@fedify/h3": "^0.1.2", "@fedify/h3": getLatestVersion("@fedify/h3"), }, federationFile: "server/federation.ts", loggingFile: "server/logging.ts", Loading Loading @@ -449,7 +457,7 @@ const kvStores: Record<KvStore, KvStoreDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.2.1", "@fedify/redis": getLatestVersion("@fedify/redis"), "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisKvStore"], ioredis: ["Redis"] }, Loading @@ -465,7 +473,7 @@ const kvStores: Record<KvStore, KvStoreDescription> = { postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.2.0", "@fedify/postgres": getLatestVersion("@fedify/postgres"), "npm:postgres": "^3.4.5", }, imports: { "@fedify/postgres": ["PostgresKvStore"], postgres: "postgres" }, Loading Loading @@ -504,7 +512,7 @@ const messageQueues: Record<MessageQueue, MessageQueueDescription> = { redis: { label: "Redis", dependencies: { "@fedify/redis": "^0.2.1", "@fedify/redis": getLatestVersion("@fedify/redis"), "npm:ioredis": "^5.4.1", }, imports: { "@fedify/redis": ["RedisMessageQueue"], ioredis: ["Redis"] }, Loading @@ -520,7 +528,7 @@ const messageQueues: Record<MessageQueue, MessageQueueDescription> = { postgres: { label: "PostgreSQL", dependencies: { "@fedify/postgres": "^0.2.0", "@fedify/postgres": getLatestVersion("@fedify/postgres"), "npm:postgres": "^3.4.5", }, imports: { Loading @@ -539,7 +547,7 @@ const messageQueues: Record<MessageQueue, MessageQueueDescription> = { amqp: { label: "AMQP (e.g., RabbitMQ)", dependencies: { "@fedify/amqp": "^0.1.0", "@fedify/amqp": getLatestVersion("@fedify/amqp"), "npm:amqplib": "^0.10.4", }, devDependencies: { Loading Loading @@ -1069,7 +1077,7 @@ await configure({ } } const dependencies: Record<string, string> = { "@fedify/fedify": `^${await getLatestFedifyVersion(metadata.version)}`, "@fedify/fedify": getLatestVersion("@fedify/fedify"), "@logtape/logtape": "^0.8.2", ...initializer.dependencies, ...kvStoreDesc?.dependencies, Loading Loading @@ -1489,25 +1497,15 @@ async function addDependencies( } } async function getLatestFedifyVersion(version: string): Promise<string> { const response = await fetch("https://jsr.io/@fedify/fedify/meta.json", { headers: { Accept: "application/json", }, }); // deno-lint-ignore no-explicit-any const result = await response.json() as any; let maxVersion = parse("0.0.0"); for (const v in result.versions) { if (v === version) return version; else if (result.versions[v].yanked) continue; const semVer = parse(v); if (semVer.prerelease != null && semVer.prerelease.length > 0) continue; if (greaterThan(semVer, maxVersion)) maxVersion = semVer; function getLatestVersion(packageName: `@fedify/${string}`): string { const version = packagesMetaData[packageName]; if (!version) { throw new Error( `Version for package "${packageName}" not found in local metadata.`, ); } return format(maxVersion); return version; } async function rewriteJsonFile( path: string, // deno-lint-ignore no-explicit-any Loading