refactor: 更好的orpc结构

This commit is contained in:
2026-01-22 16:37:10 +08:00
parent 660ee0a545
commit 2b3e91167e
20 changed files with 53 additions and 28 deletions

View File

@@ -1 +0,0 @@
export * from './db'

View File

@@ -1,7 +0,0 @@
import { implement } from '@orpc/server'
import { contract } from './contract'
// biome-ignore lint/complexity/noBannedTypes: 暂无 context
type Context = {}
export const os = implement(contract).$context<Context>()

View File

@@ -3,8 +3,8 @@ import { RPCLink } from '@orpc/client/fetch'
import { createRouterClient } from '@orpc/server' import { createRouterClient } from '@orpc/server'
import { createIsomorphicFn } from '@tanstack/react-start' import { createIsomorphicFn } from '@tanstack/react-start'
import { getRequestHeaders } from '@tanstack/react-start/server' import { getRequestHeaders } from '@tanstack/react-start/server'
import { router } from '@/api/routers' import { router } from '@/server/api/routers'
import type { RouterClient } from '@/api/types' import type { RouterClient } from '@/server/api/types'
const getORPCClient = createIsomorphicFn() const getORPCClient = createIsomorphicFn()
.server(() => .server(() =>
@@ -21,4 +21,4 @@ const getORPCClient = createIsomorphicFn()
return createORPCClient<RouterClient>(link) return createORPCClient<RouterClient>(link)
}) })
export const client: RouterClient = getORPCClient() export const orpc: RouterClient = getORPCClient()

View File

@@ -1,7 +1,7 @@
import { createTanstackQueryUtils } from '@orpc/tanstack-query' import { createTanstackQueryUtils } from '@orpc/tanstack-query'
import { client } from './client' import { orpc as orpcClient } from './orpc.client'
export const orpc = createTanstackQueryUtils(client, { export const orpc = createTanstackQueryUtils(orpcClient, {
experimental_defaults: { experimental_defaults: {
todo: { todo: {
create: { create: {

View File

@@ -2,7 +2,7 @@ import { ORPCError, onError, ValidationError } from '@orpc/server'
import { RPCHandler } from '@orpc/server/fetch' import { RPCHandler } from '@orpc/server/fetch'
import { createFileRoute } from '@tanstack/react-router' import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod' import { z } from 'zod'
import { router } from '@/api/routers' import { router } from '@/server/api/routers'
const handler = new RPCHandler(router, { const handler = new RPCHandler(router, {
interceptors: [ interceptors: [
@@ -49,7 +49,9 @@ export const Route = createFileRoute('/api/rpc/$')({
ANY: async ({ request }) => { ANY: async ({ request }) => {
const { response } = await handler.handle(request, { const { response } = await handler.handle(request, {
prefix: '/api/rpc', prefix: '/api/rpc',
context: {}, context: {
headers: request.headers,
},
}) })
return response ?? new Response('Not Found', { status: 404 }) return response ?? new Response('Not Found', { status: 404 })

View File

@@ -4,7 +4,7 @@ import { isTauri } from '@tauri-apps/api/core'
import { getCurrentWindow } from '@tauri-apps/api/window' import { getCurrentWindow } from '@tauri-apps/api/window'
import type { ChangeEventHandler, FormEventHandler } from 'react' import type { ChangeEventHandler, FormEventHandler } from 'react'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { orpc } from '@/lib/orpc/query-client' import { orpc } from '@/client/query-client'
export const Route = createFileRoute('/')({ export const Route = createFileRoute('/')({
component: Todos, component: Todos,

View File

@@ -0,0 +1,25 @@
import type { Database } from '@/server/db'
/**
* 基础 Context - 所有请求都包含的上下文
*/
export interface BaseContext {
headers: Headers
}
/**
* 数据库 Context - 通过 db middleware 扩展
*/
export interface DBContext extends BaseContext {
db: Database
}
/**
* 认证 Context - 通过 auth middleware 扩展(未来使用)
*
* @example
* export interface AuthContext extends DBContext {
* userId: string
* user: User
* }
*/

View File

@@ -1,4 +1,4 @@
import * as todo from './todo' import * as todo from './todo.contract'
export const contract = { export const contract = {
todo, todo,

View File

@@ -5,7 +5,7 @@ import {
createUpdateSchema, createUpdateSchema,
} from 'drizzle-zod' } from 'drizzle-zod'
import { z } from 'zod' import { z } from 'zod'
import { todoTable } from '@/db/schema' import { todoTable } from '@/server/db/schema'
const selectSchema = createSelectSchema(todoTable) const selectSchema = createSelectSchema(todoTable)

View File

@@ -1,5 +1,5 @@
import { os } from '@orpc/server' import { os } from '@orpc/server'
import { getDb } from '@/db' import { getDb } from '@/server/db'
export const db = os.middleware(async ({ context, next }) => { export const db = os.middleware(async ({ context, next }) => {
return next({ return next({

View File

@@ -0,0 +1 @@
export * from './db.middleware'

View File

@@ -1,5 +1,5 @@
import { os } from '../server' import { os } from '../server'
import * as todo from './todo' import * as todo from './todo.router'
export const router = os.router({ export const router = os.router({
todo, todo,

View File

@@ -1,8 +1,8 @@
import { ORPCError } from '@orpc/server' import { ORPCError } from '@orpc/server'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import { db } from '@/api/middlewares' import { todoTable } from '@/server/db/schema'
import { os } from '@/api/server' import { db } from '../middlewares'
import { todoTable } from '@/db/schema' import { os } from '../server'
export const list = os.todo.list.use(db).handler(async ({ context }) => { export const list = os.todo.list.use(db).handler(async ({ context }) => {
const todos = await context.db.query.todoTable.findMany({ const todos = await context.db.query.todoTable.findMany({

View File

@@ -0,0 +1,5 @@
import { implement } from '@orpc/server'
import type { BaseContext } from './context'
import { contract } from './contracts'
export const os = implement(contract).$context<BaseContext>()

View File

@@ -3,7 +3,7 @@ import type {
InferContractRouterInputs, InferContractRouterInputs,
InferContractRouterOutputs, InferContractRouterOutputs,
} from '@orpc/contract' } from '@orpc/contract'
import type { Contract } from './contract' import type { Contract } from './contracts'
export type RouterClient = ContractRouterClient<Contract> export type RouterClient = ContractRouterClient<Contract>
export type RouterInputs = InferContractRouterInputs<Contract> export type RouterInputs = InferContractRouterInputs<Contract>

View File

@@ -1,6 +1,6 @@
import { drizzle } from 'drizzle-orm/postgres-js' import { drizzle } from 'drizzle-orm/postgres-js'
import * as schema from '@/db/schema'
import { env } from '@/env' import { env } from '@/env'
import * as schema from '@/server/db/schema'
export const createDb = () => export const createDb = () =>
drizzle({ drizzle({
@@ -11,12 +11,12 @@ export const createDb = () =>
schema, schema,
}) })
export type Db = ReturnType<typeof createDb> export type Database = ReturnType<typeof createDb>
export const getDb = (() => { export const getDb = (() => {
let db: Db | null = null let db: Database | null = null
return (singleton = true): Db => { return (singleton = true): Database => {
if (!singleton) { if (!singleton) {
return createDb() return createDb()
} }