kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/715/head
rodzic
7dd05666ce
commit
30d909c6f1
|
@ -5,6 +5,7 @@ import * as middleware from '@/lib/middleware'
|
|||
|
||||
import { registerHealthCheck } from './health-check'
|
||||
import { registerV1UsersGetUser } from './users/get-user'
|
||||
import { registerV1UsersUpdateUser } from './users/update-user'
|
||||
|
||||
export const apiV1 = new OpenAPIHono()
|
||||
|
||||
|
@ -13,8 +14,9 @@ const pri = new OpenAPIHono<AuthenticatedEnv>()
|
|||
|
||||
registerHealthCheck(pub)
|
||||
|
||||
// users
|
||||
// users crud
|
||||
registerV1UsersGetUser(pri)
|
||||
registerV1UsersUpdateUser(pri)
|
||||
|
||||
apiV1.route('/', pub)
|
||||
apiV1.use(middleware.authenticate)
|
||||
|
|
|
@ -9,8 +9,7 @@ const ParamsSchema = z.object({
|
|||
param: {
|
||||
name: 'userId',
|
||||
in: 'path'
|
||||
},
|
||||
example: 'pfh0haxfpzowht3oi213cqos'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -37,13 +36,8 @@ const route = createRoute({
|
|||
}
|
||||
})
|
||||
|
||||
export type Route = typeof route
|
||||
export type V1UsersGetUserResponse = z.infer<
|
||||
(typeof route.responses)[200]['content']['application/json']['schema']
|
||||
>
|
||||
|
||||
export const registerV1UsersGetUser = (app: OpenAPIHono<AuthenticatedEnv>) =>
|
||||
app.openapi(route, async (c) => {
|
||||
export function registerV1UsersGetUser(app: OpenAPIHono<AuthenticatedEnv>) {
|
||||
return app.openapi(route, async (c) => {
|
||||
const { userId } = c.req.valid('param')
|
||||
|
||||
const user = await db.query.users.findFirst({
|
||||
|
@ -53,3 +47,4 @@ export const registerV1UsersGetUser = (app: OpenAPIHono<AuthenticatedEnv>) =>
|
|||
|
||||
return c.json(parseZodSchema(schema.userSelectSchema, user))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import { createRoute, type OpenAPIHono, z } from '@hono/zod-openapi'
|
||||
|
||||
import type { AuthenticatedEnv } from '@/lib/types'
|
||||
import { db, eq, schema, userIdSchema } from '@/db'
|
||||
import { assert, parseZodSchema } from '@/lib/utils'
|
||||
|
||||
const ParamsSchema = z.object({
|
||||
userId: userIdSchema.openapi({
|
||||
param: {
|
||||
name: 'userId',
|
||||
in: 'path'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const route = createRoute({
|
||||
tags: ['users'],
|
||||
operationId: 'updateUser',
|
||||
method: 'put',
|
||||
path: 'users/{userId}',
|
||||
security: [{ bearerAuth: [] }],
|
||||
request: {
|
||||
params: ParamsSchema,
|
||||
body: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: schema.userUpdateSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: 'A user object',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: schema.userSelectSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
// ...openApiErrorResponses
|
||||
}
|
||||
})
|
||||
|
||||
export function registerV1UsersUpdateUser(app: OpenAPIHono<AuthenticatedEnv>) {
|
||||
return app.openapi(route, async (c) => {
|
||||
const { userId } = c.req.valid('param')
|
||||
const body = c.req.valid('json')
|
||||
|
||||
const user = await db
|
||||
.update(schema.users)
|
||||
.set(body)
|
||||
.where(eq(schema.users.id, userId))
|
||||
.returning()
|
||||
assert(user, 404, `User not found: ${userId}`)
|
||||
|
||||
return c.json(parseZodSchema(schema.userSelectSchema, user))
|
||||
})
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
|
||||
// TODO: Currently unused after forking @fisch0920/drizzle-zod.
|
||||
export function makeNullablePropsOptional<Schema extends z.AnyZodObject>(
|
||||
schema: Schema
|
||||
): z.ZodObject<{
|
||||
[key in keyof Schema['shape']]: Schema['shape'][key] extends z.ZodNullable<
|
||||
infer T
|
||||
>
|
||||
? z.ZodOptional<T>
|
||||
: Schema['shape'][key]
|
||||
}> {
|
||||
const entries = Object.entries(schema.shape)
|
||||
const newProps: any = {}
|
||||
|
||||
for (const [key, value] of entries) {
|
||||
newProps[key] =
|
||||
value instanceof z.ZodNullable ? value.unwrap().optional() : value
|
||||
return newProps
|
||||
}
|
||||
|
||||
return z.object(newProps) as any
|
||||
}
|
||||
|
||||
export type ColumnType =
|
||||
// string
|
||||
| 'text'
|
||||
| 'varchar'
|
||||
| 'timestamp'
|
||||
| 'stripeId'
|
||||
| 'projectId'
|
||||
| 'deploymentId'
|
||||
| 'cuid'
|
||||
// boolean
|
||||
| 'boolean'
|
||||
// number
|
||||
| 'integer'
|
||||
| 'smallint'
|
||||
| 'bigint'
|
||||
// json
|
||||
| 'json'
|
||||
| 'jsonb'
|
||||
|
||||
export type ColumnTypeToTSType<T extends ColumnType> = T extends
|
||||
| 'text'
|
||||
| 'varchar'
|
||||
| 'timestamp'
|
||||
| 'cuid'
|
||||
| 'stripeId'
|
||||
| 'projectId'
|
||||
| 'deploymentId'
|
||||
? string
|
||||
: T extends 'boolean'
|
||||
? boolean
|
||||
: T extends 'integer' | 'smallint' | 'bigint'
|
||||
? number
|
||||
: never
|
||||
|
||||
/**
|
||||
* @see https://github.com/drizzle-team/@fisch0920/drizzle-orm/issues/2745
|
||||
*/
|
||||
function optional<
|
||||
T extends ColumnType,
|
||||
InferredType extends
|
||||
| string
|
||||
| boolean
|
||||
| number
|
||||
| object = ColumnTypeToTSType<T>
|
||||
>(dataType: T) {
|
||||
return customType<{
|
||||
data: InferredType | undefined
|
||||
driverData: InferredType | null
|
||||
config: T extends 'stripeId'
|
||||
? {
|
||||
length: number
|
||||
}
|
||||
: never
|
||||
}>({
|
||||
dataType() {
|
||||
if (dataType === 'stripeId') {
|
||||
return 'varchar({ length: 255 })'
|
||||
}
|
||||
|
||||
if (dataType === 'cuid') {
|
||||
return 'varchar({ length: 24 })'
|
||||
}
|
||||
|
||||
if (dataType === 'projectId') {
|
||||
return 'varchar({ length: 130 })'
|
||||
}
|
||||
|
||||
if (dataType === 'deploymentId') {
|
||||
return 'varchar({ length: 160 })'
|
||||
}
|
||||
|
||||
if (dataType === 'timestamp') {
|
||||
return 'timestamp({ mode: "string" })'
|
||||
}
|
||||
|
||||
return dataType
|
||||
},
|
||||
fromDriver: (v) => v ?? undefined,
|
||||
toDriver: (v) => v ?? null
|
||||
})
|
||||
}
|
||||
|
||||
export const optionalText = optional('text')
|
||||
export const optionalTimestamp = optional('timestamp')
|
||||
export const optionalBoolean = optional('boolean')
|
||||
export const optionalVarchar = optional('varchar')
|
||||
export const optionalCuid = optional('cuid')
|
||||
export const optionalStripeId = optional('stripeId')
|
||||
export const optionalProjectId = optional('projectId')
|
||||
export const optionalDeploymentId = optional('deploymentId')
|
|
@ -89,4 +89,9 @@ export const userSelectSchema = createSelectSchema(users, {
|
|||
providers: authProvidersSchema
|
||||
}).openapi('User')
|
||||
|
||||
export const userUpdateSchema = createUpdateSchema(users)
|
||||
export const userUpdateSchema = createUpdateSchema(users).pick({
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
image: true,
|
||||
isStripeConnectEnabledByDefault: true
|
||||
})
|
||||
|
|
|
@ -13,6 +13,9 @@ import { createSchemaFactory } from '@fisch0920/drizzle-zod'
|
|||
import { z } from '@hono/zod-openapi'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
|
||||
/**
|
||||
* `cuid2`
|
||||
*/
|
||||
export function cuid<U extends string, T extends Readonly<[U, ...U[]]>>(
|
||||
config?: PgVarcharConfig<T | Writable<T>, never>
|
||||
): PgVarcharBuilderInitial<'', Writable<T>, 24> {
|
||||
|
@ -43,6 +46,9 @@ export function deploymentId<U extends string, T extends Readonly<[U, ...U[]]>>(
|
|||
return varchar({ length: 160, ...config })
|
||||
}
|
||||
|
||||
/**
|
||||
* Default `id` primary key as a cuid2
|
||||
*/
|
||||
export const id = varchar('id', { length: 24 })
|
||||
.primaryKey()
|
||||
.$defaultFn(createId)
|
||||
|
@ -81,116 +87,3 @@ export const { createInsertSchema, createSelectSchema, createUpdateSchema } =
|
|||
date: true
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: Currently unused after forking @fisch0920/drizzle-zod.
|
||||
// export function makeNullablePropsOptional<Schema extends z.AnyZodObject>(
|
||||
// schema: Schema
|
||||
// ): z.ZodObject<{
|
||||
// [key in keyof Schema['shape']]: Schema['shape'][key] extends z.ZodNullable<
|
||||
// infer T
|
||||
// >
|
||||
// ? z.ZodOptional<T>
|
||||
// : Schema['shape'][key]
|
||||
// }> {
|
||||
// const entries = Object.entries(schema.shape)
|
||||
// const newProps: any = {}
|
||||
|
||||
// for (const [key, value] of entries) {
|
||||
// newProps[key] =
|
||||
// value instanceof z.ZodNullable ? value.unwrap().optional() : value
|
||||
// return newProps
|
||||
// }
|
||||
|
||||
// return z.object(newProps) as any
|
||||
// }
|
||||
|
||||
// export type ColumnType =
|
||||
// // string
|
||||
// | 'text'
|
||||
// | 'varchar'
|
||||
// | 'timestamp'
|
||||
// | 'stripeId'
|
||||
// | 'projectId'
|
||||
// | 'deploymentId'
|
||||
// | 'cuid'
|
||||
// // boolean
|
||||
// | 'boolean'
|
||||
// // number
|
||||
// | 'integer'
|
||||
// | 'smallint'
|
||||
// | 'bigint'
|
||||
// // json
|
||||
// | 'json'
|
||||
// | 'jsonb'
|
||||
|
||||
// export type ColumnTypeToTSType<T extends ColumnType> = T extends
|
||||
// | 'text'
|
||||
// | 'varchar'
|
||||
// | 'timestamp'
|
||||
// | 'cuid'
|
||||
// | 'stripeId'
|
||||
// | 'projectId'
|
||||
// | 'deploymentId'
|
||||
// ? string
|
||||
// : T extends 'boolean'
|
||||
// ? boolean
|
||||
// : T extends 'integer' | 'smallint' | 'bigint'
|
||||
// ? number
|
||||
// : never
|
||||
|
||||
// /**
|
||||
// * @see https://github.com/drizzle-team/@fisch0920/drizzle-orm/issues/2745
|
||||
// */
|
||||
// function optional<
|
||||
// T extends ColumnType,
|
||||
// InferredType extends
|
||||
// | string
|
||||
// | boolean
|
||||
// | number
|
||||
// | object = ColumnTypeToTSType<T>
|
||||
// >(dataType: T) {
|
||||
// return customType<{
|
||||
// data: InferredType | undefined
|
||||
// driverData: InferredType | null
|
||||
// config: T extends 'stripeId'
|
||||
// ? {
|
||||
// length: number
|
||||
// }
|
||||
// : never
|
||||
// }>({
|
||||
// dataType() {
|
||||
// if (dataType === 'stripeId') {
|
||||
// return 'varchar({ length: 255 })'
|
||||
// }
|
||||
|
||||
// if (dataType === 'cuid') {
|
||||
// return 'varchar({ length: 24 })'
|
||||
// }
|
||||
|
||||
// if (dataType === 'projectId') {
|
||||
// return 'varchar({ length: 130 })'
|
||||
// }
|
||||
|
||||
// if (dataType === 'deploymentId') {
|
||||
// return 'varchar({ length: 160 })'
|
||||
// }
|
||||
|
||||
// if (dataType === 'timestamp') {
|
||||
// return 'timestamp({ mode: "string" })'
|
||||
// }
|
||||
|
||||
// return dataType
|
||||
// },
|
||||
// fromDriver: (v) => v ?? undefined,
|
||||
// toDriver: (v) => v ?? null
|
||||
// })
|
||||
// }
|
||||
|
||||
// export const optionalText = optional('text')
|
||||
// export const optionalTimestamp = optional('timestamp')
|
||||
// export const optionalBoolean = optional('boolean')
|
||||
// export const optionalVarchar = optional('varchar')
|
||||
// export const optionalCuid = optional('cuid')
|
||||
// export const optionalStripeId = optional('stripeId')
|
||||
// export const optionalProjectId = optional('projectId')
|
||||
// export const optionalDeploymentId = optional('deploymentId')
|
||||
|
|
Ładowanie…
Reference in New Issue