Skip to content

Conversation

@anatolzak
Copy link
Contributor

@anatolzak anatolzak commented Dec 11, 2025

Closes #7038

🎯 Changes

Add streaming support for AWS API gateway Rest APIs (payload format version 1).

One of the required changes was to fix how we parse the version 1 headers from API Gateway. Previously, we duplicated the headers by processing both headers and multiValueHeaders. This duplication prevented streaming from working correctly because tRPC couldn't detect the trpc-accept header properly. The best practice is to use multiValueHeaders if available, then fall back to headers, skipping any that have already been added.

✅ Checklist

  • I have followed the steps listed in the Contributing guide.
  • If necessary, I have added documentation related to the changes made.
  • I have added or updated the tests related to the changes made.

Summary by CodeRabbit

  • New Features

    • Enabled AWS Lambda response streaming support for API Gateway REST APIs.
  • New Example

    • Added a complete Lambda + API Gateway streaming example (server, client, README, run/deploy scripts, and supporting configs).
  • Documentation

    • Updated AWS Lambda adapter docs to cover API Gateway streaming and configuration notes.
  • Chores

    • Added example-level config files (.gitignore, package manifest, TypeScript config).

✏️ Tip: You can customize this high-level summary in your review settings.

@anatolzak anatolzak requested review from a team as code owners December 11, 2025 20:58
@vercel
Copy link

vercel bot commented Dec 11, 2025

@anatolzak is attempting to deploy a commit to the trpc Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

Walkthrough

Adds API Gateway REST API response streaming support: new streaming example project, implements required toStream for v1/v2 in the AWS Lambda adapter, adjusts adapter types/runtime checks, and updates docs and example artifacts.

Changes

Cohort / File(s) Summary
New streaming example project
examples/lambda-api-gateway-streaming/.gitignore, examples/lambda-api-gateway-streaming/README.md, examples/lambda-api-gateway-streaming/package.json, examples/lambda-api-gateway-streaming/serverless.yml, examples/lambda-api-gateway-streaming/tsconfig.json
Adds a full example demonstrating API Gateway REST API response streaming with Serverless config (responseTransferMode: STREAM), scripts, README, and TypeScript config.
Example client & server
examples/lambda-api-gateway-streaming/src/client.ts, examples/lambda-api-gateway-streaming/src/server.ts
New TRPC client using httpBatchStreamLink and a Lambda streaming server with procedures greet, iterable, and deferred; exports AppRouter and streaming handler.
AWS Lambda adapter: streaming implementation
packages/server/src/adapters/aws-lambda/getPlanner.ts
Makes Processor.toStream required; implements toStream for v1/v2 processors using HttpResponseStream, pipes response body to stream, and refactors header handling to prioritize multiValueHeaders then single headers.
AWS Lambda adapter: types & runtime changes
packages/server/src/adapters/aws-lambda/index.ts
Broadens handler generics from payload-v2-specific to LambdaEvent, removes runtime validation that threw when planner.toStream was missing.
Docs: AWS Lambda adapter
www/docs/server/adapters/aws-lambda.md
Updates docs to document API Gateway REST API response streaming support, adds example row, fixes wording/typo, and aligns streaming notes.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant APIGW as API Gateway (REST)
    participant Lambda as AWS Lambda
    participant Planner as Adapter/Planner
    participant Stream as HttpResponseStream

    Client->>APIGW: HTTP request (/{proxy+})
    APIGW->>Lambda: Invoke (payload v1)
    activate Lambda
    Lambda->>Planner: Build response (router -> procedure)
    alt Procedure yields streaming data
        Planner->>Stream: Send metadata (statusCode, headers, cookies)
        loop chunks
            Planner->>Stream: Write chunk
        end
        Stream-->>APIGW: Streamed response
    else Non-streaming response
        Planner->>Stream: Send metadata + full body
        Stream-->>APIGW: Single response
    end
    deactivate Lambda
    APIGW-->>Client: HTTP response (streamed if enabled)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Focus areas:
    • packages/server/src/adapters/aws-lambda/getPlanner.ts — correctness of toStream, header/multi-value handling, cookie parsing, stream lifecycle and error paths.
    • packages/server/src/adapters/aws-lambda/index.ts — type changes and removed runtime check impact on callers.
    • examples/.../src/server.ts — context creation and handler wiring for streaming behavior.

