forked from imbytecat/fullstack-starter
refactor: 更好的orpc结构
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
export * from './db'
|
|
||||||
@@ -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>()
|
|
||||||
@@ -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()
|
||||||
@@ -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: {
|
||||||
@@ -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 })
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
25
apps/server/src/server/api/context.ts
Normal file
25
apps/server/src/server/api/context.ts
Normal 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
|
||||||
|
* }
|
||||||
|
*/
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as todo from './todo'
|
import * as todo from './todo.contract'
|
||||||
|
|
||||||
export const contract = {
|
export const contract = {
|
||||||
todo,
|
todo,
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -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({
|
||||||
1
apps/server/src/server/api/middlewares/index.ts
Normal file
1
apps/server/src/server/api/middlewares/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './db.middleware'
|
||||||
@@ -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,
|
||||||
@@ -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({
|
||||||
5
apps/server/src/server/api/server.ts
Normal file
5
apps/server/src/server/api/server.ts
Normal 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>()
|
||||||
@@ -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>
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user