kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/715/head
rodzic
f539c7ed38
commit
f55ba7f060
|
@ -26,6 +26,16 @@ import {
|
||||||
// This may require a separate model to aggregate User Applications.
|
// This may require a separate model to aggregate User Applications.
|
||||||
// https://docs.rapidapi.com/docs/keys#section-different-api-keys-per-application
|
// https://docs.rapidapi.com/docs/keys#section-different-api-keys-per-application
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `Consumer` is a user who has subscribed to a `Project`.
|
||||||
|
*
|
||||||
|
* Consumers are used to track usage and billing for a project.
|
||||||
|
*
|
||||||
|
* Consumers are linked to a corresponding Stripe Customer. The Stripe customer
|
||||||
|
* will either be the user's default Stripe Customer for the platform account,
|
||||||
|
* or a customer on the project's connected Stripe account if the project has
|
||||||
|
* Stripe Connect enabled.
|
||||||
|
*/
|
||||||
export const consumers = pgTable(
|
export const consumers = pgTable(
|
||||||
'consumers',
|
'consumers',
|
||||||
{
|
{
|
||||||
|
@ -34,9 +44,15 @@ export const consumers = pgTable(
|
||||||
|
|
||||||
// API token for this consumer
|
// API token for this consumer
|
||||||
token: text().notNull(),
|
token: text().notNull(),
|
||||||
|
|
||||||
|
// The stripe subscription plan this consumer is subscribed to (or 'free' if supported)
|
||||||
plan: text(),
|
plan: text(),
|
||||||
|
|
||||||
|
// Whether the consumer has made at least one successful API call after
|
||||||
|
// initializing their subscription.
|
||||||
activated: boolean().default(false).notNull(),
|
activated: boolean().default(false).notNull(),
|
||||||
|
|
||||||
|
// Whether the consumer's subscription is currently active
|
||||||
enabled: boolean().default(true).notNull(),
|
enabled: boolean().default(true).notNull(),
|
||||||
|
|
||||||
env: text().default('dev').notNull(),
|
env: text().default('dev').notNull(),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { relations } from '@fisch0920/drizzle-orm'
|
import { relations } from '@fisch0920/drizzle-orm'
|
||||||
import { index, pgTable, text } from '@fisch0920/drizzle-orm/pg-core'
|
import { index, jsonb, pgTable, text } from '@fisch0920/drizzle-orm/pg-core'
|
||||||
import { z } from '@hono/zod-openapi'
|
import { z } from '@hono/zod-openapi'
|
||||||
|
|
||||||
import { consumers, consumerSelectSchema } from './consumer'
|
import { consumers, consumerSelectSchema } from './consumer'
|
||||||
|
@ -12,45 +12,48 @@ import {
|
||||||
cuid,
|
cuid,
|
||||||
deploymentId,
|
deploymentId,
|
||||||
id,
|
id,
|
||||||
|
logEntryLevelEnum,
|
||||||
|
logEntryTypeEnum,
|
||||||
projectId,
|
projectId,
|
||||||
stripeId,
|
|
||||||
timestamps
|
timestamps
|
||||||
} from './utils'
|
} from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `LogEntry` is an internal audit log entry.
|
||||||
|
*/
|
||||||
export const logEntries = pgTable(
|
export const logEntries = pgTable(
|
||||||
'log_entries',
|
'log_entries',
|
||||||
{
|
{
|
||||||
id,
|
id,
|
||||||
...timestamps,
|
...timestamps,
|
||||||
|
|
||||||
type: text().notNull(),
|
// core data (required)
|
||||||
level: text().notNull().default('info'), // TODO: enum
|
type: logEntryTypeEnum().notNull().default('log'),
|
||||||
|
level: logEntryLevelEnum().notNull().default('info'),
|
||||||
|
message: text().notNull(),
|
||||||
|
|
||||||
// relations
|
// context info (required)
|
||||||
|
environment: text(),
|
||||||
|
service: text(),
|
||||||
|
requestId: text(),
|
||||||
|
traceId: text(),
|
||||||
|
|
||||||
|
// relations (optional)
|
||||||
userId: cuid(),
|
userId: cuid(),
|
||||||
projectId: projectId(),
|
projectId: projectId(),
|
||||||
deploymentId: deploymentId(),
|
deploymentId: deploymentId(),
|
||||||
consumerId: cuid(),
|
consumerId: cuid(),
|
||||||
|
|
||||||
// (optional) misc context info
|
// misc metadata (optional)
|
||||||
service: text(),
|
metadata: jsonb().$type<Record<string, unknown>>().default({}).notNull()
|
||||||
hostname: text(),
|
|
||||||
provider: text(),
|
|
||||||
ip: text(),
|
|
||||||
plan: text(),
|
|
||||||
subtype: text(),
|
|
||||||
|
|
||||||
// (optional) denormalized info
|
|
||||||
username: text(),
|
|
||||||
email: text(),
|
|
||||||
token: text(),
|
|
||||||
|
|
||||||
// (optional) denormalized stripe info
|
|
||||||
stripeCustomer: stripeId(),
|
|
||||||
stripeSubscription: stripeId()
|
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
index('log_entry_type_idx').on(table.type),
|
index('log_entry_type_idx').on(table.type),
|
||||||
|
index('log_entry_level_idx').on(table.level),
|
||||||
|
index('log_entry_environment_idx').on(table.environment),
|
||||||
|
index('log_entry_service_idx').on(table.service),
|
||||||
|
index('log_entry_requestId_idx').on(table.requestId),
|
||||||
|
index('log_entry_traceId_idx').on(table.traceId),
|
||||||
index('log_entry_userId_idx').on(table.userId),
|
index('log_entry_userId_idx').on(table.userId),
|
||||||
index('log_entry_projectId_idx').on(table.projectId),
|
index('log_entry_projectId_idx').on(table.projectId),
|
||||||
index('log_entry_deploymentId_idx').on(table.deploymentId),
|
index('log_entry_deploymentId_idx').on(table.deploymentId),
|
||||||
|
|
|
@ -92,6 +92,14 @@ export const timestamps = {
|
||||||
|
|
||||||
export const userRoleEnum = pgEnum('UserRole', ['user', 'admin'])
|
export const userRoleEnum = pgEnum('UserRole', ['user', 'admin'])
|
||||||
export const teamMemberRoleEnum = pgEnum('TeamMemberRole', ['user', 'admin'])
|
export const teamMemberRoleEnum = pgEnum('TeamMemberRole', ['user', 'admin'])
|
||||||
|
export const logEntryTypeEnum = pgEnum('LogEntryType', ['log'])
|
||||||
|
export const logEntryLevelEnum = pgEnum('LogEntryLevel', [
|
||||||
|
'trace',
|
||||||
|
'debug',
|
||||||
|
'info',
|
||||||
|
'warn',
|
||||||
|
'error'
|
||||||
|
])
|
||||||
|
|
||||||
export const { createInsertSchema, createSelectSchema, createUpdateSchema } =
|
export const { createInsertSchema, createSelectSchema, createUpdateSchema } =
|
||||||
createSchemaFactory({
|
createSchemaFactory({
|
||||||
|
|
|
@ -1,11 +1,24 @@
|
||||||
import { expectTypeOf, test } from 'vitest'
|
import { expectTypeOf, test } from 'vitest'
|
||||||
|
|
||||||
import type { RawUser, User } from './types'
|
import type { LogLevel } from '@/lib/logger'
|
||||||
|
|
||||||
type UserKeys = Exclude<keyof User, 'providers'>
|
import type { LogEntry, RawLogEntry, RawUser, User } from './types'
|
||||||
|
|
||||||
|
type UserKeys = Exclude<keyof User & keyof RawUser, 'providers'>
|
||||||
|
type LogEntryKeys = keyof RawLogEntry & keyof LogEntry
|
||||||
|
|
||||||
test('User types are compatible', () => {
|
test('User types are compatible', () => {
|
||||||
expectTypeOf<RawUser>().toExtend<User>()
|
expectTypeOf<RawUser>().toExtend<User>()
|
||||||
|
|
||||||
expectTypeOf<User[UserKeys]>().toEqualTypeOf<RawUser[UserKeys]>()
|
expectTypeOf<User[UserKeys]>().toEqualTypeOf<RawUser[UserKeys]>()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('LogEntry types are compatible', () => {
|
||||||
|
expectTypeOf<RawLogEntry>().toExtend<LogEntry>()
|
||||||
|
|
||||||
|
expectTypeOf<LogEntry[LogEntryKeys]>().toEqualTypeOf<
|
||||||
|
RawLogEntry[LogEntryKeys]
|
||||||
|
>()
|
||||||
|
|
||||||
|
expectTypeOf<LogEntry['level']>().toEqualTypeOf<LogLevel>()
|
||||||
|
})
|
||||||
|
|
|
@ -34,7 +34,7 @@ const server = serve({
|
||||||
port: env.PORT
|
port: env.PORT
|
||||||
})
|
})
|
||||||
|
|
||||||
|
initExitHooks({ server })
|
||||||
|
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(`Server running on port ${env.PORT}`)
|
console.log(`Server running on port ${env.PORT}`)
|
||||||
|
|
||||||
initExitHooks({ server })
|
|
||||||
|
|
Ładowanie…
Reference in New Issue