Add outbox listeners for client-to-server posting#688
Add outbox listeners for client-to-server posting#688dahlia merged 64 commits intofedify-dev:mainfrom
Conversation
Add typed outbox listeners for POST requests to actor outboxes so Fedify applications can handle client-to-server activities with the same routing model as inbox listeners. Keep authorization application-defined, leave federation delivery explicit through ctx.sendActivity(), and mirror the new outbox context helpers in the testing packages. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Add a runtime warning when an outbox listener returns without calling ctx.sendActivity(), since client-to-server posts are not federated automatically. Also add an @fedify/lint rule and integration tests so applications can catch the omission before it reaches runtime. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Document how to handle POST requests to actor outboxes with setOutboxListeners(), including explicit federation through ctx.sendActivity(), authorization hooks, testing helpers, and the new lint warning. Also add changelog entries for the new APIs and predict this branch's pull request number for the release notes. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Reject client-posted activities whose actor does not match the local outbox owner before any listener runs, and add regression tests for the mismatch. Also make the testing mocks able to execute registered outbox listeners through postOutboxActivity(), and update the docs and changelog to match the stronger behavior. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Update the outbox middleware tests to use posted activities whose actor matches the addressed local outbox owner, so the new ownership guard is exercised intentionally instead of tripping the happy-path fixtures. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Tighten the outbox listener lint rule and testing helpers so the follow-up self-review fixes behave the same way in docs, mocks, and static analysis. This avoids false positives from comments or strings, rejects duplicate mock listeners, prefers the most specific mock listener, and removes a misleading no-op catch-all example. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Update the unreleased outbox listener changelog entries to point at the current next pull request number. The earlier placeholder became stale after newer issues and pull requests were created. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds server-side handling for client-to-server POST /outbox: new Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Middleware as Federation Middleware
participant Handler as handleOutbox()
participant Dispatcher as Actor Dispatcher
participant AuthZ as Authorize Predicate
participant Listeners as OutboxListenerSet
participant Listener as Listener Handler
participant Delivery as ctx.sendActivity()/ctx.forwardActivity()
Client->>Middleware: POST /users/{id}/outbox
Middleware->>Handler: handleOutbox(request, params)
Handler->>Dispatcher: resolve actor for {id}
alt actor not found
Handler-->>Client: 404 Not Found
else
Handler->>AuthZ: run authorizePredicate(ctx)
alt authorization fails
Handler-->>Client: 401 Unauthorized
else
Handler->>Handler: parse JSON → Activity
alt invalid JSON/Activity
Handler-->>Client: 400 Bad Request
else
Handler->>Handler: validate activity.actor == outbox owner
alt actor mismatch
Handler-->>Client: 400 Bad Request
else
Handler->>Listeners: dispatchWithClass(activity)
alt no listener
Handler-->>Client: 202 Accepted
else
Listeners-->>Handler: (class, listener)
Handler->>Listener: invoke (OutboxContext, activity)
Listener->>Delivery: call sendActivity/forwardActivity
alt listener returns without delivery
Handler->>Handler: emit runtime warning
end
Handler-->>Client: 202 Accepted
end
end
end
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Suggested labels
🚥 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)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces support for client-to-server ActivityPub POST requests to actor outboxes by adding setOutboxListeners() and OutboxContext. It includes a new lint rule to ensure activities are explicitly federated, comprehensive documentation, and enhanced testing utilities. Feedback was provided to optimize the outbox handler by removing an unnecessary request cloning operation during JSON parsing.
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for client-to-server ActivityPub POST requests to actor outboxes through the new setOutboxListeners() method and OutboxContext. The implementation includes core handler logic, middleware integration, and a new lint rule, outbox-listener-send-activity-required, which ensures that listeners explicitly federate activities using ctx.sendActivity(). Additionally, the PR provides testing utilities such as createOutboxContext() and postOutboxActivity(), alongside updated documentation. Feedback was provided to optimize the handleOutbox function by removing an unnecessary request clone during JSON parsing to improve efficiency.
There was a problem hiding this comment.
Actionable comments posted: 13
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/manual/access-control.md`:
- Around line 114-117: The example currently compares the incoming header to
`Bearer ${identifier}` directly inside the .authorize callback
(ctx.request.headers.get("authorization")), which is insecure; replace this with
a real server-side validation or clearly annotate it as illustrative only: call
a verification helper such as verifyToken(token) or
authService.getUserFromToken(token) inside the authorize callback and then check
the verified subject/id against identifier (e.g., const user = await
verifyToken(token); return user?.id === identifier), or else add an explicit
comment near .authorize explaining the snippet is placeholder-only and must be
replaced with proper server-side token verification.
In `@docs/manual/collections.md`:
- Around line 34-37: Move the TIP block so it appears after the code example
introduced by the sentence referencing ~Federatable.setOutboxDispatcher();
specifically, relocate the existing [!TIP] about
~Federatable.setOutboxListeners() to immediately after the code fence (or at the
end of the Outbox section) so the colon-led sentence remains contiguous with its
code example while still keeping the cross-reference to Outbox listeners.
In `@docs/manual/lint.md`:
- Around line 626-635: The example listener currently calls ctx.sendActivity
with an empty recipients array (ctx.sendActivity(..., [] , ...)), which
federates to no one; update the example to pass a realistic recipient source
such as "followers" or the activity's intended audiences (e.g., activity.to/cc)
so the outbox post is actually delivered—locate the
federation.setOutboxListeners(...).on(Activity, async (ctx, activity) => { await
ctx.sendActivity({ identifier: ctx.identifier }, /* recipients */ , activity) })
snippet and replace the [] recipients argument with "followers" or an expression
that derives recipients from the activity.
In `@docs/manual/outbox.md`:
- Around line 15-17: Convert the inline links in this page (e.g., the inline
backtick links "POST /outbox", "GET /outbox" and the "./collections.md#outbox"
link) to reference-style links and add the corresponding reference definitions
at the end of the section where each is first used; replace the inline
occurrences with reference labels (for example: [POST /outbox][post-outbox],
[GET /outbox][get-outbox], [Collections - Outbox][collections-outbox]) and
append the link definitions (e.g., [post-outbox]: /outbox (POST) or appropriate
URL, [get-outbox]: /outbox (GET), [collections-outbox]: ./collections.md#outbox)
at the end of that section, and apply the same change to the other inline links
noted (the occurrences around lines 74-75, 121-122, 165-166).
In `@docs/manual/test.md`:
- Around line 300-317: The example shows createFederation and postOutboxActivity
but never registers an outbox listener; update the snippet to register an outbox
listener on the federation instance (using the testing library's outbox listener
registration API) before calling federation.postOutboxActivity, showing a
minimal handler that receives the activity (e.g., logs or asserts the received
activity/id and actor) so readers can see what postOutboxActivity is intended to
drive; keep references to createFederation and postOutboxActivity so the change
is easy to locate.
In `@packages/fedify/src/federation/builder.ts`:
- Around line 729-734: The error message in the setOutboxDispatcher code path is
reversed: when this.router.has("outbox") and the new dispatcher path (path) does
not equal this.outboxPath, change the RouterError text to indicate the
dispatcher path is wrong (e.g., "Outbox dispatcher path must match outbox
listener path.") so it mirrors setInboxDispatcher and the reciprocal message in
setOutboxListeners; update the message in the block that checks
this.router.has("outbox") inside setOutboxDispatcher to reference the dispatcher
matching the listener.
In `@packages/fedify/src/federation/handler.ts`:
- Around line 586-603: The actor-mismatch rejection currently logs and returns a
400 directly; modify this branch to call the existing outboxErrorHandler so this
rejection is processed consistently with the other 400 paths. Specifically, when
activity.actorIds is empty or any actorId.href !== expectedActorId.href,
construct a descriptive Error (or a new ActorMismatchError) including
identifier, activity.id, expectedActorId.href and actorIds, then pass that error
and the same request/context into outboxErrorHandler (the same signature used at
lines handling JSON/activity parse failures) and return its Response; remove the
direct Response return so all observability/metrics flow through
outboxErrorHandler while preserving the current log/context information.
- Around line 662-671: The handler currently returns 202 with no Location and
discards the listener result (see the listener invocation around line 619),
which breaks ActivityPub C2S §6.2; change the outbox handler in
federation/handler.ts so the listener (the function invoked at/near line 619)
may return a URL or a Response indicating the canonical activity id, then in the
handler inspect that return value: if a URL or Response with a Location is
provided, respond with 201 Created and set the Location header to the canonical
id (and include the Response body if returned), otherwise keep the async
fallback of 202 Accepted; update the listener type/signature accordingly (allow
URL | Response) and ensure callers propagate the canonical id back to the
handler so compliant clients receive the Location header.
In `@packages/fedify/src/federation/middleware.ts`:
- Around line 3196-3208: The sendActivity override sets `#sendActivityState.sent`
to true synchronously before awaiting super.sendActivity, so hasSentActivity()
can be true even if send fails; change the method to await
super.sendActivity(...) first and only set `#sendActivityState.sent` = true after
the await completes successfully (do not catch/suppress errors that would
indicate a failed send), keeping the original method signature and returning the
Promise result so callers still observe rejections from Context.sendActivity;
reference the sendActivity override, `#sendActivityState.sent`,
super.sendActivity(), hasSentActivity(), and handleOutbox for locating the
change.
In `@packages/lint/src/rules/outbox-listener-send-activity-required.ts`:
- Around line 81-84: The rule currently skips non-inline listeners (it only
checks node.arguments[1] when isFunction(listener)), so patterns like
.on(Activity, handler) where handler is an Identifier or const arrow are
ignored; modify the logic to resolve referenced listener callbacks before
skipping: if listener is an Identifier (or MemberExpression referencing a local
const), use the ESLint scope utilities (e.g., context.getScope() / findVariable)
to find the variable or function declaration/initializer, extract the underlying
FunctionExpression/ArrowFunctionExpression or FunctionDeclaration AST node, and
pass that resolved node into listenerCallsSendActivity (fall back to original
behavior if resolution fails). Update references to listener, isFunction, and
listenerCallsSendActivity accordingly so named symbols are used to locate and
test the resolved callback.
In `@packages/lint/src/tests/integration.test.ts`:
- Around line 182-215: Add integration tests that cover fluent/chained
registration forms so the rule detects handlers attached via chained calls;
extend the existing cases for setOutboxListeners().on by adding analogous tests
that call setOutboxListeners(...).authorize(...).on(...) and
setOutboxListeners(...).onError(...).on(...) (both with an explicit
ctx.sendActivity and with the missing sendActivity case) so the linter rule is
exercised against chained invocation patterns (look for setOutboxListeners,
authorize, onError, and on in the new test strings).
In `@packages/testing/src/mock.ts`:
- Around line 366-376: The mock's setOutboxListeners/on currently keys listeners
by type.name (using type.name and activity.constructor.name), which causes
collisions and differs from runtime behavior; change it to store and match
listeners by the actual constructor function (use the type itself as the key in
this.outboxListeners and compare by identity while walking prototypes rather
than using type.name strings), and update the corresponding removal/dispatch
logic (the on(...) and any unregister/emit code around outboxListeners) so it
looks up listeners by constructor identity and checks prototype chain
matches—refer to setOutboxListeners, its on method, and the outboxListeners Map
when making the fix.
- Around line 492-521: postOutboxActivity currently dispatches to listeners
without verifying the activity's actor belongs to the addressed identifier; add
the same ownership guard used in the real outbox POST flow before any listener
runs: extract the actor from the Activity (e.g. activity.actor), normalize it to
a string, and verify it corresponds to the provided identifier (or is owned by
that actor URL/actor id as production does); if the check fails, throw the same
kind of rejection/error (e.g. new Error("Actor does not belong to the addressed
identifier") or the project's standard error) so listeners are never invoked for
outbox ownership violations (refer to postOutboxActivity, createOutboxContext
and outboxListeners to locate where to insert the guard).
🪄 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: 9acc22d0-bec0-4dda-b451-d968a958609f
📒 Files selected for processing (30)
CHANGES.mddocs/.vitepress/config.mtsdocs/manual/access-control.mddocs/manual/collections.mddocs/manual/context.mddocs/manual/lint.mddocs/manual/outbox.mddocs/manual/test.mdpackages/fedify/src/federation/builder.test.tspackages/fedify/src/federation/builder.tspackages/fedify/src/federation/callback.tspackages/fedify/src/federation/context.tspackages/fedify/src/federation/federation.tspackages/fedify/src/federation/handler.test.tspackages/fedify/src/federation/handler.tspackages/fedify/src/federation/middleware.test.tspackages/fedify/src/federation/middleware.tspackages/fedify/src/federation/outbox.tspackages/fedify/src/testing/context.tspackages/fedify/src/testing/mod.tspackages/lint/src/index.tspackages/lint/src/lib/const.tspackages/lint/src/mod.tspackages/lint/src/rules/outbox-listener-send-activity-required.tspackages/lint/src/tests/integration.test.tspackages/lint/src/tests/outbox-listener-send-activity-required.test.tspackages/testing/src/context.tspackages/testing/src/mock.test.tspackages/testing/src/mock.tspackages/testing/src/mod.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 730a7f7ccf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Implements a first-class routing surface for ActivityPub client-to-server POST requests to actor outboxes, via typed “outbox listeners”, while keeping authorization, persistence, and delivery policy application-defined.
Changes:
- Adds
setOutboxListeners()with.on(),.authorize(), and.onError()hooks and introducesOutboxContext.identifier. - Implements
POST /outboxdispatch, including actor/outbox-owner matching and a runtime warning when listeners don’t callctx.sendActivity(). - Adds a new
@fedify/lintrule plus@fedify/testinghelpers (createOutboxContext(),postOutboxActivity()) and documents the flow.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/testing/src/mod.ts | Re-exports createOutboxContext from testing API surface. |
| packages/testing/src/mock.ts | Adds mock setOutboxListeners() and postOutboxActivity() to exercise outbox listeners in tests. |
| packages/testing/src/mock.test.ts | Adds coverage for outbox listener dispatch + identifier propagation in testing mock. |
| packages/testing/src/context.ts | Adds createOutboxContext() helper for the testing package. |
| packages/lint/src/tests/outbox-listener-send-activity-required.test.ts | Adds rule-level tests for new outbox listener lint rule. |
| packages/lint/src/tests/integration.test.ts | Adds integration coverage for the new lint rule. |
| packages/lint/src/rules/outbox-listener-send-activity-required.ts | Introduces lint rule enforcing explicit ctx.sendActivity() in outbox listeners. |
| packages/lint/src/mod.ts | Registers the new rule in the Deno lint plugin. |
| packages/lint/src/lib/const.ts | Adds new RULE_ID constant. |
| packages/lint/src/index.ts | Registers the new rule in the ESLint plugin export. |
| packages/fedify/src/testing/mod.ts | Exposes createOutboxContext() from @fedify/fedify/testing. |
| packages/fedify/src/testing/context.ts | Adds createOutboxContext() helper for fedify’s internal testing utilities. |
| packages/fedify/src/federation/outbox.ts | Adds OutboxListenerSet with prototype-chain dispatch. |
| packages/fedify/src/federation/middleware.ts | Routes POST /outbox to handleOutbox() and adds OutboxContextImpl with send-tracking. |
| packages/fedify/src/federation/middleware.test.ts | Adds end-to-end middleware tests for outbox listeners, auth, and warning behavior. |
| packages/fedify/src/federation/handler.ts | Implements handleOutbox() for parsing, actor validation, dispatching, and error handling. |
| packages/fedify/src/federation/handler.test.ts | Adds unit tests for handleOutbox() behavior (auth, invalid JSON, actor mismatch, error handler). |
| packages/fedify/src/federation/federation.ts | Adds public types/API: setOutboxListeners() and OutboxListenerSetters. |
| packages/fedify/src/federation/context.ts | Adds OutboxContext interface and identifier. |
| packages/fedify/src/federation/callback.ts | Adds OutboxListener and OutboxListenerErrorHandler callback types. |
| packages/fedify/src/federation/builder.ts | Adds builder support for outbox listeners and wires listener path validation/clone. |
| packages/fedify/src/federation/builder.test.ts | Adds builder tests for outbox listener routing + path validation. |
| docs/manual/test.md | Documents testing helpers for outbox listeners (createOutboxContext, postOutboxActivity). |
| docs/manual/outbox.md | New manual page describing outbox listeners, authorization, explicit delivery, and errors. |
| docs/manual/lint.md | Documents outbox-listener-send-activity-required rule. |
| docs/manual/context.md | Adds outbox listeners to list of Context consumers. |
| docs/manual/collections.md | Notes relationship between outbox collection (GET) and outbox listeners (POST). |
| docs/manual/access-control.md | Documents authorization hook for POST /outbox. |
| docs/.vitepress/config.mts | Adds “Outbox listeners” to manual navigation sidebar. |
| CHANGES.md | Adds changelog entries for fedify/lint/testing additions. |
Outbox listeners need the same escape hatch that inbox listeners have when they must relay a signed activity without round-tripping it through Fedify's vocabulary objects. This adds OutboxContext.forwardActivity(), reuses the existing forwarding path for raw posted JSON-LD, and treats explicit forwarding as delivery so outbox warnings only fire when nothing was actually sent. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Now that outbox listeners can either send a new activity or forward the posted payload as-is, the surrounding rule names, docs, and testing helpers need to say "delivery" rather than "sendActivity". This renames the lint rule, updates the manuals and changelog, and teaches @fedify/testing's outbox mocks about forwardActivity and skipIfUnsigned. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Outbox listener POST handling had a few edge cases that diverged from the existing outbox dispatcher flow. This reuses dispatcher authorization when listener-specific authorization is unset, routes actor-mismatch rejections through the outbox error hook for consistent observability, removes an unnecessary request clone while parsing JSON, and clarifies mismatch wording in the builder and public JSDoc. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Linked Data Signature payloads can expose `signature.type` as either a string or an array of strings after compaction and expansion. The quick signature detector now accepts both forms so skipIfUnsigned does not misclassify signed payloads, and a regression covers the array case. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
Outbox listeners already reject query and fragment identifier operators because the router only matches URL pathnames. This applies the same validation to setOutboxDispatcher() so both entry points enforce the same routable pathname-only subset, with a regression for the query case. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces client-to-server ActivityPub outbox listeners, allowing developers to handle POST requests to actor outboxes using typed listeners and custom authorization logic. Key additions include the setOutboxListeners() method, an OutboxContext for activity delivery and forwarding, and a new lint rule to ensure activities are explicitly federated. The PR also provides comprehensive testing support for outbox activities in the @fedify/testing package. I have no feedback to provide.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a98a33705
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The remaining @fedify/testing gaps were both in the mock POST /outbox context. This makes outbox path validation reject non-absolute templates like the runtime router does, and it wires sendActivity() and forwardActivity() into the mock outbox delivery state so tests see the same hasDeliveredActivity() behavior as runtime. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request implements support for client-to-server ActivityPub outbox POST requests by adding setOutboxListeners() and the OutboxContext API. It also introduces a new lint rule, outbox-listener-delivery-required, to ensure activities are explicitly delivered, and provides comprehensive testing utilities and documentation. Feedback identifies a bug in the outbox handler where the request body is consumed before the listener can access it if no authorization predicate is defined; always cloning the request is recommended to ensure the body remains available for the listener.
2chanhaeng
left a comment
There was a problem hiding this comment.
LGTM! I commented suggestions about some duplications.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6e3de857f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The remaining outbox handler review comments were all about request and queue control flow. Authorization now runs before actor resolution so write endpoints do not leak account existence, body-aware auth still gets a readable Request clone, and the queue enqueue branch has been flattened to the simpler equivalent structure the review suggested. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
The mock outbox helper was still checking skipIfUnsigned against the parsed Activity instance instead of the raw posted JSON-LD. That could diverge from runtime when proof information only survived in the raw payload shape, so the mock now uses hasProofLike(rawActivity) and adds an expanded-proof regression for that path. fedify-dev#430 Assisted-by: OpenCode:gpt-5.4
The current staged changes are both follow-ups to earlier outbox review fixes. One middleware regression now expects the 401 returned by auth-before-actor handling, and the mock proof-shape regression uses a normal Create instance with an overridden raw JSON-LD view instead of trying to deserialize an intentionally shape-only proof payload. fedify-dev#688 Assisted-by: OpenCode:gpt-5.4
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request implements client-to-server ActivityPub support by introducing outbox listeners and the OutboxContext interface. It adds the setOutboxListeners() method to the Federation builder, a dedicated handleOutbox handler, and a new lint rule, outbox-listener-delivery-required, to ensure activities are explicitly federated. The changes also include testing utilities for outbox activities, extensive documentation updates, and a fix for OpenTelemetry span attributes regarding cc and bcc identifiers. I have no feedback to provide.
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Issue #430 narrowed the problem to one concrete piece of C2S support: handling
POST /outboxthrough Fedify's routing surface. This PR implements that agreed surface without trying to land full server-side C2S semantics at once, so applications can keep authorization, persistence, recipient selection, and delivery policy in their own code.Closes #430.
Changes
setOutboxListeners()for actor outboxes, with typed.on(),.authorize(), and.onError()hooksOutboxContext.identifierandOutboxContext.forwardActivity()forPOST /outboxhandlersactordoes not match the addressed outbox ownerctx.sendActivity()orctx.forwardActivity()instead of auto-federating after the handler returnsctx.forwardActivity()relays the posted payload as-isoutbox-listener-delivery-requiredrule to packages/lint/ so missing delivery calls are caught statically, including named callbacks and chained registration formscreateOutboxContext()andpostOutboxActivity()support to packages/testing/, and aligns the mock outbox dispatch and ownership checks with runtime behaviorTesting
mise run checkmise run testpnpm buildin docs/