Possibly related PRs

  • #6680 — Modifies the AWS Lambda adapter streaming path and Processor interface; likely directly related to these adapter updates.

Suggested reviewers

  • KATT

Poem

🐰 I hopped a path through gateway streams,
Pushed headers, chunks, and tiny beams,
v1 now sings as toStream leads,
Bits of joy in rushing feeds,
The rabbit cheers — deploy those dreams! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature: adding streaming support for API Gateway REST API. It is clear, concise, and directly related to the primary change.
Description check ✅ Passed The description includes issue reference, a clear explanation of changes (streaming support and header parsing fix), and follows the template checklist. One non-critical item (tests) remains unchecked.
Linked Issues check ✅ Passed All coding requirements from issue #7038 are met: streaming support for API Gateway REST APIs (payload version 1) is implemented with proper header parsing fix to detect trpc-accept header.
Out of Scope Changes check ✅ Passed All changes are directly related to adding streaming support for API Gateway REST APIs. The new example app, updated adapter code, header parsing fixes, and documentation updates are all within scope.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@anatolzak anatolzak changed the title feat(server): add streaming to API Gateway payload v1 feat(server): add streaming to API Gateway REST API Dec 11, 2025
@anatolzak anatolzak changed the title feat(server): add streaming to API Gateway REST API feat(server): support streaming in API Gateway REST API Dec 11, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
www/docs/server/adapters/aws-lambda.md (1)

129-129: Duplicate heading "Example apps" may cause navigation issues.

The static analysis tool correctly identified that there are now two headings with identical text ("Example apps" on lines 15 and 129). This can cause issues with documentation anchor links and table of contents navigation.

Consider differentiating the headings:

-## Example apps
+## Streaming example apps
packages/server/src/adapters/aws-lambda/getPlanner.ts (1)

133-149: Consider extracting shared streaming logic to reduce duplication.

The toStream implementations in v1Processor and v2Processor are nearly identical. While not blocking, extracting a shared helper would improve maintainability.

+async function streamResponse(
+  response: Response,
+  stream: Writable,
+  headers: Record<string, string>,
+  cookies: string[],
+): Promise<void> {
+  const metadata = {
+    statusCode: response.status,
+    headers,
+    cookies,
+  };
+
+  const responseStream = awslambda.HttpResponseStream.from(stream, metadata);
+
+  if (response.body) {
+    await pipeline(Readable.fromWeb(response.body as any), responseStream);
+  } else {
+    responseStream.end();
+  }
+}

 const v1Processor: Processor<APIGatewayProxyEvent> = {
   // ... other methods
   toStream: async (response, stream) => {
     const { headers, cookies } = getHeadersAndCookiesFromResponse(response);
-
-    const metadata = {
-      statusCode: response.status,
-      headers,
-      cookies,
-    };
-
-    const responseStream = awslambda.HttpResponseStream.from(stream, metadata);
-
-    if (response.body) {
-      await pipeline(Readable.fromWeb(response.body as any), responseStream);
-    } else {
-      responseStream.end();
-    }
+    await streamResponse(response, stream, headers, cookies);
   },
 };

Also applies to: 198-214

examples/lambda-api-gateway-streaming/package.json (1)

5-5: Consider removing unnecessary main field.

Example packages typically don't require distribution fields like main, module, or types since they aren't published or distributed.

Apply this diff to remove the unnecessary field:

   "private": true,
   "type": "module",
-  "main": "index.js",
   "license": "MIT",
examples/lambda-api-gateway-streaming/tsconfig.json (1)

3-3: Remove unnecessary DOM library for Lambda backend.

