pull/715/head
Travis Fischer 2025-05-15 20:50:32 +07:00
rodzic f539c7ed38
commit f55ba7f060
5 zmienionych plików z 65 dodań i 25 usunięć

Wyświetl plik

@ -26,6 +26,16 @@ import {
// This may require a separate model to aggregate User Applications.
// 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(
'consumers',
{
@ -34,9 +44,15 @@ export const consumers = pgTable(
// API token for this consumer
token: text().notNull(),
// The stripe subscription plan this consumer is subscribed to (or 'free' if supported)
plan: text(),
// Whether the consumer has made at least one successful API call after
// initializing their subscription.
activated: boolean().default(false).notNull(),
// Whether the consumer's subscription is currently active
enabled: boolean().default(true).notNull(),
env: text().default('dev').notNull(),

Wyświetl plik

@ -1,5 +1,5 @@
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 { consumers, consumerSelectSchema } from './consumer'
@ -12,45 +12,48 @@ import {
cuid,
deploymentId,
id,
logEntryLevelEnum,
logEntryTypeEnum,
projectId,
stripeId,
timestamps
} from './utils'
/**
* A `LogEntry` is an internal audit log entry.
*/
export const logEntries = pgTable(
'log_entries',
{
id,
...timestamps,
type: text().notNull(),
level: text().notNull().default('info'), // TODO: enum
// core data (required)
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(),
projectId: projectId(),
deploymentId: deploymentId(),
consumerId: cuid(),
// (optional) misc context info
service: text(),
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()
// misc metadata (optional)
metadata: jsonb().$type<Record<string, unknown>>().default({}).notNull()
},
(table) => [
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_projectId_idx').on(table.projectId),
index('log_entry_deploymentId_idx').on(table.deploymentId),

Wyświetl plik

@ -92,6 +92,14 @@ export const timestamps = {
export const userRoleEnum = pgEnum('UserRole', ['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 } =
createSchemaFactory({

Wyświetl plik

@ -1,11 +1,24 @@
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', () => {
expectTypeOf<RawUser>().toExtend<User>()
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>()
})

Wyświetl plik

@ -34,7 +34,7 @@ const server = serve({
port: env.PORT
})
initExitHooks({ server })
// eslint-disable-next-line no-console
console.log(`Server running on port ${env.PORT}`)
initExitHooks({ server })