server/db/schema/settings-tables.ts
Rama main · réplica de lectura del repositorio original.
import { sql } from 'drizzle-orm'
import { check, index, integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'
import { user } from './auth-tables'
import { application, organization } from './authorization-tables'
export const webhookEndpoint = sqliteTable(
'webhook_endpoint',
{
id: text('id').primaryKey(),
url: text('url').notNull(),
events: text('events', { mode: 'json' }).$type<string[]>().notNull(),
enabled: integer('enabled', { mode: 'boolean' }).default(true).notNull(),
organizationId: text('organization_id').references(() => organization.id, { onDelete: 'cascade' }),
signingSecret: text('signing_secret').notNull(),
secretPrefix: text('secret_prefix').notNull(),
createdByUserId: text('created_by_user_id').references(() => user.id, { onDelete: 'set null' }),
createdAt: integer('created_at', { mode: 'timestamp_ms' })
.default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
.notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
.default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
.$onUpdate(() => new Date())
.notNull(),
},
(table) => [
index('webhookEndpoint_enabled_idx').on(table.enabled),
index('webhookEndpoint_organizationId_idx').on(table.organizationId),
index('webhookEndpoint_createdByUserId_idx').on(table.createdByUserId),
],
)
export const webhookDeliveryRequest = sqliteTable(
'webhook_delivery_request',
{
id: text('id').primaryKey(),
endpointId: text('endpoint_id')
.notNull()
.references(() => webhookEndpoint.id, { onDelete: 'cascade' }),
event: text('event').notNull(),
status: text('status').notNull().default('pending'),
attemptCount: integer('attempt_count').notNull().default(0),
httpStatus: integer('http_status'),
error: text('error'),
requestBody: text('request_body'),
responseBody: text('response_body'),
nextAttemptAt: integer('next_attempt_at', { mode: 'timestamp_ms' }),
createdAt: integer('created_at', { mode: 'timestamp_ms' })
.default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
.notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
.default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
.$onUpdate(() => new Date())
.notNull(),
},
(table) => [
index('webhookDeliveryRequest_endpointId_idx').on(table.endpointId),
index('webhookDeliveryRequest_status_idx').on(table.status),
index('webhookDeliveryRequest_createdAt_idx').on(table.createdAt),
],
)
export const webhookDeliveryAttempt = sqliteTable(
'webhook_delivery_attempt',
{
id: text('id').primaryKey(),
requestId: text('request_id')
.notNull()
.references(() => webhookDeliveryRequest.id, { onDelete: 'cascade' }),
idempotencyKey: text('idempotency_key').notNull(),
sequence: integer('sequence').notNull(),
status: text('status').notNull().default('pending'),
httpStatus: integer('http_status'),
error: text('error'),
responseBody: text('response_body'),
createdAt: integer('created_at', { mode: 'timestamp_ms' })
.default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
.notNull(),
completedAt: integer('completed_at', { mode: 'timestamp_ms' }),
},
(table) => [
uniqueIndex('webhookDeliveryAttempt_requestSequence_uidx').on(table.requestId, table.sequence),
uniqueIndex('webhookDeliveryAttempt_requestIdempotencyKey_uidx').on(table.requestId, table.idempotencyKey),
index('webhookDeliveryAttempt_requestId_idx').on(table.requestId),
index('webhookDeliveryAttempt_createdAt_idx').on(table.createdAt),
],
)
export const customDomain = sqliteTable(
'custom_domain',
{
id: text('id').primaryKey(),
hostname: text('hostname').notNull().unique(),
applicationId: text('application_id').references(() => application.id, { onDelete: 'cascade' }),
organizationId: text('organization_id').references(() => organization.id, { onDelete: 'cascade' }),
status: text('status').notNull().default('pending'),
verificationToken: text('verification_token').notNull().unique(),
cnameTarget: text('cname_target'),
tlsStatus: text('tls_status'),
verifiedAt: integer('verified_at', { mode: 'timestamp_ms' }),
createdAt: integer('created_at', { mode: 'timestamp_ms' })
.default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
.notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
.default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`)
.$onUpdate(() => new Date())
.notNull(),
},
(table) => [
index('customDomain_applicationId_idx').on(table.applicationId),
index('customDomain_organizationId_idx').on(table.organizationId),
index('customDomain_status_idx').on(table.status),
],
)
export const siteSettings = sqliteTable(
'site_settings',
{
key: text('key').primaryKey(),
value: text('value', { mode: 'json' }).$type<Record<string, unknown>>().notNull(),
revision: integer('revision').notNull().default(1),
updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),
},
(table) => [
check('site_settings_value_json', sql`json_valid(${table.value})`),
check('site_settings_revision_positive', sql`${table.revision} > 0`),
],
)