Skip to content

Conversation

@digoburigo
Copy link
Contributor

Sever adapter for Tanstack Start

Usage example

// routes/api/$.ts
import { createFileRoute } from '@tanstack/react-router'
import { TanStackStartHandler } from '@zenstackhq/server/tanstack-start'
import { enhance } from '@zenstackhq/runtime'
import { prisma } from '~/server/db'

const handler = TanStackStartHandler({
  getPrisma: async () => enhance(prisma)
})

export const Route = createFileRoute('/api/$')({
  server: {
    handlers: {
      GET: handler,
      POST: handler,
      PUT: handler,
      PATCH: handler,
      DELETE: handler,
    }
  }
})

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 11, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • packages/server/package.json is excluded by !**/*.json

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Adds a new TanStack Start adapter: defines options and a handler factory that loads assets, extracts Prisma from context, parses request URL/body/params, delegates to an RPC/custom handler, and returns JSON responses with basic error handling. Includes a comprehensive test suite covering RPC and REST flows, permissions, and schema loading.

Changes

Cohort / File(s) Summary
TanStack Start adapter implementation
packages/server/src/tanstack-start/index.ts, packages/server/src/tanstack-start/handler.ts
Introduces TanStackStartOptions with getPrisma; adds a handler factory that loads assets, parses requests (method, path, query, body), resolves a request handler, invokes it with Prisma and assets, and returns JSON responses with error handling.
Adapter tests
packages/server/tests/adapter/tanstack-start.test.ts
Adds tests for RPC and REST operations, access policies, custom load paths, zod schema usage, and end-to-end request handling via TanStackStartHandler.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant TanStackRoute as TanStack Start Route Handler
  participant Prisma as Prisma Provider
  participant RPC as RPCApiHandler / Custom Handler
  Note over TanStackRoute: New adapter flow
  Client->>TanStackRoute: HTTP Request (method, URL, params._splat, body)
  TanStackRoute->>Prisma: getPrisma(request, params)
  Prisma-->>TanStackRoute: prisma | null
  alt prisma missing
    TanStackRoute-->>Client: 500 JSON { error: "Prisma client not available" }
  else prisma present
    TanStackRoute->>TanStackRoute: Parse path/query/body
    TanStackRoute->>RPC: handle({ method, path, query, body, prisma, modelMeta, zodSchemas, logger })
    RPC-->>TanStackRoute: { status, result | error }
    TanStackRoute-->>Client: JSON Response with status
  end
  rect rgba(240,240,255,0.5)
  Note over TanStackRoute,RPC: Catches unhandled errors → 500 JSON
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • ymc9

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title “feat: add tanstack start adapter” directly summarizes the primary change in this pull request by indicating the addition of a TanStack Start adapter, and it does so concisely and without unnecessary detail.
Description Check ✅ Passed The description outlines the creation of a server adapter for TanStack Start and includes a relevant usage example, clearly relating to the changes made in the code.

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.

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 (2)
packages/server/tests/adapter/tanstack-start.test.ts (1)

13-16: Consider alignment with tanstack-query unmarshal for consistency.

This unmarshal implementation simply parses JSON, whereas the tanstack-query runtime's unmarshal (referenced in relevant code snippets) handles serialization metadata via deserialize. If ZenStack's handlers return serialized data with metadata, this simpler unmarshal may lose fidelity.

If the handlers return serialization metadata, consider using the tanstack-query unmarshal pattern:

+import { unmarshal as deserialize } from '@zenstackhq/plugins/tanstack-query/runtime/common';
+
 async function unmarshal(response: Response): Promise<any> {
     const text = await response.text();
-    return JSON.parse(text);
+    const parsed = JSON.parse(text);
+    if (typeof parsed === 'object' && parsed?.data && parsed?.meta?.serialization) {
+        const deserializedData = deserialize(parsed.data, parsed.meta.serialization);
+        return { ...parsed, data: deserializedData };
+    }
+    return parsed;
 }

Otherwise, if handlers never return serialization metadata, the current implementation is sufficient.

packages/server/src/tanstack-start/handler.ts (1)

21-30: Add error handling for getPrisma callback.

The getPrisma callback is awaited but not wrapped in a try-catch. If it throws (e.g., due to a database connection issue or invalid request context), the unhandled error will propagate to the outer catch block at line 73, returning a generic 500 error.

Wrap the getPrisma call in a try-catch to provide a more specific error response:

+    let prisma: DbClientContract;
+    try {
+        prisma = (await options.getPrisma(request, params)) as DbClientContract;
+    } catch (err) {
+        return new Response(JSON.stringify({ message: 'Failed to initialize Prisma client' }), {
+            status: 500,
+            headers: {
+                'Content-Type': 'application/json',
+            },
+        });
+    }
-    const prisma = (await options.getPrisma(request, params)) as DbClientContract;
     if (!prisma) {
         return new Response(JSON.stringify({ message: 'unable to get prisma from request context' }), {
             status: 500,
             headers: {
                 'Content-Type': 'application/json',
             },
         });
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edfd557 and eb56d63.

⛔ Files ignored due to path filters (2)
  • packages/server/package.json is excluded by !**/*.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/*.yaml
📒 Files selected for processing (3)
  • packages/server/src/tanstack-start/handler.ts (1 hunks)
  • packages/server/src/tanstack-start/index.ts (1 hunks)
  • packages/server/tests/adapter/tanstack-start.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
packages/server/src/tanstack-start/index.ts (1)
packages/server/src/types.ts (1)
  • AdapterBaseOptions (32-56)
packages/server/src/tanstack-start/handler.ts (3)
packages/server/src/tanstack-start/index.ts (1)
  • TanStackStartOptions (7-12)
packages/server/src/shared.ts (1)
  • loadAssets (5-21)
packages/runtime/src/types.ts (1)
  • DbClientContract (91-93)
packages/server/tests/adapter/tanstack-start.test.ts (4)
packages/plugins/tanstack-query/src/runtime/common.ts (1)
  • unmarshal (222-230)
packages/server/src/types.ts (1)
  • Response (19-22)
packages/server/src/tanstack-start/index.ts (2)
  • TanStackStartOptions (7-12)
  • TanStackStartHandler (18-20)
packages/testtools/src/schema.ts (1)
  • loadSchema (173-249)
🔇 Additional comments (3)
packages/server/src/tanstack-start/index.ts (1)

1-22: LGTM!

The TanStack Start adapter's public API is well-designed:

  • TanStackStartOptions extends AdapterBaseOptions with a flexible getPrisma callback.
  • TanStackStartHandler is a clean wrapper that delegates to the internal Handler.
  • JSDoc includes a reference to the documentation.
  • The default export follows standard patterns.
packages/server/src/tanstack-start/handler.ts (1)

47-54: Request body parsing tolerates failures appropriately.

The try-catch around request.json() silently ignores parse failures. This is intentional and correct for GET/DELETE requests that may have no body, or for requests with malformed JSON that should proceed without a body.

packages/server/tests/adapter/tanstack-start.test.ts (1)

121-127: Upsert always returns 201 by design, so both tests are correct.

Likely an incorrect or invalid review comment.

Copy link
Member

@ymc9 ymc9 left a comment

Choose a reason for hiding this comment

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

Hey @digoburigo , thanks for making this contribution! I don't have much knowledge about tanstack start but the code looks great to me. I'll merge and include it in the next minor.

Do you want to add a quick documentation for it too? Code is here: https://github.com/zenstackhq/zenstack-docs/tree/main/docs/reference/server-adapters

@ymc9 ymc9 merged commit 153047b into zenstackhq:dev Oct 13, 2025
12 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