The "dom" library is intended for browser environments and is unnecessary for an AWS Lambda backend. Including it may allow inadvertent use of browser-only APIs that won't be available at runtime.

Apply this diff to remove the DOM library:

-    "lib": ["esnext", "dom"],
+    "lib": ["esnext"],
examples/lambda-api-gateway-streaming/src/server.ts (1)

7-16: Consider improving type safety for version detection.

The type assertion (event as { version?: string }).version on line 13 is used to detect the API Gateway payload format version. However, this approach bypasses TypeScript's type checking.

Consider a more explicit approach:

 function createContext({
   event,
   context,
 }: CreateAWSLambdaContextOptions<APIGatewayProxyEvent>) {
+  const version = 'version' in event ? (event as any).version : undefined;
   return {
     event: event,
-    apiVersion: (event as { version?: string }).version ?? '1.0',
+    apiVersion: version ?? '1.0',
     user: event.headers['x-user'],
   };
 }

Or use a type guard if version detection becomes more complex in the future.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e5a037e and ae1e14c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • examples/lambda-api-gateway-streaming/.gitignore (1 hunks)
  • examples/lambda-api-gateway-streaming/README.md (1 hunks)
  • examples/lambda-api-gateway-streaming/package.json (1 hunks)
  • examples/lambda-api-gateway-streaming/serverless.yml (1 hunks)
  • examples/lambda-api-gateway-streaming/src/client.ts (1 hunks)
  • examples/lambda-api-gateway-streaming/src/server.ts (1 hunks)
  • examples/lambda-api-gateway-streaming/tsconfig.json (1 hunks)
  • packages/server/src/adapters/aws-lambda/getPlanner.ts (3 hunks)
  • packages/server/src/adapters/aws-lambda/index.ts (2 hunks)
  • www/docs/server/adapters/aws-lambda.md (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

Use camelCase for file names (with exceptions like TRPC/RPC/HTTP/JSON acronyms, .config.js, .d.ts, and tests)

Files:

  • examples/lambda-api-gateway-streaming/README.md
  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/src/server.ts
  • packages/server/src/adapters/aws-lambda/getPlanner.ts
  • packages/server/src/adapters/aws-lambda/index.ts
  • www/docs/server/adapters/aws-lambda.md
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

**/*.{ts,tsx}: Always use import type for type-only imports
Separate type imports from value imports
Avoid overzealous object destructuring; prefer direct property access
Object destructuring is acceptable when a variable is used 3+ times
Prefer array destructuring
Avoid sparse array destructuring
Never destructure in function parameter declarations
Avoid destructuring potentially nullish nested properties
Maximum 3 parameters per function; use options objects when more
Type parameter names must match /^(T|$)(A-Z)?[0-9]*$/
Prefix unused variables, parameters, and caught errors with _
Prefer namespace imports for validation libraries and large modules (e.g., import * as z from 'zod', import * as React from 'react')
Follow import order: test helpers, tRPC test imports, third-party, then relative
Never import from @trpc/*/src; import from the package root instead
Do not use Symbol.dispose or Symbol.asyncDispose; use makeResource()/makeAsyncResource()
Always use await using for resource cleanup
Prefer makeResource()/makeAsyncResource() over manual disposal logic
Avoid non-null assertions (!)
Use proper type guards and optional chaining instead of non-null assertions
Switch statements must be exhaustive for union types
Rely on TypeScript inference; avoid unnecessary explicit return/output types
Use explicit types at public API boundaries, for complex generic constraints, or when inference is insufficient/ambiguous
Use the satisfies operator to retain inference while enforcing shapes
Use as const for literal type inference when appropriate
Prefer explicit typing over any
Use type assertions sparingly
Leverage TypeScript strict mode features

Files:

  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/src/server.ts
  • packages/server/src/adapters/aws-lambda/getPlanner.ts
  • packages/server/src/adapters/aws-lambda/index.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

No console.log in packages; use proper logging instead

Files:

  • packages/server/src/adapters/aws-lambda/getPlanner.ts
  • packages/server/src/adapters/aws-lambda/index.ts
🧠 Learnings (17)
📚 Learning: 2025-09-05T16:48:06.982Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-09-05T16:48:06.982Z
Learning: Applies to **/*.{ts,tsx,md,mdx} : Use camelCase for file names (with exceptions like TRPC/RPC/HTTP/JSON acronyms, .config.js, .d.ts, and tests)

Applied to files:

  • examples/lambda-api-gateway-streaming/tsconfig.json
📚 Learning: 2025-09-05T16:48:06.982Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-09-05T16:48:06.982Z
Learning: Applies to **/*.{ts,tsx} : Leverage TypeScript strict mode features

Applied to files:

  • examples/lambda-api-gateway-streaming/tsconfig.json
📚 Learning: 2025-06-09T14:01:20.033Z
Learnt from: juliusmarminge
Repo: trpc/trpc PR: 6789
File: packages/tanstack-react-query/tsdown.config.ts:1-24
Timestamp: 2025-06-09T14:01:20.033Z
Learning: In the tRPC monorepo, packages/tests and packages/upgrade don't need main/module/types fields in their package.json because tests is not distributed and upgrade just exposes a binary.

Applied to files:

  • examples/lambda-api-gateway-streaming/tsconfig.json
  • examples/lambda-api-gateway-streaming/package.json
📚 Learning: 2025-09-05T16:48:06.982Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-09-05T16:48:06.982Z
Learning: Share common functionality through `trpc/server` and keep client/server concerns separate

Applied to files:

  • examples/lambda-api-gateway-streaming/README.md
  • examples/lambda-api-gateway-streaming/serverless.yml
  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/src/server.ts
  • packages/server/src/adapters/aws-lambda/index.ts
📚 Learning: 2025-09-05T15:16:31.379Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/tanstack-react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:31.379Z
Learning: Applies to packages/tanstack-react-query/**/*.test.tsx : Use `ctx.useTRPCClient()` for direct (vanilla) tRPC client access in tests

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/src/server.ts
📚 Learning: 2025-09-05T15:16:48.745Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-09-05T15:16:48.745Z
Learning: Applies to **/*.test.ts : Use `ctx.client` from the test resource for making tRPC calls

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:48.745Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-09-05T15:16:48.745Z
Learning: Applies to **/*.test.ts : Import `testServerAndClientResource` from `trpc/client/__tests__/testClientResource`

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Create the tRPC React client with createTRPCReact<typeof appRouter>()

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/src/server.ts
📚 Learning: 2025-09-05T15:16:48.745Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-09-05T15:16:48.745Z
Learning: Applies to **/*.test.ts : Configure client options via the `client` callback in `testServerAndClientResource` options

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Import getUntypedClient from 'trpc/client' when an untyped client is needed

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:17:32.520Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/upgrade-tests.mdc:0-0
Timestamp: 2025-09-05T15:17:32.520Z
Learning: Applies to packages/upgrade/**/*.{test,spec,trpc,snap}.tsx : Import both 'trpc/react-query' as rq (legacy) and 'trpc/tanstack-react-query' as trq (modern) when writing migration tests

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-06-29T21:21:07.306Z
Learnt from: heitorlisboa
Repo: trpc/trpc PR: 6849
File: examples/minimal-react-typesafe-errors/client/src/Users.tsx:6-6
Timestamp: 2025-06-29T21:21:07.306Z
Learning: In the minimal-react-typesafe-errors example, the `trpc.user.list` query is designed to never throw errors since it's a minimal example focused on demonstrating typed error handling in mutations rather than queries.

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Import createTRPCReact from 'trpc/react-query' (legacy API)

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : If not using createAppRouter, you may create an inline router using testServerAndClientResource with appropriate server and client link configuration

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Wrap components with a custom App that provides trpc.Provider (legacy) and QueryClientProvider

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:31.379Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/tanstack-react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:31.379Z
Learning: Applies to packages/tanstack-react-query/**/*.test.tsx : Use `ctx.useTRPC()` for TanStack React Query hooks access in components under test

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/src/server.ts
📚 Learning: 2025-04-07T05:50:41.797Z
Learnt from: zirkelc
Repo: trpc/trpc PR: 6680
File: packages/server/src/adapters/aws-lambda/index.ts:89-124
Timestamp: 2025-04-07T05:50:41.797Z
Learning: In AWS Lambda, the `awslambda` namespace is provided globally by the runtime environment and doesn't require an import statement. It contains utilities for response streaming such as `streamifyResponse` and `HttpResponseStream.from`.

Applied to files:

  • examples/lambda-api-gateway-streaming/src/server.ts
  • packages/server/src/adapters/aws-lambda/index.ts
  • www/docs/server/adapters/aws-lambda.md
🧬 Code graph analysis (2)
examples/lambda-api-gateway-streaming/src/client.ts (3)
examples/lambda-api-gateway-streaming/src/server.ts (1)
  • AppRouter (48-48)
packages/client/src/links/loggerLink.ts (1)
  • loggerLink (214-268)
packages/client/src/links/httpBatchStreamLink.ts (1)
  • httpBatchStreamLink (23-186)
packages/server/src/adapters/aws-lambda/index.ts (1)
packages/server/src/adapters/aws-lambda/getPlanner.ts (1)
  • LambdaEvent (11-11)
🪛 GitHub Actions: autofix.ci
examples/lambda-api-gateway-streaming/package.json

[error] 1-1: Lockfile specifiers do not match package.json: lockfile has {"@trpc/client":"workspace:","@trpc/server":"workspace:","tsx":"^4.19.3","zod":"^3.25.51","@types/aws-lambda":"^8.10.149","@types/node":"^22.13.5","esbuild":"^0.17.10","eslint":"^9.26.0","serverless":"^4.28.0","serverless-esbuild":"^1.55.0","typescript":"^5.9.2"} while package.json requires {"@types/aws-lambda":"^8.10.149","@types/node":"^22.13.5","esbuild":"^0.17.10","eslint":"^9.26.0","serverless":"^3.38.0","serverless-esbuild":"^1.55.0","typescript":"^5.9.2","@trpc/client":"workspace:","@trpc/server":"workspace:","tsx":"^4.19.3","zod":"^3.25.51"}.

🪛 GitHub Actions: main
examples/lambda-api-gateway-streaming/package.json

[error] 1-1: pnpm install failed: ERR_PNPM_OUTDATED_LOCKFILE Cannot install with 'frozen-lockfile' because pnpm-lock.yaml is not up to date with the package.json. Use 'pnpm install --no-frozen-lockfile' to update the lockfile.

🪛 LanguageTool
examples/lambda-api-gateway-streaming/README.md

[style] ~12-~12: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...npm install pnpm build pnpm deploy ``` This will deploy the Lambda function and API...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 markdownlint-cli2 (0.18.1)
www/docs/server/adapters/aws-lambda.md

129-129: Multiple headings with the same content

(MD024, no-duplicate-heading)

🔇 Additional comments (12)
packages/server/src/adapters/aws-lambda/index.ts (2)

10-10: LGTM! Clean import update.

The removal of APIGatewayProxyEventV2 from direct imports and addition of StreamifyHandler properly reflects the expanded streaming support for both payload format versions.


86-114: LGTM! Streaming handler now supports both v1 and v2 payload formats.

The generic constraint change from APIGatewayProxyEventV2 to LambdaEvent correctly enables streaming for both REST API (v1) and HTTP API (v2), fulfilling the PR objective. The implementation maintains consistency with awsLambdaRequestHandler.

www/docs/server/adapters/aws-lambda.md (2)

125-127: LGTM! Documentation accurately reflects the new streaming capabilities.

The updated description correctly explains that streaming is now supported for both Lambda Function URLs and API Gateway REST APIs, with proper guidance on the responseTransferMode: STREAM configuration requirement.


33-40: LGTM! Example links added for the new streaming example.

The new example rows are properly formatted and link to the correct example directory for API Gateway REST API streaming.

Also applies to: 147-154

packages/server/src/adapters/aws-lambda/getPlanner.ts (3)

44-44: LGTM! Making toStream required aligns with universal streaming support.

This interface change correctly reflects that all processors now must implement streaming, supporting both v1 and v2 payload formats.


99-118: LGTM! Headers processing correctly prioritizes multiValueHeaders.

The refactored logic properly processes multiValueHeaders first (which can have multiple values per header) and then adds single-value headers only if not already present. This follows AWS API Gateway behavior where multiValueHeaders takes precedence.


145-145: Consider using a more specific type assertion or verify if a newer @types/node version resolves this typing incompatibility.

The as any cast works around a known TypeScript typing difference between ReadableStream<Uint8Array> (from the Fetch API) and Readable.fromWeb. While this workaround is functional, the coding guidelines prefer explicit typing over any. Consider checking if a newer @types/node version has resolved this issue, or alternatively, use a more specific type assertion (e.g., as unknown as ReadableStream<any>) to avoid the blanket any type. Both occurrences (lines 145 and 210) use this same pattern.

examples/lambda-api-gateway-streaming/.gitignore (1)

1-1: LGTM!

The .serverless directory exclusion is appropriate for Serverless Framework deployments.

examples/lambda-api-gateway-streaming/README.md (1)

1-27: LGTM!

The documentation clearly explains the streaming setup, deployment steps, and usage. The AWS blog post reference provides helpful context.

examples/lambda-api-gateway-streaming/src/client.ts (1)

1-38: LGTM!

The client correctly demonstrates tRPC streaming with:

  • Proper type-only import for AppRouter
  • httpBatchStreamLink for streaming support
  • loggerLink for debugging
  • Good examples of query, parallel deferred calls, and async iteration
  • Appropriate error handling

The placeholder URL on line 14 is expected per the README instructions.

examples/lambda-api-gateway-streaming/src/server.ts (1)

19-55: LGTM!

The server implementation correctly demonstrates tRPC streaming:

  • Proper context creation with event and headers
  • Good streaming examples (async generator in iterable, deferred responses)
  • Correct use of awslambda.streamifyResponse wrapper
  • Type export for client usage

Note: The awslambda global is provided by the Lambda runtime and doesn't require an import. Based on learnings, this is the expected usage pattern.

examples/lambda-api-gateway-streaming/serverless.yml (1)

9-17: LGTM on streaming configuration!

The HTTP event configuration correctly enables response streaming with transferMode: STREAM, which is essential for API Gateway REST API streaming support. The /{proxy+} path with any method allows tRPC to handle all routes.

@anatolzak anatolzak marked this pull request as draft December 11, 2025 21:15
@anatolzak anatolzak marked this pull request as ready for review December 11, 2025 21:20
@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 11, 2025

Open in StackBlitz

@trpc/client

npm i https://pkg.pr.new/trpc/trpc/@trpc/client@7039

@trpc/next

npm i https://pkg.pr.new/trpc/trpc/@trpc/next@7039

@trpc/react-query

npm i https://pkg.pr.new/trpc/trpc/@trpc/react-query@7039

@trpc/server

npm i https://pkg.pr.new/trpc/trpc/@trpc/server@7039

@trpc/tanstack-react-query

npm i https://pkg.pr.new/trpc/trpc/@trpc/tanstack-react-query@7039

@trpc/upgrade

npm i https://pkg.pr.new/trpc/trpc/@trpc/upgrade@7039

commit: 8fb0404

@Nick-Lucas
Copy link
Contributor

I hadn't realised that API Gateway finally got streaming support! We'll be very keen to land this one, just shout when it's done 😃

@anatolzak
Copy link
Contributor Author

I hadn't realised that API Gateway finally got streaming support! We'll be very keen to land this one, just shout when it's done 😃

@Nick-Lucas it's ready! :)

Copy link
Contributor

@Nick-Lucas Nick-Lucas left a comment

Choose a reason for hiding this comment

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

LGTM! I just pushed a small tweak to the example as I had a little confusion (my AWS is rusty) but it works!

@vercel
Copy link

vercel bot commented Dec 12, 2025

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

Project Deployment Preview Comments Updated (UTC)
next-prisma-starter Ready Ready Preview Dec 12, 2025 6:44pm
og-image Ready Ready Preview Comment Dec 12, 2025 6:44pm
www Ready Ready Preview Comment Dec 12, 2025 6:44pm

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
examples/lambda-api-gateway-streaming/README.md (1)

1-5: Clarify “REST API (payload v1)” vs “HTTP API (payload v2)” to prevent deployment confusion.
Given tRPC historically supported streaming on payload v2, it’d help to explicitly call out here that this example targets API Gateway REST API (payload format v1).

Also applies to: 13-13

examples/lambda-api-gateway-streaming/src/client.ts (2)

13-16: Prefer configuring the URL via env var (and fail fast if unset) instead of a hard-coded placeholder.
Reduces accidental misconfig and makes the example easier to run in CI/docs tooling.

-    httpBatchStreamLink({
-      // Insert your API Gateway URL after deploying the serverless app
-      url: 'https://???????.execute-api.us-east-1.amazonaws.com/dev',
-    }),
+    httpBatchStreamLink({
+      url:
+        process.env.TRPC_API_URL ??
+        (() => {
+          throw new Error('Missing TRPC_API_URL');
+        })(),
+    }),

20-39: Catch block: treat error as unknown and log via console.error (example ergonomics).
This avoids losing stack traces and keeps TS strictness-friendly patterns for users.

-  } catch (error) {
-    console.log('error', error);
+  } catch (error: unknown) {
+    console.error('error', error);
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0583db and 8fb0404.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • examples/lambda-api-gateway-streaming/README.md (1 hunks)
  • examples/lambda-api-gateway-streaming/src/client.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

**/*.{ts,tsx}: Always use import type for type-only imports
Separate type imports from value imports
Avoid overzealous object destructuring; prefer direct property access
Object destructuring is acceptable when a variable is used 3+ times
Prefer array destructuring
Avoid sparse array destructuring
Never destructure in function parameter declarations
Avoid destructuring potentially nullish nested properties
Maximum 3 parameters per function; use options objects when more
Type parameter names must match /^(T|$)(A-Z)?[0-9]*$/
Prefix unused variables, parameters, and caught errors with _
Prefer namespace imports for validation libraries and large modules (e.g., import * as z from 'zod', import * as React from 'react')
Follow import order: test helpers, tRPC test imports, third-party, then relative
Never import from @trpc/*/src; import from the package root instead
Do not use Symbol.dispose or Symbol.asyncDispose; use makeResource()/makeAsyncResource()
Always use await using for resource cleanup
Prefer makeResource()/makeAsyncResource() over manual disposal logic
Avoid non-null assertions (!)
Use proper type guards and optional chaining instead of non-null assertions
Switch statements must be exhaustive for union types
Rely on TypeScript inference; avoid unnecessary explicit return/output types
Use explicit types at public API boundaries, for complex generic constraints, or when inference is insufficient/ambiguous
Use the satisfies operator to retain inference while enforcing shapes
Use as const for literal type inference when appropriate
Prefer explicit typing over any
Use type assertions sparingly
Leverage TypeScript strict mode features

Files:

  • examples/lambda-api-gateway-streaming/src/client.ts
**/*.{ts,tsx,md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

Use camelCase for file names (with exceptions like TRPC/RPC/HTTP/JSON acronyms, .config.js, .d.ts, and tests)

Files:

  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/README.md
🧠 Learnings (11)
📚 Learning: 2025-09-05T15:16:48.745Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-09-05T15:16:48.745Z
Learning: Applies to **/*.test.ts : Use `ctx.client` from the test resource for making tRPC calls

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:31.379Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/tanstack-react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:31.379Z
Learning: Applies to packages/tanstack-react-query/**/*.test.tsx : Use `ctx.useTRPCClient()` for direct (vanilla) tRPC client access in tests

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/README.md
📚 Learning: 2025-09-05T15:16:48.745Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-09-05T15:16:48.745Z
Learning: Applies to **/*.test.ts : Import `testServerAndClientResource` from `trpc/client/__tests__/testClientResource`

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:48.745Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/test-patterns.mdc:0-0
Timestamp: 2025-09-05T15:16:48.745Z
Learning: Applies to **/*.test.ts : Configure client options via the `client` callback in `testServerAndClientResource` options

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Create the tRPC React client with createTRPCReact<typeof appRouter>()

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T16:48:06.982Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-09-05T16:48:06.982Z
Learning: Share common functionality through `trpc/server` and keep client/server concerns separate

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
  • examples/lambda-api-gateway-streaming/README.md
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Import getUntypedClient from 'trpc/client' when an untyped client is needed

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : If not using createAppRouter, you may create an inline router using testServerAndClientResource with appropriate server and client link configuration

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Import createTRPCReact from 'trpc/react-query' (legacy API)

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:01.878Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:01.878Z
Learning: Applies to packages/react-query/**/*.test.tsx : Wrap components with a custom App that provides trpc.Provider (legacy) and QueryClientProvider

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
📚 Learning: 2025-09-05T15:16:31.379Z
Learnt from: CR
Repo: trpc/trpc PR: 0
File: .cursor/rules/tanstack-react-query-tests.mdc:0-0
Timestamp: 2025-09-05T15:16:31.379Z
Learning: Applies to packages/tanstack-react-query/**/*.test.tsx : Use `ctx.useTRPC()` for TanStack React Query hooks access in components under test

Applied to files:

  • examples/lambda-api-gateway-streaming/src/client.ts
🧬 Code graph analysis (1)
examples/lambda-api-gateway-streaming/src/client.ts (3)
examples/lambda-api-gateway-streaming/src/server.ts (1)
  • AppRouter (48-48)
packages/client/src/links/loggerLink.ts (1)
  • loggerLink (214-268)
packages/client/src/links/httpBatchStreamLink.ts (1)
  • httpBatchStreamLink (23-186)
🪛 LanguageTool
examples/lambda-api-gateway-streaming/README.md

[style] ~12-~12: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...npm install pnpm build pnpm deploy ``` This will deploy the Lambda function and API...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Lint and auto-fix
  • GitHub Check: test
  • GitHub Check: typecheck
  • GitHub Check: build
🔇 Additional comments (1)
examples/lambda-api-gateway-streaming/src/client.ts (1)

1-18: No changes needed. createTRPCClient is the correct public API for typed clients with links like httpBatchStreamLink. This is the recommended approach for creating a tRPC client with type inference from a router definition (the lower-level createTRPCProxyClient is an internal API). The example is correct as written.

Comment on lines +13 to +14
This will deploy the Lambda function and API Gateway REST API. The API Gateway endpoint URL will be displayed after deployment.

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Minor doc style: avoid repeating “This will …”. (LanguageTool hint)
Consider rephrasing Line 13 to not start with “This”.

🤖 Prompt for AI Agents
In examples/lambda-api-gateway-streaming/README.md around lines 13 to 14, the
sentence begins with a repeated "This will..." which is stylistically redundant;
rephrase the line to avoid starting with "This" (for example, use an active
phrasing like "Deploy the Lambda function and API Gateway REST API; the API
Gateway endpoint URL will be displayed after deployment." or similar) so the
sentence reads more concise and avoids repetition.

@Nick-Lucas Nick-Lucas merged commit 9a17cef into trpc:main Dec 12, 2025
45 checks passed
@anatolzak anatolzak deleted the feat/api-gateway-streaming branch December 12, 2025 19:29
@github-actions
Copy link
Contributor

This pull request has been locked because we are very unlikely to see comments on closed issues. If you think, this PR is still necessary, create a new one with the same branch. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 14, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: aws api gateway streaming support

2 participants