feat: platform

This commit is contained in:
Acbox
2026-01-12 00:45:32 +08:00
parent 6cd95bcaf7
commit 22aa5baaaa
14 changed files with 1011 additions and 2 deletions
+2
View File
@@ -2,6 +2,7 @@ import { Elysia } from 'elysia'
import { corsMiddleware, errorMiddleware } from './middlewares'
import { agentModule, authModule, modelModule, scheduleModule, settingsModule, userModule } from './modules'
import { memoryModule } from './modules/memory'
import { platformModule } from './modules/platform'
import openapi from '@elysiajs/openapi'
const port = process.env.API_SERVER_PORT || 7002
@@ -17,6 +18,7 @@ export const app = new Elysia()
.use(scheduleModule)
.use(settingsModule)
.use(userModule)
.use(platformModule)
.listen(port)
console.log(
+223
View File
@@ -0,0 +1,223 @@
import Elysia from 'elysia'
import { adminMiddleware, optionalAuthMiddleware } from '../../middlewares/auth'
import {
CreatePlatformModel,
UpdatePlatformModel,
GetPlatformByIdModel,
DeletePlatformModel,
UpdatePlatformConfigModel,
SetPlatformActiveModel,
} from './model'
import {
getPlatforms,
getPlatformById,
createPlatform,
updatePlatform,
deletePlatform,
updatePlatformConfig,
getActivePlatforms,
activePlatform,
setActivePlatform,
} from './service'
import { Platform } from '@memohome/shared'
export const platformModule = new Elysia({
prefix: '/platform',
})
// 公开的读取接口 - 用户可读
.use(optionalAuthMiddleware)
// Get all platforms
.onStart(async () => {
const platforms = await getActivePlatforms()
for (const platform of platforms) {
await activePlatform({
id: platform.id,
name: platform.name,
endpoint: platform.endpoint,
config: platform.config as Record<string, unknown>,
active: platform.active,
})
}
})
.get('/', async ({ query }) => {
try {
const page = parseInt(query.page as string) || 1
const limit = parseInt(query.limit as string) || 10
const sortOrder = (query.sortOrder as string) || 'desc'
const result = await getPlatforms({
page,
limit,
sortOrder: sortOrder as 'asc' | 'desc',
})
return {
success: true,
...result,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to fetch platforms',
}
}
})
// Get platform by ID
.get('/:id', async ({ params }) => {
try {
const { id } = params
const platform = await getPlatformById(id)
if (!platform) {
return {
success: false,
error: 'Platform not found',
}
}
return {
success: true,
data: platform,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to fetch platform',
}
}
}, GetPlatformByIdModel)
// 管理员权限的写入接口 - 管理员可读写
.guard(
{
beforeHandle: () => {
// This will be overridden by adminMiddleware
},
},
(app) =>
app
.use(adminMiddleware)
// Create new platform
.post('/', async ({ body }) => {
try {
const newPlatform = await createPlatform(body as Omit<Platform, 'id'>)
return {
success: true,
data: newPlatform,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to create platform',
}
}
}, CreatePlatformModel)
// Update platform
.put('/:id', async ({ params, body }) => {
try {
const { id } = params
const updatedPlatform = await updatePlatform(id, body as Partial<Omit<Platform, 'id'>>)
if (!updatedPlatform) {
return {
success: false,
error: 'Platform not found',
}
}
return {
success: true,
data: updatedPlatform,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to update platform',
}
}
}, UpdatePlatformModel)
// Update platform config
.put('/:id/config', async ({ params, body }) => {
try {
const { id } = params
const { config } = body as { config: Record<string, unknown> }
const updatedPlatform = await updatePlatformConfig(id, config)
if (!updatedPlatform) {
return {
success: false,
error: 'Platform not found',
}
}
return {
success: true,
data: updatedPlatform,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to update platform config',
}
}
}, UpdatePlatformConfigModel)
// Delete platform
.delete('/:id', async ({ params }) => {
try {
const { id } = params
const deletedPlatform = await deletePlatform(id)
if (!deletedPlatform) {
return {
success: false,
error: 'Platform not found',
}
}
return {
success: true,
data: deletedPlatform,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to delete platform',
}
}
}, DeletePlatformModel)
// Active platform
.post('/:id/active', async ({ params }) => {
try {
const { id } = params
const activatedPlatform = await setActivePlatform(id, true)
if (!activatedPlatform) {
return {
success: false,
error: 'Platform not found',
}
}
return {
success: true,
data: activatedPlatform,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to activate platform',
}
}
}, SetPlatformActiveModel)
// Inactive platform
.post('/:id/inactive', async ({ params }) => {
try {
const { id } = params
const inactivatedPlatform = await setActivePlatform(id, false)
if (!inactivatedPlatform) {
return {
success: false,
error: 'Platform not found',
}
}
return {
success: true,
data: inactivatedPlatform,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to inactivate platform',
}
}
}, SetPlatformActiveModel)
)
@@ -0,0 +1,49 @@
import { z } from 'zod'
const PlatformSchema = z.object({
name: z.string().min(1, 'Platform name is required'),
endpoint: z.string().min(1, 'Endpoint is required'),
config: z.record(z.string(), z.unknown()),
active: z.boolean().optional().default(true),
})
export type PlatformInput = z.infer<typeof PlatformSchema>
export const CreatePlatformModel = {
body: PlatformSchema,
}
export const UpdatePlatformModel = {
params: z.object({
id: z.string(),
}),
body: PlatformSchema,
}
export const GetPlatformByIdModel = {
params: z.object({
id: z.string(),
}),
}
export const DeletePlatformModel = {
params: z.object({
id: z.string(),
}),
}
export const UpdatePlatformConfigModel = {
params: z.object({
id: z.string(),
}),
body: z.object({
config: z.record(z.string(), z.unknown()),
}),
}
export const SetPlatformActiveModel = {
params: z.object({
id: z.string(),
}),
}
@@ -0,0 +1,203 @@
import { db } from '@memohome/db'
import { platform } from '@memohome/db/schema'
import { Platform } from '@memohome/shared'
import { eq, sql, desc, asc } from 'drizzle-orm'
import { calculateOffset, createPaginatedResult, type PaginatedResult } from '../../utils/pagination'
import path from 'node:path'
/**
* 平台列表返回类型
*/
type PlatformListItem = {
id: string
name: string
endpoint: string
config: Record<string, unknown>
active: boolean
createdAt: Date
updatedAt: Date
}
export const getPlatforms = async (params?: {
page?: number
limit?: number
sortOrder?: 'asc' | 'desc'
}): Promise<PaginatedResult<PlatformListItem>> => {
const page = params?.page || 1
const limit = params?.limit || 10
const sortOrder = params?.sortOrder || 'desc'
const offset = calculateOffset(page, limit)
// 获取总数
const [{ count }] = await db
.select({ count: sql<number>`count(*)` })
.from(platform)
// 获取分页数据
const orderFn = sortOrder === 'desc' ? desc : asc
const platforms = await db
.select()
.from(platform)
.orderBy(orderFn(platform.createdAt))
.limit(limit)
.offset(offset)
// Cast config to Record<string, unknown> for type safety
const typedPlatforms = platforms.map(p => ({
...p,
config: p.config as Record<string, unknown>,
}))
return createPaginatedResult(typedPlatforms, Number(count), page, limit)
}
export const getPlatformById = async (id: string) => {
const [result] = await db.select().from(platform).where(eq(platform.id, id))
return result
}
export const getPlatformByName = async (name: string) => {
const [result] = await db.select().from(platform).where(eq(platform.name, name))
return result
}
export const getActivePlatforms = async () => {
return await db.select()
.from(platform)
.where(eq(platform.active, true))
}
export const createPlatform = async (data: Omit<Platform, 'id'>) => {
const [newPlatform] = await db
.insert(platform)
.values({
name: data.name,
endpoint: data.endpoint,
config: data.config,
active: data.active ?? true,
})
.returning()
if (data.active ?? true) {
await activePlatform({
id: newPlatform.id,
name: newPlatform.name,
endpoint: newPlatform.endpoint,
config: newPlatform.config as Record<string, unknown>,
active: newPlatform.active,
})
}
return newPlatform
}
export const updatePlatform = async (id: string, data: Partial<Omit<Platform, 'id'>>) => {
const updateData: {
name?: string
endpoint?: string
config?: Record<string, unknown>
active?: boolean
updatedAt: Date
} = {
updatedAt: new Date(),
}
if (data.name !== undefined) updateData.name = data.name
if (data.endpoint !== undefined) updateData.endpoint = data.endpoint
if (data.config !== undefined) updateData.config = data.config
if (data.active !== undefined) updateData.active = data.active
const [updatedPlatform] = await db
.update(platform)
.set(updateData)
.where(eq(platform.id, id))
.returning()
return updatedPlatform
}
export const deletePlatform = async (id: string) => {
const [deletedPlatform] = await db
.delete(platform)
.where(eq(platform.id, id))
.returning()
return deletedPlatform
}
export const updatePlatformConfig = async (id: string, config: Record<string, unknown>) => {
const [updatedPlatform] = await db
.update(platform)
.set({
config,
updatedAt: new Date(),
})
.where(eq(platform.id, id))
.returning()
return updatedPlatform
}
// active
export const activePlatform = async (platform: Platform) => {
if (platform.active) {
return
}
await fetch(path.join(platform.endpoint, '/start'), {
method: 'POST',
body: JSON.stringify(platform.config),
headers: {
'Content-Type': 'application/json',
},
})
}
export const inactivePlatform = async (platform: Platform) => {
if (!platform.active) {
return
}
await fetch(path.join(platform.endpoint, '/stop'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
}
export const setActivePlatform = async (id: string, active: boolean) => {
const currentPlatform = await getPlatformById(id)
if (!currentPlatform) {
throw new Error('Platform not found')
}
const platformData: Platform = {
id: currentPlatform.id,
name: currentPlatform.name,
endpoint: currentPlatform.endpoint,
config: currentPlatform.config as Record<string, unknown>,
active: active,
}
if (active) {
await activePlatform(platformData)
} else {
await inactivePlatform(platformData)
}
const [updatedPlatform] = await db
.update(platform)
.set({ active })
.where(eq(platform.id, id))
.returning()
return updatedPlatform
}
export const sendMessageToPlatform = async (name: string, options: {
message: string
userId: string
}) => {
const currentPlatform = await getPlatformByName(name)
if (!currentPlatform) {
throw new Error('Platform not found')
}
await fetch(path.join(currentPlatform.endpoint, '/send'), {
method: 'POST',
body: JSON.stringify(options),
headers: {
'Content-Type': 'application/json',
},
})
}
+294
View File
@@ -0,0 +1,294 @@
import type { Command } from 'commander'
import chalk from 'chalk'
import inquirer from 'inquirer'
import ora from 'ora'
import { table } from 'table'
import * as platformCore from '../../core/platform'
import { formatError } from '../../utils'
import { getApiUrl } from '../../core/client'
export function platformCommands(program: Command) {
program
.command('list')
.description('List all platform configurations')
.action(async () => {
const spinner = ora('Fetching platform list...').start()
try {
const platforms = await platformCore.listPlatforms()
spinner.succeed(chalk.green('Platform List'))
if (platforms.length === 0) {
console.log(chalk.yellow('No platform configurations found'))
return
}
const tableData = [
['ID', 'Name', 'Endpoint', 'Active', 'Created'],
...platforms.map((item) => [
item.id.substring(0, 8) + '...',
item.name,
item.endpoint,
item.active ? chalk.green('✓ Active') : chalk.dim('✗ Inactive'),
new Date(item.createdAt).toLocaleDateString(),
]),
]
console.log(table(tableData))
} catch (error) {
spinner.fail(chalk.red('Operation failed'))
if (error instanceof Error) {
if (error.name === 'AbortError' || error.name === 'TimeoutError') {
console.error(chalk.red('Connection timeout, please check:'))
console.error(chalk.yellow(' 1. Is the API server running?'))
console.error(chalk.yellow(' 2. Is the API URL correct?'))
console.error(chalk.dim(` Current config: ${getApiUrl()}`))
} else {
console.error(chalk.red('Error:'), error.message)
}
} else {
console.error(chalk.red('Error:'), String(error))
}
process.exit(1)
}
})
program
.command('create')
.description('Create platform configuration')
.option('-n, --name <name>', 'Platform name')
.option('-e, --endpoint <endpoint>', 'Platform endpoint URL')
.option('-c, --config <config>', 'Platform config (JSON string)')
.option('-a, --active', 'Set platform as active', true)
.action(async (options) => {
try {
let { name, endpoint, config, active } = options
if (!name || !endpoint) {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Platform name:',
when: !name,
validate: (value: string) => {
if (value.trim()) return true
return 'Platform name is required'
},
},
{
type: 'input',
name: 'endpoint',
message: 'Platform endpoint URL:',
when: !endpoint,
validate: (value: string) => {
if (value.trim()) return true
return 'Endpoint is required'
},
},
{
type: 'input',
name: 'config',
message: 'Platform config (JSON string):',
default: '{}',
when: !config,
},
{
type: 'confirm',
name: 'active',
message: 'Set as active?',
default: true,
when: active === undefined,
},
])
name = name || answers.name
endpoint = endpoint || answers.endpoint
config = config || answers.config
active = active ?? answers.active
}
// Parse config JSON
let configObj: Record<string, unknown> = {}
if (config) {
try {
configObj = JSON.parse(config)
} catch {
console.error(chalk.red('Invalid JSON config'))
process.exit(1)
}
}
const spinner = ora('Creating platform configuration...').start()
const platform = await platformCore.createPlatform({
name,
endpoint,
config: configObj,
active,
})
spinner.succeed(chalk.green('Platform configuration created successfully'))
console.log(chalk.blue(`Name: ${platform.name}`))
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
console.log(chalk.blue(`ID: ${platform.id}`))
} catch (error) {
console.error(chalk.red(formatError(error)))
process.exit(1)
}
})
program
.command('get <id>')
.description('Get platform configuration details')
.action(async (id) => {
const spinner = ora('Fetching platform configuration...').start()
try {
const platform = await platformCore.getPlatform(id)
spinner.succeed(chalk.green('Platform Configuration'))
console.log(chalk.blue(`ID: ${platform.id}`))
console.log(chalk.blue(`Name: ${platform.name}`))
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
console.log(chalk.blue(`Config: ${JSON.stringify(platform.config, null, 2)}`))
console.log(chalk.blue(`Created At: ${new Date(platform.createdAt).toLocaleString('en-US')}`))
console.log(chalk.blue(`Updated At: ${new Date(platform.updatedAt).toLocaleString('en-US')}`))
} catch (error) {
spinner.fail(chalk.red('Operation failed'))
console.error(chalk.red(formatError(error)))
process.exit(1)
}
})
program
.command('update <id>')
.description('Update platform configuration')
.option('-n, --name <name>', 'Platform name')
.option('-e, --endpoint <endpoint>', 'Platform endpoint URL')
.option('-c, --config <config>', 'Platform config (JSON string)')
.option('-a, --active <active>', 'Set active status (true/false)')
.action(async (id, options) => {
try {
const updates: Record<string, unknown> = {}
if (options.name) updates.name = options.name
if (options.endpoint) updates.endpoint = options.endpoint
if (options.config) {
try {
updates.config = JSON.parse(options.config)
} catch {
console.error(chalk.red('Invalid JSON config'))
process.exit(1)
}
}
if (options.active !== undefined) {
updates.active = options.active === 'true'
}
if (Object.keys(updates).length === 0) {
console.log(chalk.yellow('No updates specified'))
return
}
const spinner = ora('Updating platform configuration...').start()
const platform = await platformCore.updatePlatform(id, updates as any)
spinner.succeed(chalk.green('Platform configuration updated successfully'))
console.log(chalk.blue(`Name: ${platform.name}`))
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
} catch (error) {
console.error(chalk.red(formatError(error)))
process.exit(1)
}
})
program
.command('update-config <id>')
.description('Update platform config only')
.requiredOption('-c, --config <config>', 'Platform config (JSON string)')
.action(async (id, options) => {
try {
let configObj: Record<string, unknown>
try {
configObj = JSON.parse(options.config)
} catch {
console.error(chalk.red('Invalid JSON config'))
process.exit(1)
}
const spinner = ora('Updating platform config...').start()
const platform = await platformCore.updatePlatformConfig(id, configObj)
spinner.succeed(chalk.green('Platform config updated successfully'))
console.log(chalk.blue(`Name: ${platform.name}`))
console.log(chalk.blue(`Config: ${JSON.stringify(platform.config, null, 2)}`))
} catch (error) {
console.error(chalk.red(formatError(error)))
process.exit(1)
}
})
program
.command('delete <id>')
.description('Delete platform configuration')
.action(async (id) => {
try {
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: chalk.yellow(`Are you sure you want to delete platform configuration ${id}?`),
default: false,
},
])
if (!confirm) {
console.log(chalk.yellow('Cancelled'))
return
}
const spinner = ora('Deleting platform configuration...').start()
await platformCore.deletePlatform(id)
spinner.succeed(chalk.green('Platform configuration deleted'))
} catch (error) {
console.error(chalk.red(formatError(error)))
process.exit(1)
}
})
program
.command('activate <id>')
.description('Activate platform (admin only)')
.action(async (id) => {
const spinner = ora('Activating platform...').start()
try {
const platform = await platformCore.activatePlatform(id)
spinner.succeed(chalk.green('Platform activated successfully'))
console.log(chalk.blue(`Name: ${platform.name}`))
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
console.log(chalk.blue(`Active: ${platform.active ? chalk.green('Yes') : 'No'}`))
} catch (error) {
spinner.fail(chalk.red('Operation failed'))
console.error(chalk.red(formatError(error)))
process.exit(1)
}
})
program
.command('deactivate <id>')
.description('Deactivate platform (admin only)')
.action(async (id) => {
const spinner = ora('Deactivating platform...').start()
try {
const platform = await platformCore.inactivatePlatform(id)
spinner.succeed(chalk.green('Platform deactivated successfully'))
console.log(chalk.blue(`Name: ${platform.name}`))
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : chalk.dim('No')}`))
} catch (error) {
spinner.fail(chalk.red('Operation failed'))
console.error(chalk.red(formatError(error)))
process.exit(1)
}
})
}
+5
View File
@@ -5,6 +5,7 @@ import chalk from 'chalk'
import { authCommands } from './commands/auth'
import { userCommands } from './commands/user'
import { modelCommands } from './commands/model'
import { platformCommands } from './commands/platform'
import { agentCommands, startInteractiveMode } from './commands/agent'
import { memoryCommands } from './commands/memory'
import { configCommands } from './commands/config'
@@ -30,6 +31,10 @@ userCommands(user)
const model = program.command('model').description('AI model configuration management')
modelCommands(model)
// Platform management commands
const platform = program.command('platform').description('Platform configuration management')
platformCommands(platform)
// Agent conversation commands
const agent = program.command('agent').description('Chat with AI Agent')
agentCommands(agent)
+14
View File
@@ -54,6 +54,20 @@ export {
type ModelListItem,
} from './model'
// Platform
export {
listPlatforms,
createPlatform,
getPlatform,
updatePlatform,
updatePlatformConfig,
deletePlatform,
activatePlatform,
inactivatePlatform,
type CreatePlatformParams,
type PlatformListItem,
} from './platform'
// Agent
export {
chat,
+188
View File
@@ -0,0 +1,188 @@
import { createClient, requireAuth } from './client'
import type { Platform, ApiResponse } from '../types'
export interface CreatePlatformParams {
name: string
endpoint: string
config: Record<string, unknown>
active?: boolean
}
export interface PlatformListItem {
id: string
name: string
endpoint: string
config: Record<string, unknown>
active: boolean
createdAt: string
updatedAt: string
}
/**
* List all platforms
*/
export async function listPlatforms(): Promise<PlatformListItem[]> {
requireAuth()
const client = createClient()
const response = await client.platform.get()
if (response.error) {
throw new Error(response.error.value)
}
const data = response.data as { success?: boolean; items?: PlatformListItem[] } | null
if (data?.success && data?.items) {
return data.items
}
throw new Error('Failed to fetch platform list')
}
/**
* Create platform configuration
*/
export async function createPlatform(params: CreatePlatformParams): Promise<Platform> {
requireAuth()
const client = createClient()
const payload: Record<string, unknown> = {
name: params.name,
endpoint: params.endpoint,
config: params.config,
active: params.active ?? true,
}
const response = await client.platform.post(payload)
if (response.error) {
throw new Error(response.error.value)
}
const data = response.data as ApiResponse<Platform> | null
if (data?.success && data?.data) {
return data.data
}
throw new Error('Failed to create platform configuration')
}
/**
* Get platform by ID
*/
export async function getPlatform(id: string): Promise<Platform> {
requireAuth()
const client = createClient()
const response = await client.platform({ id }).get()
if (response.error) {
throw new Error(response.error.value)
}
const data = response.data as ApiResponse<Platform> | null
if (data?.success && data?.data) {
return data.data
}
throw new Error('Failed to fetch platform configuration')
}
/**
* Update platform
*/
export async function updatePlatform(id: string, params: Partial<CreatePlatformParams>): Promise<Platform> {
requireAuth()
const client = createClient()
const response = await client.platform({ id }).put(params)
if (response.error) {
throw new Error(response.error.value)
}
const data = response.data as ApiResponse<Platform> | null
if (data?.success && data?.data) {
return data.data
}
throw new Error('Failed to update platform configuration')
}
/**
* Update platform config
*/
export async function updatePlatformConfig(id: string, config: Record<string, unknown>): Promise<Platform> {
requireAuth()
const client = createClient()
const response = await client.platform({ id }).config.put({ config })
if (response.error) {
throw new Error(response.error.value)
}
const data = response.data as ApiResponse<Platform> | null
if (data?.success && data?.data) {
return data.data
}
throw new Error('Failed to update platform config')
}
/**
* Delete platform
*/
export async function deletePlatform(id: string): Promise<void> {
requireAuth()
const client = createClient()
const response = await client.platform({ id }).delete()
if (response.error) {
throw new Error(response.error.value)
}
}
/**
* Activate platform
*/
export async function activatePlatform(id: string): Promise<Platform> {
requireAuth()
const client = createClient()
const response = await client.platform({ id }).active.post()
if (response.error) {
throw new Error(response.error.value)
}
const data = response.data as ApiResponse<Platform> | null
if (data?.success && data?.data) {
return data.data
}
throw new Error('Failed to activate platform')
}
/**
* Inactivate platform
*/
export async function inactivatePlatform(id: string): Promise<Platform> {
requireAuth()
const client = createClient()
const response = await client.platform({ id }).inactive.post()
if (response.error) {
throw new Error(response.error.value)
}
const data = response.data as ApiResponse<Platform> | null
if (data?.success && data?.data) {
return data.data
}
throw new Error('Failed to inactivate platform')
}
+10
View File
@@ -69,3 +69,13 @@ export interface Schedule {
updatedAt: string
}
export interface Platform {
id: string
name: string
endpoint: string
config: Record<string, unknown>
active: boolean
createdAt: string
updatedAt: string
}
+11
View File
@@ -0,0 +1,11 @@
import { boolean, jsonb, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'
export const platform = pgTable('platform', {
id: uuid('id').primaryKey().defaultRandom(),
name: text('name').notNull(),
endpoint: text('endpoint').notNull(),
config: jsonb('config').notNull(),
active: boolean('active').notNull().default(true),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
})
+2 -1
View File
@@ -2,4 +2,5 @@ export * from './history'
export * from './model'
export * from './settings'
export * from './schedule'
export * from './users'
export * from './users'
export * from './platform'
+1
View File
@@ -18,6 +18,7 @@ export class TelegramPlatform extends BasePlatform {
config = z.object({
botToken: z.string(),
})
port = 7101
private bot?: Telegraf
redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379')
+2 -1
View File
@@ -1,2 +1,3 @@
export * from './model'
export * from './schedule'
export * from './schedule'
export * from './platform'
+7
View File
@@ -0,0 +1,7 @@
export interface Platform {
id: string
name: string
endpoint: string
config: Record<string, unknown>
active: boolean
}