Skip to content

Add webhook event bus for async processing#35

Open
cb-srinaths wants to merge 2 commits into
mainfrom
feat/webhook-bus
Open

Add webhook event bus for async processing#35
cb-srinaths wants to merge 2 commits into
mainfrom
feat/webhook-bus

Conversation

@cb-srinaths

@cb-srinaths cb-srinaths commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

The current implementation only supports synchronous processing of webhook events. If an application was to follow our best practices and save the incoming events to an event bus and then process it, all the default subscription handlers will have to be duplicated. This PR abstracts the processing of the webhook from the way the events are triggered. This will let apps implement an async flow: Chargebee -> App -> Queue -> Worker -> Process Better Auth related events.

Introduce a Chargebee webhook event bus + processor to enable async queue/worker flows. Add webhook event-bus types and public re-exports, refactor the webhook handler to dispatch validated events or publish them when webhookEventBus is configured, and add a processor factory plus tests covering publish and processing behavior.

@snyk-io

snyk-io Bot commented Jun 26, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: f5e2310f-48e8-4a5f-9ad2-54ed1c1fda74

📥 Commits

Reviewing files that changed from the base of the PR and between 1136a4b and 2bfcfa8.

📒 Files selected for processing (1)
  • packages/better-auth/src/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/better-auth/src/types.ts

Walkthrough

The PR adds Chargebee webhook event-bus support, updates webhook event types and options, refactors webhook handling into shared dispatch and publish paths, adds a webhook processor factory, updates route wiring, and extends tests for publish and processor behavior.

Changes

Chargebee webhook API surface

Layer / File(s) Summary
Webhook types and exports
packages/better-auth/src/types.ts, packages/better-auth/src/index.ts
WebhookEvent now aliases Chargebee’s webhook event type, ChargebeeWebhookEventBus is added, ChargebeeOptions gains webhookEventBus, and the new webhook processor symbols are re-exported.
Webhook dispatch and publish handler
packages/better-auth/src/webhook-handler.ts, packages/better-auth/test/webhook-queue.test.ts
Webhook validation and event dispatch are centralized, and a publish handler forwards handled events to an event bus; tests cover publish routing and handled/unhandled event behavior.
Route selection
packages/better-auth/src/routes.ts
Webhook route construction now ընտրates between the publish handler and the synchronous handler based on options.webhookEventBus.
Processor and processor tests
packages/better-auth/src/webhook-processor.ts, packages/better-auth/test/webhook-queue.test.ts
A webhook processor factory is added to resolve context and dispatch Chargebee events, with tests covering explicit context, lazy context, and unknown events.

Estimated code review effort: 4 (Complex) | ~45 minutes


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/better-auth/src/webhook-handler.ts`:
- Around line 47-55: buildRequestValidator currently falls back to undefined
when only one of webhookUsername or webhookPassword is set, which disables Basic
Auth and leaves webhooks unauthenticated. Update buildRequestValidator in
webhook-handler.ts to fail closed by validating the webhook auth config up
front: if either credential is provided without the other, treat it as an error
instead of returning undefined. Keep basicAuthValidator only for the fully
configured case, and ensure the webhook-handler path rejects partial/empty auth
configuration rather than accepting requests without auth.
- Around line 298-323: The webhook handlers for handled and unhandled events
currently await eventBus.publish(event) and rely on the shared
handler.on("error") path, which converts every non-authentication failure into
200 OK. Update the event publishing flow in webhook-handler.ts so publish
failures are not acknowledged: handle errors from eventBus.publish(event)
explicitly in the HANDLED_EVENT_TYPES and "unhandled_event" listeners, and
ensure those queueing failures either rethrow or send a non-2xx response instead
of falling through to the generic 200 OK path.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 91ba27d8-d462-4cb3-b3f1-f26664642907

📥 Commits

Reviewing files that changed from the base of the PR and between 27e172a and 1136a4b.

📒 Files selected for processing (6)
  • packages/better-auth/src/index.ts
  • packages/better-auth/src/routes.ts
  • packages/better-auth/src/types.ts
  • packages/better-auth/src/webhook-handler.ts
  • packages/better-auth/src/webhook-processor.ts
  • packages/better-auth/test/webhook-queue.test.ts

Comment thread packages/better-auth/src/webhook-handler.ts
Comment on lines +298 to +323
for (const eventType of HANDLED_EVENT_TYPES) {
handler.on(eventType, async ({ event, response }) => {
await eventBus.publish(event);
response?.status(200).send("OK");
});
}

// Forward all other events too, so the application receives every webhook.
handler.on("unhandled_event", async ({ event, response }) => {
await eventBus.publish(event);
response?.status(200).send("OK");
});

handler.on("error", (error: Error, { response }) => {
const webhookResponse = response as WebhookResponse | undefined;
if (error instanceof WebhookAuthenticationError) {
logger.warn(
`Webhook rejected: ${error.message}. Please verify webhookUsername and webhookPassword are correctly configured in your plugin options and that the webhook in Chargebee dashboard has matching Basic Auth credentials.`,
);
webhookResponse?.status(401).send("Unauthorized");
return;
}

// Log other errors and send 200 to prevent Chargebee retries
logger.error("Error processing webhook event:", error);
webhookResponse?.status(200).send("OK");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C4 'eventBus\.publish|Error processing webhook event|response: undefined' packages/better-auth/src packages/better-auth/test

Repository: chargebee/js-framework-adapters

Length of output: 6411


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant handler implementation and its tests with line numbers.
sed -n '240,330p' packages/better-auth/src/webhook-handler.ts
printf '\n--- TESTS ---\n'
sed -n '780,870p' packages/better-auth/test/webhook-events.test.ts
printf '\n--- QUEUE TESTS ---\n'
sed -n '80,150p' packages/better-auth/test/webhook-queue.test.ts

Repository: chargebee/js-framework-adapters

Length of output: 7810


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the code paths that route webhook events and how errors are surfaced.
sed -n '1,120p' packages/better-auth/src/routes.ts
printf '\n--- WEBHOOK HANDLER ---\n'
sed -n '1,360p' packages/better-auth/src/webhook-handler.ts

Repository: chargebee/js-framework-adapters

Length of output: 14178


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether publish failures are expected to be caught by the shared error handler.
rg -n -C3 'handler\.on\("error"|publish\(event\)|eventBus\.publish|WebhookAuthenticationError|unhandled_event' packages/better-auth/src packages/better-auth/test

Repository: chargebee/js-framework-adapters

Length of output: 8657


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '240,330p' packages/better-auth/src/webhook-handler.ts
printf '\n--- TESTS ---\n'
sed -n '780,870p' packages/better-auth/test/webhook-events.test.ts
printf '\n--- QUEUE TESTS ---\n'
sed -n '80,150p' packages/better-auth/test/webhook-queue.test.ts

Repository: chargebee/js-framework-adapters

Length of output: 7810


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the top of the file for the handler/event-emitter implementation.
sed -n '1,240p' packages/better-auth/src/webhook-handler.ts
printf '\n--- RELATED TYPES/USAGE ---\n'
rg -n -C3 'new .*Handler|create.*Webhook|on\("error"|on\("unhandled_event"|HANDLED_EVENT_TYPES' packages/better-auth/src packages/better-auth/test

Repository: chargebee/js-framework-adapters

Length of output: 50023


Don't ACK queueing failures. eventBus.publish(event) in both webhook listeners can reject, but the shared "error" handler turns every non-authentication error into 200 OK. That drops events on transient queue failures; return a non-2xx or rethrow for publish errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/better-auth/src/webhook-handler.ts` around lines 298 - 323, The
webhook handlers for handled and unhandled events currently await
eventBus.publish(event) and rely on the shared handler.on("error") path, which
converts every non-authentication failure into 200 OK. Update the event
publishing flow in webhook-handler.ts so publish failures are not acknowledged:
handle errors from eventBus.publish(event) explicitly in the HANDLED_EVENT_TYPES
and "unhandled_event" listeners, and ensure those queueing failures either
rethrow or send a non-2xx response instead of falling through to the generic 200
OK path.

Source: Path instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants