Add @fedify/nuxt package for Nuxt integration#674
Add @fedify/nuxt package for Nuxt integration#6742chanhaeng wants to merge 7 commits intofedify-dev:mainfrom
@fedify/nuxt package for Nuxt integration#674Conversation
📝 WalkthroughWalkthroughAdds a new Changes
Sequence DiagramsequenceDiagram
participant Client
participant Nitro as Nitro/H3 Event Handler
participant FedifyMiddleware as Fedify Middleware
participant FedifyFetch as fetchWithFedify
participant Federation as Federation Instance
participant Framework as Nuxt Framework Handler
participant Plugin as Deferred Response Plugin
Client->>Nitro: HTTP Request
Nitro->>FedifyMiddleware: Invoke handler (H3 event)
FedifyMiddleware->>FedifyMiddleware: toWebRequest / compute contextData
FedifyMiddleware->>FedifyFetch: Call fetchWithFedify(fetch, request, contextData)
FedifyFetch->>Federation: federation.fetch(request, { onNotFound, onNotAcceptable, ... })
Federation->>Framework: onNotFound/onNotAcceptable callbacks (delegate to Nuxt)
Framework-->>Federation: Framework Response (status, headers, body)
Federation-->>FedifyFetch: Response
alt handled (ActivityPub)
FedifyFetch-->>FedifyMiddleware: { kind: "handled", response }
FedifyMiddleware->>Nitro: return federation response
Nitro-->>Client: federation response
else not-found
FedifyFetch-->>FedifyMiddleware: { kind: "not-found" }
FedifyMiddleware->>Nitro: return undefined (delegate)
Nitro->>Framework: continue to Nuxt handler
Framework-->>Nitro: framework response
Nitro-->>Client: framework response
else not-acceptable
FedifyFetch-->>FedifyMiddleware: { kind: "not-acceptable" }
FedifyMiddleware->>FedifyMiddleware: set deferred flag in event.context
FedifyMiddleware->>Nitro: return undefined (delegate)
Nitro->>Framework: continue to Nuxt handler
Framework-->>Nitro: framework response
Nitro->>Plugin: beforeResponse hook
Plugin->>Plugin: resolveDeferredNotAcceptable(deferred, frameworkStatus)
alt returns 406
Plugin->>Nitro: set status, headers, body -> 406 Not Acceptable
else undefined
Plugin->>Nitro: leave framework response intact
end
Nitro-->>Client: final response
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces the @fedify/nuxt package to integrate Fedify with the Nuxt framework, providing a module, Nitro middleware, and a plugin for deferred 406 Not Acceptable handling. It also updates documentation, agent skills, and workspace configurations. Feedback recommends improving TypeScript type safety by using specific types from @nuxt/kit and h3, and suggests extracting the "Not acceptable" response body into a shared constant to prevent duplication across the runtime logic and plugin.
| }, | ||
| setup( | ||
| options: ModuleOptions, | ||
| nuxt: { options: { alias: Record<string, string> } }, |
There was a problem hiding this comment.
Instead of manually typing a subset of the Nuxt object, use the Nuxt type imported from @nuxt/kit. This ensures better maintainability and alignment with Nuxt module development standards.
| nuxt: { options: { alias: Record<string, string> } }, | |
| nuxt: Nuxt, |
References
- Maintain strict TypeScript typing throughout. (link)
| const createNotAcceptableResponse = () => | ||
| new Response("Not acceptable", { |
There was a problem hiding this comment.
| @@ -0,0 +1,46 @@ | |||
| import type { Federation } from "@fedify/fedify/federation"; | |||
| import { defineEventHandler, toWebRequest } from "h3"; | |||
There was a problem hiding this comment.
Import H3Event to properly type the event parameter in the middleware and factory functions.
| import { defineEventHandler, toWebRequest } from "h3"; | |
| import { defineEventHandler, toWebRequest, type H3Event } from "h3"; |
References
- Maintain strict TypeScript typing throughout. (link)
|
|
||
| export function createFedifyMiddleware( | ||
| federation: unknown, | ||
| contextDataFactory?: (event: unknown, request: Request) => unknown, |
There was a problem hiding this comment.
The event parameter should be typed as H3Event instead of unknown to maintain strict type safety, consistent with the ContextDataFactory definition in mod.ts.
| contextDataFactory?: (event: unknown, request: Request) => unknown, | |
| contextDataFactory?: (event: H3Event, request: Request) => unknown, |
References
- Maintain strict TypeScript typing throughout. (link)
| import { | ||
| DEFERRED_NOT_ACCEPTABLE_CONTEXT_KEY, | ||
| resolveDeferredNotAcceptable, | ||
| } from "./logic.ts"; |
There was a problem hiding this comment.
Import the shared NOT_ACCEPTABLE_BODY constant to avoid duplication.
| import { | |
| DEFERRED_NOT_ACCEPTABLE_CONTEXT_KEY, | |
| resolveDeferredNotAcceptable, | |
| } from "./logic.ts"; | |
| import { | |
| DEFERRED_NOT_ACCEPTABLE_CONTEXT_KEY, | |
| NOT_ACCEPTABLE_BODY, | |
| resolveDeferredNotAcceptable, | |
| } from "./logic.ts"; |
| setResponseHeader(event, key, value); | ||
| }); | ||
|
|
||
| payload.body = "Not acceptable"; |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.agents/skills/create-example-app-with-integration/SKILL.md (1)
180-193:⚠️ Potential issue | 🟠 MajorClose the bash fence immediately after the curl example.
Line 180 opens a fence, but it is only closed at Line 193. That makes the “Lint, format, and final checks” section render as code.
Suggested fix
~~~~ bash curl -H "Accept: application/activity+json" http://localhost:0000/users/demo +~~~~ Lint, format, and final checks ------------------------------ @@ -~~~~🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/create-example-app-with-integration/SKILL.md around lines 180 - 193, The markdown code fence opened with "~~~~ bash" around the curl example is left open; close that fence immediately after the curl command so the following "Lint, format, and final checks" section is not rendered as code—i.e., move or add the matching closing fence "~~~~" directly after the line with `curl -H "Accept: application/activity+json" http://localhost:0000/users/demo` (refer to the fenced block starting with "~~~~ bash" in SKILL.md) and ensure subsequent text is plain markdown outside the fence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.agents/skills/create-example-app-with-integration/SKILL.md:
- Line 178: Update the wording in SKILL.md where the sentence reads "If the
`test:examples` can not be run, just run the server and test with curl:" to use
the standard single-word form "cannot" (i.e., change "can not" to "cannot") so
the line becomes "If the `test:examples` cannot be run, just run the server and
test with curl:".
In `@docs/manual/integration.md`:
- Around line 397-418: The Nuxt docs use inconsistent path styling; update the
Nuxt section so all file and module paths are wrapped in asterisks instead of
underscores or backticks—replace occurrences like _server/federation.ts_,
_nuxt.config.ts_, and `~/server/federation` with *server/federation.ts*,
*nuxt.config.ts*, and *~/server/federation* respectively (in the block that
shows createFederation / MemoryKvStore and the module enablement) so path
styling matches the repo guideline.
In `@packages/nuxt/README.md`:
- Around line 71-72: Replace the inline code backticks around the default module
path with asterisks: change the instance that reads "`@fedify/nuxt` loads your
Federation instance from `~/server/federation`" so that the module and path use
asterisk wrapping (e.g., *@fedify/nuxt* and *~/server/federation*) to comply
with the repo Markdown rule; update the README line containing "@fedify/nuxt"
and "~/server/federation" accordingly.
In `@packages/nuxt/src/mod.test.ts`:
- Line 2: Replace the runtime-specific import of the test entrypoint by
importing the test function from the runtime-agnostic package: change the import
of test from "node:test" to "@fedify/fixture" (i.e., replace the existing import
statement that references node:test with one that imports test from
`@fedify/fixture`), ensuring any usages of the test identifier remain unchanged.
In `@packages/nuxt/src/runtime/server/logic.ts`:
- Around line 47-53: Add a JSDoc block above the exported function
resolveDeferredNotAcceptable that documents its purpose (handle deferred
requests that should return a 406 Not Acceptable when the framework routed to
404), describes parameters isDeferred:boolean and frameworkStatus:number,
explains the return type Response|undefined and the conditions when
createNotAcceptableResponse() is returned, and notes that this is part of the
deferred 406 handling pattern for public API consumers; keep the comment concise
and follow existing project JSDoc style.
- Around line 22-45: Add a JSDoc block to the exported function fetchWithFedify
describing its purpose, parameters (fetcher: (request: Request, options:
FederationFetchOptions<unknown>) => Promise<Response>, request: Request,
contextData: unknown) and return value (Promise<FetchResult>), and note the
behavior/assumption that a response equal to DUMMY_NOT_FOUND_RESPONSE maps to {
kind: "not-found" } and any Response with status 406 is treated as { kind:
"not-acceptable" } (which relies on user handlers not returning 406 for
unrelated reasons); reference DUMMY_NOT_FOUND_RESPONSE and
createNotAcceptableResponse in the doc so callers understand the special-case
mappings.
In `@packages/nuxt/src/runtime/server/middleware.ts`:
- Around line 20-23: Add a JSDoc block above the exported createFedifyMiddleware
function that documents its parameters and return value: describe the
"federation" parameter type/expected shape (unknown but clarify expected usage),
the optional "contextDataFactory" callback signature ((event: unknown, request:
Request) => unknown) and when it is invoked, the middleware behavior (what the
returned function does, side effects, and that it returns a
Connect/Node/Fetch-style middleware handler), and the return type expectations
(e.g., middleware function or handler). Use the function name
createFedifyMiddleware and mention the contextDataFactory callback to make the
doc discoverable.
---
Outside diff comments:
In @.agents/skills/create-example-app-with-integration/SKILL.md:
- Around line 180-193: The markdown code fence opened with "~~~~ bash" around
the curl example is left open; close that fence immediately after the curl
command so the following "Lint, format, and final checks" section is not
rendered as code—i.e., move or add the matching closing fence "~~~~" directly
after the line with `curl -H "Accept: application/activity+json"
http://localhost:0000/users/demo` (refer to the fenced block starting with "~~~~
bash" in SKILL.md) and ensure subsequent text is plain markdown outside the
fence.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 833b06e0-e342-4d98-af3c-fa0f0c532116
⛔ Files ignored due to path filters (2)
deno.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
.agents/skills/add-to-fedify-init/SKILL.md.agents/skills/create-example-app-with-integration/SKILL.md.agents/skills/create-example-app-with-integration/example/README.md.agents/skills/create-example-app-with-integration/example/src/logging.ts.agents/skills/create-integration-package/SKILL.md.hongdown.tomlAGENTS.mdCHANGES.mdCONTRIBUTING.mdcspell.jsondeno.jsondocs/manual/integration.mdmise.tomlpackages/fedify/README.mdpackages/nuxt/README.mdpackages/nuxt/deno.jsonpackages/nuxt/package.jsonpackages/nuxt/src/mod.test.tspackages/nuxt/src/mod.tspackages/nuxt/src/runtime/server/logic.tspackages/nuxt/src/runtime/server/middleware.tspackages/nuxt/src/runtime/server/plugin.tspackages/nuxt/tsdown.config.tspnpm-workspace.yaml
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
- Use @fedify/fixture instead of node:test in mod.test.ts - Type event parameter as H3Event instead of unknown in middleware.ts Co-Authored-By: Claude (claude-opus-4-20250514)
Move NOT_ACCEPTABLE_BODY and DEFERRED_NOT_ACCEPTABLE_CONTEXT_KEY into a shared lib.ts to avoid string duplication across logic.ts and plugin.ts. Co-Authored-By: Claude (claude-opus-4-20250514)
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.agents/skills/add-to-fedify-init/SKILL.md:
- Around line 37-39: Replace the inline link and plain file paths in the
sentence that mentions WebFrameworkDescription, changing `./init/framework.ts`
and `packages/init/src/types.ts` to wrapped paths (*./init/framework.ts*,
*packages/init/src/types.ts*) and convert the inline link to a reference-style
link (e.g., [init/framework.ts][init-framework]) with the corresponding
reference entry placed at the end of the section; update the sentence to refer
to the reference label and ensure the symbol WebFrameworkDescription remains
mentioned so you can find the exact line to edit.
In `@packages/nuxt/deno.json`:
- Line 24: The "check" npm script currently only runs deno check on "src/*.ts"
which skips nested runtime files (e.g., src/runtime/server/); update the "check"
script (the "check" key value that currently contains "deno fmt --check && deno
lint && deno check src/*.ts") to use a recursive glob such as "src/**/*.ts" or
explicitly include the runtime folder (for example add
"src/runtime/server/**/*.ts") so that deno check covers all nested runtime
TypeScript files.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 44c494fa-0e71-490b-ad31-ac3a6bde1a5c
⛔ Files ignored due to path filters (2)
deno.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (25)
.agents/skills/add-to-fedify-init/SKILL.md.agents/skills/create-example-app-with-integration/SKILL.md.agents/skills/create-example-app-with-integration/example/README.md.agents/skills/create-example-app-with-integration/example/src/logging.ts.agents/skills/create-integration-package/SKILL.md.hongdown.tomlAGENTS.mdCHANGES.mdCONTRIBUTING.mdcspell.jsondeno.jsondocs/manual/integration.mdmise.tomlpackages/fedify/README.mdpackages/nuxt/README.mdpackages/nuxt/deno.jsonpackages/nuxt/package.jsonpackages/nuxt/src/mod.test.tspackages/nuxt/src/mod.tspackages/nuxt/src/runtime/server/lib.tspackages/nuxt/src/runtime/server/logic.tspackages/nuxt/src/runtime/server/middleware.tspackages/nuxt/src/runtime/server/plugin.tspackages/nuxt/tsdown.config.tspnpm-workspace.yaml
| `WebFrameworkDescription` object, referring to | ||
| [init/framework.ts](./init/framework.ts). Check the specifications in the | ||
| comments in `packages/init/src/types.ts` for details. |
There was a problem hiding this comment.
Use project markdown link/path style in this sentence.
Please switch the inline link to a reference-style link and wrap file paths with asterisks for consistency with repo docs conventions.
✏️ Suggested doc fix
-`WebFrameworkDescription` object, referring to
-[init/framework.ts](./init/framework.ts). Check the specifications in the
-comments in `packages/init/src/types.ts` for details.
+`WebFrameworkDescription` object, referring to
+[*init/framework.ts*][init-framework-ts]. Check the specifications in the
+comments in *packages/init/src/types.ts* for details.
+
+[init-framework-ts]: ./init/framework.tsAs per coding guidelines, "/*.md: Wrap file paths in asterisks in Markdown documentation" and "/*.md: Place reference-style links at the end of each section in Markdown documentation".
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| `WebFrameworkDescription` object, referring to | |
| [init/framework.ts](./init/framework.ts). Check the specifications in the | |
| comments in `packages/init/src/types.ts` for details. | |
| `WebFrameworkDescription` object, referring to | |
| [*init/framework.ts*][init-framework-ts]. Check the specifications in the | |
| comments in *packages/init/src/types.ts* for details. | |
| [init-framework-ts]: ./init/framework.ts |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/add-to-fedify-init/SKILL.md around lines 37 - 39, Replace the
inline link and plain file paths in the sentence that mentions
WebFrameworkDescription, changing `./init/framework.ts` and
`packages/init/src/types.ts` to wrapped paths (*./init/framework.ts*,
*packages/init/src/types.ts*) and convert the inline link to a reference-style
link (e.g., [init/framework.ts][init-framework]) with the corresponding
reference entry placed at the end of the section; update the sentence to refer
to the reference label and ensure the symbol WebFrameworkDescription remains
mentioned so you can find the exact line to edit.
| }, | ||
| "tasks": { | ||
| "test": "deno test", | ||
| "check": "deno fmt --check && deno lint && deno check src/*.ts" |
There was a problem hiding this comment.
Type-check coverage is incomplete for nested runtime files.
Line 24 only checks src/*.ts, so files under src/runtime/server/ are skipped by deno check. That can allow runtime type errors to pass CI.
🔧 Proposed fix
- "check": "deno fmt --check && deno lint && deno check src/*.ts"
+ "check": "deno fmt --check && deno lint && deno check src/*.ts src/runtime/server/*.ts"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "check": "deno fmt --check && deno lint && deno check src/*.ts" | |
| "check": "deno fmt --check && deno lint && deno check src/*.ts src/runtime/server/*.ts" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/deno.json` at line 24, The "check" npm script currently only
runs deno check on "src/*.ts" which skips nested runtime files (e.g.,
src/runtime/server/); update the "check" script (the "check" key value that
currently contains "deno fmt --check && deno lint && deno check src/*.ts") to
use a recursive glob such as "src/**/*.ts" or explicitly include the runtime
folder (for example add "src/runtime/server/**/*.ts") so that deno check covers
all nested runtime TypeScript files.
Add
@fedify/nuxtpackage for Nuxt integrationCloses #149
Changes
New package:
@fedify/nuxtsrc/mod.ts: Defines the Nuxt module (defineNuxtModule) that:federationModuleand optionalcontextDataFactoryModulepathsinto a Nitro server handler
src/runtime/server/middleware.ts: Creates the Fedify middleware(
defineEventHandler) that intercepts incoming requests, convertsthem via
toWebRequest, and delegates tofederation.fetch().Non-federation requests fall through to Nuxt routing.
src/runtime/server/logic.ts: Pure-logic helpers(
fetchWithFedify,resolveDeferredNotAcceptable) that determinewhether Fedify handled the request, the framework should take over
(404 fallthrough), or a deferred 406 should be returned.
src/runtime/server/plugin.ts: NitrobeforeResponsehookplugin that resolves deferred 406 Not Acceptable responses when
Fedify owns the route but the client does not accept ActivityPub and
Nuxt itself returns 404.
src/mod.test.ts: Unit tests covering:(
onNotFoundfallthrough)framework route matches
Documentation
docs/manual/integration.md: Added Nuxt section withinstallation instructions, module configuration, and context data
factory usage example.
Configuration updates
@fedify/nuxtto workspace configs (deno.json, deno.lock,pnpm-workspace.yaml, pnpm-lock.yaml)
@fedify/nuxtto AGENTS.md, CONTRIBUTING.md, andpackages/fedify/README.md package listings
tunneltask to mise.tomlAgent skill improvements (non-functional)
create-integration-package,add-to-fedify-init, andcreate-example-app-with-integrationskill docs with clarifiedguidance on version verification, fallthrough/406 behavior, template
file references, and host restriction configuration.
Co-Authored-By: GPT-5.3-codex