Skip to content

feat(nest): allow context as async fn(ExecutionContext)#1666

Merged
dinwwwh merged 3 commits into
middleapi:mainfrom
Wadiou:feat/nest-dynamic-context
Jul 13, 2026
Merged

feat(nest): allow context as async fn(ExecutionContext)#1666
dinwwwh merged 3 commits into
middleapi:mainfrom
Wadiou:feat/nest-dynamic-context

Conversation

@Wadiou

@Wadiou Wadiou commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Adds support for passing a factory function as context in ORPCModuleConfig
(works with both forRoot and forRootAsync):

context: (ctx) => {
const req = ctx.switchToHttp().getRequest()
return { tenantId: req.headers['x-tenant-id'] ?? 'default' }
}

The factory receives the NestJS ExecutionContext on each request and
can be sync or async. ORPCModule and ImplementInterceptor remain
singletons regardless — only the factory runs per request.

Previously, injecting per-request data required forRootAsync with
inject: [REQUEST], which forces the entire module into request scope.

Changes:

  • module.ts — export ContextFactory type, widen context union
  • implement.ts — resolve factory at request time in intercept()
  • implement.test.ts — 6 new test cases (incl. forRootAsync compat)
  • docs/integrations/nest.md — updated Initial Context section

Fully backward compatible. Existing static object usage is unchanged.

- Export `ContextFactory` type from `module.ts`
- Widen `context` union in `ORPCModuleConfig` to accept `ContextFactory`
- Resolve context per-request in `ImplementInterceptor.intercept()` via
  `typeof` check + `await` — module and interceptor remain singletons
- Add 6 test cases: static object, sync factory, async factory,
  handler integration, x-tenant-id header extraction, forRootAsync compat
- Update NestJS integration docs
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
orpc Ready Ready Preview, Comment Jul 13, 2026 8:11am

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — Adds support for a per-request context factory in @orpc/nest, keeping ORPCModule and ImplementInterceptor as singletons.

  • Adds ContextFactory type to packages/nest/src/module.ts and widens ORPCModuleConfig.context to accept DefaultInitialContext | ContextFactory.
  • Resolves the factory at request time in ImplementInterceptor.intercept() and passes the resulting context to the standard handler.
  • Adds 6 regression and feature tests covering static objects, sync/async factories, forRootAsync, and header-based dynamic context.
  • Updates the Initial Context section of the NestJS integration docs with factory examples.

Pullfrog  | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@pkg-pr-new

pkg-pr-new Bot commented Jul 13, 2026

Copy link
Copy Markdown
More templates

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1666

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@1666

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1666

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@1666

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1666

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@1666

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@1666

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1666

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1666

@orpc/next

npm i https://pkg.pr.new/@orpc/next@1666

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1666

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@1666

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@1666

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@1666

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@1666

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1666

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1666

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1666

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1666

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1666

commit: f68b5ad

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@dinwwwh

dinwwwh commented Jul 13, 2026

Copy link
Copy Markdown
Member

I just simply implementation, if you have time please review it again @Wadiou

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The latest commit refactors factory resolution onto the shared value helper, but it also regresses the documentation and trims test coverage for the feature.

Reviewed changes — Refactored the per-request context factory to use @orpc/shared and simplified the type/test/docs surface around it.

  • Updated packages/nest/src/implement.ts to resolve context via await value(..., ctx), removing the local typeof ... === 'function' branch.
  • Reworked packages/nest/src/module.ts from a local ContextFactory export to the generic Value<Promisable<DefaultInitialContext>, [ctx: ExecutionContext]> union.
  • Replaced the six dynamic-context integration tests in packages/nest/src/implement.test.ts with a single isolation test in packages/nest/src/module.test.ts.
  • Removed the dedicated ORPCModule.forRoot factory example from apps/content/docs/integrations/nest.md and rewrote the existing forRootAsync example to use a factory while still injecting REQUEST.

⚠️ Docs example keeps the request-scoped pattern the feature is meant to replace

The Initial Context example now shows a context factory inside ORPCModule.forRootAsync while still using inject: [REQUEST]. That keeps the module request-scoped and does not demonstrate the primary use case in the PR description: a singleton ORPCModule.forRoot({ context: (ctx) => ... }).

The standalone section that demonstrated the forRoot factory and an async variant was also removed in this commit.

Restore a clean forRoot factory example in the Initial Context section. If a forRootAsync example is useful, show it as a specific fallback rather than the only example.

Technical details
# Docs example no longer demonstrates the main factory use case

## Affected sites
- `apps/content/docs/integrations/nest.md:187-205` — the only Initial Context example uses `forRootAsync` + `inject: [REQUEST]`, which forces the module into request scope.
- `apps/content/docs/integrations/nest.md:206-244` (deleted in this commit) — previously held the dedicated `forRoot` factory and async examples that showed the singleton use case.

## Required outcome
- The Initial Context section should clearly show `ORPCModule.forRoot({ context: (ctx) => ... })` as the primary factory usage.
- The request-scoped `forRootAsync` example should be clearly separated or labeled as the legacy/optional route.

## Suggested approach
- Reintroduce the removed `forRoot` factory example at the start of the Initial Context section.
- Keep the new inline factory example inside `forRootAsync` but annotate that `inject: [REQUEST]` still makes the module request-scoped and that the factory is optional there.

## Open questions for the human
- Do you want to document `forRoot` and `forRootAsync` factory usage, or simplify to only one pattern?

⚠️ Test coverage dropped for async factories and forRootAsync

The new test in packages/nest/src/module.test.ts only exercises a synchronous factory via ORPCModule.forRoot. The PR description claims support for async factories and forRootAsync, and the previous commit covered both in packages/nest/src/implement.test.ts (now deleted).

Move those missing cases into module.test.ts so the feature keeps regression coverage.

Technical details
# Test coverage dropped for async factories and forRootAsync

## Affected sites
- `packages/nest/src/module.test.ts:100` — added test title says async, but the factory is synchronous.
- `packages/nest/src/implement.test.ts` — previous `dynamic context factory` block covered static regression, sync factory, async factory, handler input, header tenant id, and `forRootAsync` compatibility; it was removed in this commit.

## Required outcome
- `module.test.ts` should cover async factory resolution (awaited in `intercept()`) and `ORPCModule.forRootAsync` with a factory `context`.

## Suggested approach
- Add a test where the factory returns a `Promise`.
- Add a `forRootAsync` test whose `useFactory` returns a config with a factory `context`.
- If the deleted `implement.test.ts` cases were intentionally removed for weight, recreate lightweight versions in `module.test.ts` instead.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Comment thread apps/content/docs/integrations/nest.md
Comment thread packages/nest/src/module.test.ts Outdated
@dinwwwh dinwwwh changed the title feat(nest): allow context factory function for per-request initial context feat(nest): allow context as async fn(ExecutionContext) Jul 13, 2026
@dinwwwh dinwwwh merged commit d5472fd into middleapi:main Jul 13, 2026
9 checks passed
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