Skip to content

Restore Fresh 2 compatibility in Fedify#639

Merged
dahlia merged 5 commits intofedify-dev:2.0-maintenancefrom
dahlia:fix/fresh2
Mar 22, 2026
Merged

Restore Fresh 2 compatibility in Fedify#639
dahlia merged 5 commits intofedify-dev:2.0-maintenancefrom
dahlia:fix/fresh2

Conversation

@dahlia
Copy link
Member

@dahlia dahlia commented Mar 21, 2026

Summary

This PR restores Fresh 2 compatibility in Fedify by removing two SSR-hostile dependency paths and by validating the Fresh example end-to-end on Deno 2.7.7.

Closes #621.

Changes

  • Replaced the multicodec dependency in packages/vocab-runtime/src/key.ts with an internal multicodec/varint helper implemented in packages/vocab-runtime/src/internal/multicodec.ts.
  • Added regression tests for the new helper in packages/vocab-runtime/src/internal/multicodec.test.ts and extended malformed-input coverage in packages/vocab-runtime/src/key.test.ts.
  • Removed the multicodec dependency from the relevant manifests, including packages/vocab-runtime/deno.json and packages/vocab-runtime/package.json.
  • Added the new @fedify/vocab-runtime/jsonld subpath export in packages/vocab-runtime/src/jsonld.ts so Fedify and generated vocabulary code can share one JSR-safe wrapper around the jsonld ESM entrypoint.
  • Updated packages/fedify/src/sig/ld.ts and the code generated through packages/vocab-tools/src/class.ts to import JSON-LD support through @fedify/vocab-runtime/jsonld instead of depending on fragile relative shims or the package-root jsonld entrypoint.
  • Updated the generated-code snapshots in packages/vocab-tools/src/class.test.ts and packages/vocab-tools/src/snapshots/ so Deno, Node.js, and Bun all expect the same runtime import path.
  • Removed the Fresh-specific SSR externalization workaround from examples/fresh/vite.config.ts.
  • Extended the Fresh example in examples/fresh/federation.ts so it exercises an actual actor JSON-LD response path instead of only the landing page and NodeInfo endpoints.
  • Updated the Fresh integration guidance in docs/manual/integration.md, the example notes in examples/fresh/README.md, and the changelog in CHANGES.md.
  • Bumped the verified Deno version for Fresh development to 2.7.7 in mise.toml and .github/actions/setup-deno/action.yaml.

Investigation

This issue turned out to have multiple layers rather than a single Fresh-specific bug.

The first failure reproduced in Fresh 2 SSR was TypeError: varint.encode is not a function. Tracing the import graph showed that the failure came from the multibase key path in packages/vocab-runtime/src/key.ts, which depended on multicodec. That package was safe enough in other environments but became fragile when evaluated through Fresh 2's SSR toolchain. Since Fedify only needs a very small subset of multicodec behavior there, the most robust fix was to stop depending on the package at runtime and replace it with a local helper that only handles the supported prefixes and varint encoding and decoding logic.

After that change, the original error disappeared, but Fresh still failed in a different place with buildHeaders is not a function. That pointed to a second SSR-hostile path: the default jsonld entrypoint. The important detail here was that Fresh users typically consume Fedify through JSR, so fixing only npm build artifacts under dist/ would not have solved the actual problem. The real fix had to happen in the source modules that are published to JSR, which is why this PR changes the imports in packages/fedify/src/sig/ld.ts and in the generated vocabulary source path produced by packages/vocab-tools/src/class.ts.

The first version of that fix switched those imports directly to jsonld/dist/jsonld.esm.js, which solved the runtime issue but still left two structural problems. First, generated code had to rely on a package-local shim file through a relative import, which was more fragile than necessary. Second, a declare module approach for typing that deep import turned out to be incompatible with JSR publishing because JSR rejects packages that modify global types. The final shape in this PR is therefore a dedicated @fedify/vocab-runtime/jsonld subpath export. It centralizes the deep import in one runtime package that generated vocab code is already meant to depend on, avoids relative-path coupling in generated sources, and remains valid for both JSR and npm packaging.

Once those two Fedify-side issues were fixed, Fresh dev mode still crashed, but the error had changed again to The service is no longer running: Callback called multiple times while evaluating fresh/build-id through Vite. At that point the failure no longer implicated Fedify directly. Verifying against Deno release information and rerunning the example on Deno 2.7.7 showed that this remaining crash was an upstream Deno regression in 2.7.6 rather than another Fedify bug. In other words, the Fedify fixes in this PR remove the SSR incompatibilities that belonged to Fedify itself, and the final end-to-end verification succeeds once the underlying Deno regression is no longer present.

One smaller follow-up that surfaced during verification was that mise run test:bun still failed even after the functional fixes were complete. That was not a runtime regression but a stale snapshot in packages/vocab-tools/src/snapshots/class.test.ts.snap, which still expected the older import path after the generator had been updated. Refreshing the Bun, Node.js, and Deno snapshots brought all three runtimes back in line.

Benefits

These changes remove the need for the previous Fresh SSR workaround, make the fix apply to both the JSR and npm package paths instead of only one packaging format, and keep the affected code paths portable across Deno, Node.js, Bun, and Cloudflare Workers.

Verification

  • Ran the new and updated regression tests for the multicodec helper and key import path.
  • Ran the affected Fedify and vocabulary JSON-LD tests after switching to the shared @fedify/vocab-runtime/jsonld runtime path.
  • Refreshed and rechecked the Deno, Node.js, and Bun snapshots for generated vocabulary imports.
  • Confirmed that the Fresh example works on Deno 2.7.7 with deno task dev and deno task build.
  • Verified the Fresh example endpoints /, /nodeinfo/2.1, and /users/sample with Accept: application/activity+json.
  • Confirmed that the earlier Fresh errors varint.encode is not a function and buildHeaders is not a function no longer reproduce.
  • Confirmed that deno publish --dry-run --allow-dirty succeeds in both packages/vocab-runtime/ and packages/vocab/.
  • Confirmed that mise run test:bun passes after refreshing the runtime-specific snapshots.

Checklist

  • Did you add a changelog entry to the CHANGES.md?
  • Did you write some relevant docs about this change (if it's a new feature)?
  • Did you write a regression test to reproduce the bug (if it's a bug fix)?
  • Did you write some tests for this change (if it's a new feature)?
  • Did you run mise test on your machine?

Additional notes

  • The final Fresh verification result depends on Deno 2.7.7 or later because Deno 2.7.6 still had an upstream dev-mode regression unrelated to Fedify itself.
  • AI-assisted: this PR was updated with help from Codex.

dahlia added 4 commits March 21, 2026 22:29
Remove the CommonJS-only multicodec dependency from the multibase
public key path in @fedify/vocab-runtime. This keeps key handling
inside Fedify and avoids the Vite SSR crash that prevented Fresh 2
apps from importing @fedify/fedify without an externalization
workaround.

This also removes the temporary Fresh workaround from the example and
integration guide, and updates the changelog for the regression.

Fixes fedify-dev#621
Switch the source-facing JSON-LD imports used by Fedify to the
package's ESM entrypoint so Deno, Cloudflare Workers, and other
source-based runtimes do not have to go through CommonJS interop.
This also updates the code generator regression test and the Fresh
example used for manual verification.

fedify-dev#621
Deno 2.7.7 fixes the upstream Fresh/Vite dev server crash that
prevented final verification of the Fedify fixes for Fresh 2.
Update the repository's default Deno version and document the
known-good baseline for the Fresh integration example.

fedify-dev#621
https://github.com/denoland/deno/releases/tag/v2.7.7
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves Fedify's compatibility with Fresh 2 by eliminating problematic dependency paths that caused SSR failures. By replacing the multicodec package with an internal implementation and adjusting jsonld imports for ESM compatibility, Fedify can now be seamlessly integrated into Fresh 2 applications without workarounds. The changes ensure portability across various JavaScript runtimes and are validated with an extended Fresh example, providing a more robust and reliable experience for developers.

Highlights

  • Fresh 2 Compatibility Restored: Addressed and resolved two key issues preventing Fedify from being compatible with Fresh 2's Server-Side Rendering (SSR) toolchain.
  • Dependency Refactoring: Replaced the external multicodec dependency with an internal, lightweight helper to avoid SSR-hostile behavior, and updated jsonld imports to use its ESM-safe entrypoint.
  • Enhanced Test Coverage: Introduced new regression tests for the internal multicodec helper and expanded existing tests to cover malformed input scenarios.
  • Simplified Fresh Integration: Removed the previously required Fresh-specific SSR externalization workaround from vite.config.ts and updated documentation accordingly.
  • Extended Fresh Example: The Fresh example now includes an actual actor JSON-LD response path, providing a more comprehensive demonstration of Fedify's capabilities.
  • Deno Version Alignment: Updated the verified Deno version for Fresh development to 2.7.7, addressing an upstream Deno regression that affected Fresh dev mode.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@dahlia dahlia self-assigned this Mar 21, 2026
@dahlia dahlia added type/bug Something isn't working component/integration Web framework integration integration/fresh Fresh integration (@fedify/fresh) component/build Build system and packaging labels Mar 21, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively resolves Fresh 2 compatibility issues by replacing the problematic multicodec dependency with a well-tested internal implementation and by switching to an ESM-safe import for jsonld. The changes are thorough, including updates to tests, documentation, and examples. My main feedback is a suggestion to improve type safety by adding a custom declaration file instead of using @ts-ignore for the jsonld import, which would enhance long-term maintainability.

dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
A local declaration keeps the jsonld ESM deep import typed without
silencing the checker in the linked data signature code. The same
change is applied to the vocab code generator so generated sources and
snapshot expectations stay aligned.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
A local declaration keeps the jsonld ESM deep import typed without
silencing the checker in the linked data signature code. The same
change is applied to the vocab code generator so generated sources and
snapshot expectations stay aligned.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
A local declaration keeps the jsonld ESM deep import typed without
silencing the checker in the linked data signature code. The same
change is applied to the vocab code generator so generated sources and
snapshot expectations stay aligned.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
@codecov
Copy link

codecov bot commented Mar 21, 2026

Codecov Report

❌ Patch coverage is 94.54545% with 3 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/vocab-runtime/src/internal/multicodec.ts 93.02% 2 Missing and 1 partial ⚠️
Files with missing lines Coverage Δ
packages/fedify/src/sig/ld.ts 86.23% <100.00%> (ø)
packages/vocab-runtime/src/jsonld.ts 100.00% <100.00%> (ø)
packages/vocab-runtime/src/key.ts 87.60% <100.00%> (+0.93%) ⬆️
packages/vocab-tools/src/class.ts 97.26% <100.00%> (-0.04%) ⬇️
packages/vocab-runtime/src/internal/multicodec.ts 93.02% <93.02%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
A local shim module keeps the jsonld ESM deep import isolated without
ambient declarations that JSR rejects during publish. The same change
is applied to the vocab code generator so generated sources and
snapshots stay aligned across Deno, Node.js, and Bun.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
Move the jsonld ESM shim into @fedify/vocab-runtime and expose it
through the new jsonld subpath export. This avoids fragile relative
imports in generated vocab sources while keeping JSR-safe packaging for
the deep jsonld ESM entrypoint. Update Fedify's Linked Data signature
code, the vocab code generator, snapshots, and CHANGES.md to use the
shared runtime module.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
@issues-auto-labeler issues-auto-labeler bot added the breaking change Breaking change label Mar 21, 2026
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
Move the jsonld ESM shim into @fedify/vocab-runtime and expose it
through the new jsonld subpath export. This avoids fragile relative
imports in generated vocab sources while keeping JSR-safe packaging for
the deep jsonld ESM entrypoint. Update Fedify's Linked Data signature
code, the vocab code generator, snapshots, and CHANGES.md to use the
shared runtime module.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
@dahlia dahlia removed the breaking change Breaking change label Mar 21, 2026
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
Move the jsonld ESM shim into @fedify/vocab-runtime and expose it
through the new jsonld subpath export. This avoids fragile relative
imports in generated vocab sources while keeping JSR-safe packaging for
the deep jsonld ESM entrypoint. Update Fedify's Linked Data signature
code, the vocab code generator, snapshots, and CHANGES.md to use the
shared runtime module.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
Move the jsonld ESM shim into @fedify/vocab-runtime and expose it
through the new jsonld subpath export. This avoids fragile relative
imports in generated vocab sources while keeping JSR-safe packaging for
the deep jsonld ESM entrypoint. Update Fedify's Linked Data signature
code, the vocab code generator, snapshots, and CHANGES.md to use the
shared runtime module.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
dahlia added a commit to dahlia/fedify-fork that referenced this pull request Mar 21, 2026
Move the jsonld ESM shim into @fedify/vocab-runtime and expose it
through the new jsonld subpath export. This avoids fragile relative
imports in generated vocab sources while keeping JSR-safe packaging for
the deep jsonld ESM entrypoint. Update Fedify's Linked Data signature
code, the vocab code generator, snapshots, and CHANGES.md to use the
shared runtime module.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
Move the jsonld ESM shim into @fedify/vocab-runtime and expose it
through the new jsonld subpath export. This avoids fragile relative
imports in generated vocab sources while keeping JSR-safe packaging for
the deep jsonld ESM entrypoint. Update Fedify's Linked Data signature
code, the vocab code generator, snapshots, and CHANGES.md to use the
shared runtime module.

fedify-dev#639 (comment)

Co-Authored-By: OpenAI Codex <codex@openai.com>
@github-actions
Copy link
Contributor

Pre-release has been published for this pull request:

Packages

Package Version JSR npm
@fedify/fedify 2.0.7-pr.639.14+40546420 JSR npm
@fedify/cli 2.0.7-pr.639.14+40546420 JSR npm
@fedify/amqp 2.0.7-pr.639.14+40546420 JSR npm
@fedify/cfworkers 2.0.7-pr.639.14+40546420 JSR npm
@fedify/create 2.0.7-pr.639.14+40546420 npm
@fedify/debugger 2.0.7-pr.639.14+40546420 JSR npm
@fedify/denokv 2.0.7-pr.639.14+40546420 JSR
@fedify/elysia 2.0.7-pr.639.14+40546420 JSR npm
@fedify/express 2.0.7-pr.639.14+40546420 JSR npm
@fedify/fastify 2.0.7-pr.639.14+40546420 JSR npm
@fedify/fixture 2.0.7-pr.639.14+40546420 JSR
@fedify/fresh 2.0.7-pr.639.14+40546420 JSR
@fedify/h3 2.0.7-pr.639.14+40546420 JSR npm
@fedify/hono 2.0.7-pr.639.14+40546420 JSR npm
@fedify/init 2.0.7-pr.639.14+40546420 JSR npm
@fedify/koa 2.0.7-pr.639.14+40546420 JSR npm
@fedify/lint 2.0.7-pr.639.14+40546420 JSR npm
@fedify/nestjs 2.0.7-pr.639.14+40546420 npm
@fedify/next 2.0.7-pr.639.14+40546420 npm
@fedify/postgres 2.0.7-pr.639.14+40546420 JSR npm
@fedify/redis 2.0.7-pr.639.14+40546420 JSR npm
@fedify/relay 2.0.7-pr.639.14+40546420 JSR npm
@fedify/sqlite 2.0.7-pr.639.14+40546420 JSR npm
@fedify/sveltekit 2.0.7-pr.639.14+40546420 JSR npm
@fedify/testing 2.0.7-pr.639.14+40546420 JSR npm
@fedify/vocab 2.0.7-pr.639.14+40546420 JSR npm
@fedify/vocab-runtime 2.0.7-pr.639.14+40546420 JSR npm
@fedify/vocab-tools 2.0.7-pr.639.14+40546420 JSR npm
@fedify/webfinger 2.0.7-pr.639.14+40546420 JSR npm

@dahlia dahlia merged commit b3928d6 into fedify-dev:2.0-maintenance Mar 22, 2026
16 checks passed
@dahlia dahlia deleted the fix/fresh2 branch March 22, 2026 04:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/build Build system and packaging component/integration Web framework integration integration/fresh Fresh integration (@fedify/fresh) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant