Skip to content

refactor(next): reuse the shared middleware pipeline - #474

Merged
HugoRCD merged 3 commits into
mainfrom
refactor/next-shared-pipeline
Aug 1, 2026
Merged

refactor(next): reuse the shared middleware pipeline#474
HugoRCD merged 3 commits into
mainfrom
refactor/next-shared-pipeline

Conversation

@HugoRCD

@HugoRCD HugoRCD commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Stacked on #471 — base is refactor/framework-integration-consistency, which introduces pickBaseEvlogOptions(). Merge #471 first; the base will retarget to main automatically.

What

evlog/next was the last integration reimplementing the request pipeline instead of reusing it. It had its own shouldLog / getServiceForPath calls, its own tail sampling, its own emitRequestEvent, and its own callEnrichAndDrain — a parallel copy of createMiddlewareLogger + runEnrichAndDrain.

withEvlog now goes through defineFrameworkIntegration, like every other integration. Net −110 lines.

Two options that silently did nothing

Keeping a second copy of the pipeline meant Next drifted from the shared one. Both of these are declared on NextEvlogOptions (which extends BaseEvlogOptions) and were accepted without complaint:

  1. plugins was never applied. Next built no plugin runner at all. Passing plugins: [...] to createEvlog() did nothing — no enrich, no drain, no lifecycle hooks.
  2. Global sampling.keep conditions were never evaluated. Next called the user's keep callback but never shouldKeep(). And its hand-rolled tail context carried no duration, so a sampling: { keep: [{ duration: 500 }] } rule could not match even in principle.

Both now work, and keep callbacks receive ctx.duration. Error statuses are derived through the shared extractErrorStatus rather than an inline status ?? statusCode ?? 500.

⚠️ One behaviour change: enrich timing

Next's after() is the platform's waitUntil — it is now wired as exactly that, so drain work still runs after the response is sent.

But the old code passed both enrich and drain to after(). The shared pipeline awaits enrich inline and defers only drain, per the documented waitUntil contract:

When set, enrich still runs before the response returns but drain work is registered with waitUntil instead of being awaited.

If you have a slow async enricher, this moves that cost onto the response's critical path. The fix is to move that work into drain, which stays deferred.

I chose consistency with the other seven integrations over preserving Next's private timing, but this is the one judgment call in the series worth a second opinion — happy to invert it if you'd rather keep enrich deferred on Next.

Verification

  • All 73 existing Next tests pass unmodified — the strongest signal the migration is behaviour-preserving
  • 3 new specs: plugins are applied, ctx.duration reaches the keep callback, sampling.keep conditions fire
  • pnpm run test — 1631/1631 pass
  • pnpm run lint — 0 errors (2 pre-existing max-params warnings in nitro-v3/plugin.ts)
  • pnpm run typecheck — 26/26 tasks pass
  • pnpm run api:snapshot — unchanged, Next's public exports are identical

Preserved untouched: instrumentation/configureHandler interplay, unstable_rethrow navigation-signal handling (#436), dev error-stack enrichment, the x-evlog-start middleware header, EvlogError JSON responses, streaming defer (#321), and server-action support (non-Request first argument).

@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

4 Skipped Deployments
Project Deployment Actions Updated (UTC)
evlog-docs Skipped Skipped Aug 1, 2026 4:26pm
evlog-render-lab Skipped Skipped Aug 1, 2026 4:26pm
evlog-telemetry Skipped Skipped Aug 1, 2026 4:26pm
just-use-evlog Skipped Skipped Aug 1, 2026 4:26pm

Request Review

@changeset-bot

changeset-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 01557cf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
evlog Minor
@evlog/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@HugoRCD, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fcb0baa3-8db1-49c3-8646-4f59cbd9f045

📥 Commits

Reviewing files that changed from the base of the PR and between 4e12ebb and 01557cf.

📒 Files selected for processing (3)
  • .changeset/next-shared-pipeline.md
  • packages/evlog/src/next/handler.ts
  • packages/evlog/test/next/handler.test.ts

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.

❤️ Share

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

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Thank you for following the naming conventions! 🙏

@HugoRCD

HugoRCD commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@HugoRCD

HugoRCD commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…rations

`evlog/nestjs`, `evlog/react-router` and `evlog/sveltekit` called
`createMiddlewareLogger()` directly and rebuilt by hand what
`defineFrameworkIntegration()` already does: request extraction, the
`crypto.randomUUID()` request-id fallback, `attachForkToLogger()` and the
`storage.run()` wrapper. Hono, Express, Elysia, Fastify and oRPC were
already on the helper. Behaviour is unchanged; they now inherit whatever
the helper gains next, including `extractWaitUntil`.

Adds `pickBaseEvlogOptions()` to the toolkit as the single place listing
the `BaseEvlogOptions` fields. `toMiddlewareOptions()` and `evlog/eve` both
duplicated that list; eve's copy omitted `waitUntil` and would have omitted
any option added afterwards.

`evlog/eve` keeps its own turn lifecycle — it is not an HTTP middleware, so
it only adopts the shared option projection, not the integration helper.
@HugoRCD
HugoRCD force-pushed the refactor/framework-integration-consistency branch from 7b4610b to e4a3081 Compare August 1, 2026 16:14
`evlog/next` reimplemented the request pipeline instead of calling
`createMiddlewareLogger`: its own `shouldLog` / `getServiceForPath` calls,
its own tail sampling, its own `emitRequestEvent` and `callEnrichAndDrain`.
Keeping a second copy meant it drifted, and two options declared on
`NextEvlogOptions` did nothing at all:

- `plugins` was never applied — Next built no plugin runner
- global `sampling.keep` conditions were never evaluated. Next called only
  the user's `keep` callback, never `shouldKeep()`, and its hand-rolled
  tail context carried no `duration`, so duration-based keep rules could
  not match even in principle

`withEvlog` now goes through `defineFrameworkIntegration`, like every other
integration. Next's `after()` is resolved once and passed as the pipeline's
`waitUntil`, so drain work still runs after the response is sent.

Behaviour change: enrich now runs before the response returns rather than
inside `after()`. That is the documented `waitUntil` contract and matches
every other integration; drain remains deferred.

All 73 existing Next tests pass unmodified. Adds three specs covering the
two gaps above and `ctx.duration` in the keep callback.
@vercel
vercel Bot temporarily deployed to Preview – evlog-telemetry August 1, 2026 16:26 Inactive
@vercel
vercel Bot temporarily deployed to Preview – evlog-docs August 1, 2026 16:26 Inactive
@vercel
vercel Bot temporarily deployed to Preview – evlog-render-lab August 1, 2026 16:26 Inactive
@vercel
vercel Bot temporarily deployed to Preview – just-use-evlog August 1, 2026 16:26 Inactive
@HugoRCD
HugoRCD merged commit c5e85b0 into main Aug 1, 2026
19 checks passed
@HugoRCD
HugoRCD deleted the refactor/next-shared-pipeline branch August 1, 2026 16:27
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.

1 participant