diff --git a/src/app.ts b/src/app.ts index 79cab56..cf40ab8 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,11 +6,13 @@ import { useContextKey } from '@kevisual/context'; import { SimpleRouter } from '@kevisual/router/simple'; import { OssBase } from '@kevisual/oss/services'; import { BailianProvider } from '@kevisual/ai'; - +import * as schema from './db/schema.ts'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import { config } from './modules/config.ts' export const router = useContextKey('router', () => new SimpleRouter()); export const runtime = useContextKey('runtime', () => { return { - env: process.env.NODE_ENV || 'development', + env: config.NODE_ENV || 'development', type: 'server', }; }); @@ -27,7 +29,10 @@ export const redis = useContextKey('redis', () => redisLib.redis); export const subscriber = useContextKey('subscriber', () => redisLib.subscriber); export const minioClient = useContextKey('minioClient', () => minioLib.minioClient); export const sequelize = useContextKey('sequelize', () => sequelizeLib.sequelize); - +export const db = useContextKey('db', () => { + const db = drizzle(config.DATABASE_URL || ''); + return db; +}) const init = () => { return new App({ serverOptions: { @@ -42,7 +47,9 @@ export const app = useContextKey('app', init); export const ai = useContextKey('ai', () => { return new BailianProvider({ - apiKey: process.env.BAILIAN_API_KEY || '', + apiKey: config.BAILIAN_API_KEY || '', model: 'qwen-plus', }); -}); \ No newline at end of file +}); + +export { schema }; \ No newline at end of file diff --git a/src/db/drizzle/0001_solid_nocturne.sql b/src/db/drizzle/0001_solid_nocturne.sql new file mode 100644 index 0000000..17cfad2 --- /dev/null +++ b/src/db/drizzle/0001_solid_nocturne.sql @@ -0,0 +1,42 @@ +CREATE TABLE "cf_prompts" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "uid" uuid, + "parents" jsonb DEFAULT '[]'::jsonb NOT NULL, + "data" jsonb DEFAULT '{}'::jsonb NOT NULL, + "title" text DEFAULT '', + "description" text DEFAULT '', + "summary" text DEFAULT '', + "tags" jsonb DEFAULT '[]'::jsonb NOT NULL, + "link" text DEFAULT '', + "createdAt" timestamp DEFAULT now() NOT NULL, + "updatedAt" timestamp DEFAULT now() NOT NULL, + "deletedAt" timestamp +); +--> statement-breakpoint +DROP TABLE "TestPromptTools" CASCADE;--> statement-breakpoint +DROP TABLE "ai_agent" CASCADE;--> statement-breakpoint +DROP TABLE "apps_trades" CASCADE;--> statement-breakpoint +DROP TABLE "cf_orgs" CASCADE;--> statement-breakpoint +DROP TABLE "cf_router_code" CASCADE;--> statement-breakpoint +DROP TABLE "cf_user" CASCADE;--> statement-breakpoint +DROP TABLE "cf_user_secrets" CASCADE;--> statement-breakpoint +DROP TABLE "chat_histories" CASCADE;--> statement-breakpoint +DROP TABLE "chat_prompts" CASCADE;--> statement-breakpoint +DROP TABLE "chat_sessions" CASCADE;--> statement-breakpoint +DROP TABLE "file_sync" CASCADE;--> statement-breakpoint +DROP TABLE "kv_ai_chat_history" CASCADE;--> statement-breakpoint +DROP TABLE "kv_app" CASCADE;--> statement-breakpoint +DROP TABLE "kv_app_domain" CASCADE;--> statement-breakpoint +DROP TABLE "kv_app_list" CASCADE;--> statement-breakpoint +DROP TABLE "kv_config" CASCADE;--> statement-breakpoint +DROP TABLE "kv_container" CASCADE;--> statement-breakpoint +DROP TABLE "kv_github" CASCADE;--> statement-breakpoint +DROP TABLE "kv_packages" CASCADE;--> statement-breakpoint +DROP TABLE "kv_page" CASCADE;--> statement-breakpoint +DROP TABLE "kv_resource" CASCADE;--> statement-breakpoint +DROP TABLE "kv_vip" CASCADE;--> statement-breakpoint +DROP TABLE "micro_apps_upload" CASCADE;--> statement-breakpoint +DROP TABLE "micro_mark" CASCADE;--> statement-breakpoint +DROP TABLE "prompts" CASCADE;--> statement-breakpoint +DROP TABLE "work_share_mark" CASCADE;--> statement-breakpoint +DROP TYPE "public"."enum_cf_router_code_type"; \ No newline at end of file diff --git a/src/db/drizzle/meta/0001_snapshot.json b/src/db/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..0fbf9bb --- /dev/null +++ b/src/db/drizzle/meta/0001_snapshot.json @@ -0,0 +1,114 @@ +{ + "id": "f87c2440-e0ce-4caa-ab13-560d9aac9e8e", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.cf_prompts": { + "name": "cf_prompts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "uid": { + "name": "uid", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "parents": { + "name": "parents", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "tags": { + "name": "tags", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/db/drizzle/meta/_journal.json b/src/db/drizzle/meta/_journal.json index 8ce0645..78d3e96 100644 --- a/src/db/drizzle/meta/_journal.json +++ b/src/db/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1766803308366, "tag": "0000_groovy_red_skull", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1767070768620, + "tag": "0001_solid_nocturne", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/db/drizzle/schema.ts b/src/db/drizzle/schema.ts index 169c9b9..1912d32 100644 --- a/src/db/drizzle/schema.ts +++ b/src/db/drizzle/schema.ts @@ -68,13 +68,13 @@ export const cfRouterCode = pgTable("cf_router_code", { key: varchar({ length: 255 }).notNull(), active: boolean().default(false), project: varchar({ length: 255 }).default('default'), - code: text().default('), + code: text().default(''), type: enumCfRouterCodeType().default('route'), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), middleware: varchar({ length: 255 }).array().default(["RRAY[]::character varying[])::character varying(25"]), - next: varchar({ length: 255 }).default('), - exec: text().default('), + next: varchar({ length: 255 }).default(''), + exec: text().default(''), data: json().default({}), validator: json().default({}), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), @@ -107,7 +107,7 @@ export const cfUserSecrets = pgTable("cf_user_secrets", { status: varchar({ length: 255 }).default('active'), title: text(), expiredTime: timestamp({ withTimezone: true, mode: 'string' }), - token: varchar({ length: 255 }).default(').notNull(), + token: varchar({ length: 255 }).default('').notNull(), userId: uuid(), data: jsonb().default({}), orgId: uuid(), @@ -133,7 +133,7 @@ export const chatPrompts = pgTable("chat_prompts", { title: varchar({ length: 255 }).notNull(), description: text(), data: json(), - key: varchar({ length: 255 }).default(').notNull(), + key: varchar({ length: 255 }).default('').notNull(), uid: varchar({ length: 255 }), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), @@ -148,7 +148,7 @@ export const chatSessions = pgTable("chat_sessions", { uid: varchar({ length: 255 }), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), - title: varchar({ length: 255 }).default('), + title: varchar({ length: 255 }).default(''), key: varchar({ length: 255 }), }); @@ -167,10 +167,10 @@ export const fileSync = pgTable("file_sync", { export const kvAiChatHistory = pgTable("kv_ai_chat_history", { id: uuid().primaryKey().notNull(), - username: varchar({ length: 255 }).default(').notNull(), - model: varchar({ length: 255 }).default(').notNull(), - group: varchar({ length: 255 }).default(').notNull(), - title: varchar({ length: 255 }).default(').notNull(), + username: varchar({ length: 255 }).default('').notNull(), + model: varchar({ length: 255 }).default('').notNull(), + group: varchar({ length: 255 }).default('').notNull(), + title: varchar({ length: 255 }).default('').notNull(), messages: jsonb().default([]).notNull(), promptTokens: integer("prompt_tokens").default(0), totalTokens: integer("total_tokens").default(0), @@ -186,14 +186,14 @@ export const kvAiChatHistory = pgTable("kv_ai_chat_history", { export const kvApp = pgTable("kv_app", { id: uuid().primaryKey().notNull(), data: jsonb().default({}), - version: varchar({ length: 255 }).default('), + version: varchar({ length: 255 }).default(''), key: varchar({ length: 255 }), uid: uuid(), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), - title: varchar({ length: 255 }).default('), - description: varchar({ length: 255 }).default('), + title: varchar({ length: 255 }).default(''), + description: varchar({ length: 255 }).default(''), user: varchar({ length: 255 }), status: varchar({ length: 255 }).default('running'), pid: uuid(), @@ -220,7 +220,7 @@ export const kvAppDomain = pgTable("kv_app_domain", { export const kvAppList = pgTable("kv_app_list", { id: uuid().primaryKey().notNull(), data: json().default({}), - version: varchar({ length: 255 }).default('), + version: varchar({ length: 255 }).default(''), uid: uuid(), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), @@ -231,24 +231,24 @@ export const kvAppList = pgTable("kv_app_list", { export const kvConfig = pgTable("kv_config", { id: uuid().primaryKey().notNull(), - title: text().default('), - key: text().default('), - description: text().default('), + title: text().default(''), + key: text().default(''), + description: text().default(''), tags: jsonb().default([]), data: jsonb().default({}), uid: uuid(), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), - hash: text().default('), + hash: text().default(''), }); export const kvContainer = pgTable("kv_container", { id: uuid().primaryKey().notNull(), - title: text().default('), - description: text().default('), + title: text().default(''), + description: text().default(''), type: varchar({ length: 255 }).default('render-js'), - code: text().default('), + code: text().default(''), data: json().default({}), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), @@ -256,13 +256,13 @@ export const kvContainer = pgTable("kv_container", { publish: json().default({}), tags: json().default([]), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), - hash: text().default('), + hash: text().default(''), }); export const kvGithub = pgTable("kv_github", { id: uuid().primaryKey().notNull(), - title: varchar({ length: 255 }).default('), - githubToken: varchar({ length: 255 }).default('), + title: varchar({ length: 255 }).default(''), + githubToken: varchar({ length: 255 }).default(''), uid: uuid(), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), @@ -271,8 +271,8 @@ export const kvGithub = pgTable("kv_github", { export const kvPackages = pgTable("kv_packages", { id: uuid().primaryKey().notNull(), - title: text().default('), - description: text().default('), + title: text().default(''), + description: text().default(''), tags: jsonb().default([]), data: jsonb().default({}), publish: jsonb().default({}), @@ -285,9 +285,9 @@ export const kvPackages = pgTable("kv_packages", { export const kvPage = pgTable("kv_page", { id: uuid().primaryKey().notNull(), - title: varchar({ length: 255 }).default('), - description: text().default('), - type: varchar({ length: 255 }).default('), + title: varchar({ length: 255 }).default(''), + description: text().default(''), + type: varchar({ length: 255 }).default(''), data: json().default({}), uid: uuid(), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), @@ -298,10 +298,10 @@ export const kvPage = pgTable("kv_page", { export const kvResource = pgTable("kv_resource", { id: uuid().primaryKey().notNull(), - name: varchar({ length: 255 }).default('), - description: text().default('), - source: varchar({ length: 255 }).default('), - sourceId: varchar({ length: 255 }).default('), + name: varchar({ length: 255 }).default(''), + description: text().default(''), + source: varchar({ length: 255 }).default(''), + sourceId: varchar({ length: 255 }).default(''), version: varchar({ length: 255 }).default('0.0.0'), data: json().default({}), uid: uuid(), @@ -321,20 +321,20 @@ export const kvVip = pgTable("kv_vip", { createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), - title: text().default(').notNull(), - description: text().default(').notNull(), + title: text().default('').notNull(), + description: text().default('').notNull(), }); export const microAppsUpload = pgTable("micro_apps_upload", { id: uuid().primaryKey().notNull(), - title: varchar({ length: 255 }).default('), - description: varchar({ length: 255 }).default('), + title: varchar({ length: 255 }).default(''), + description: varchar({ length: 255 }).default(''), tags: jsonb().default([]), - type: varchar({ length: 255 }).default('), - source: varchar({ length: 255 }).default('), + type: varchar({ length: 255 }).default(''), + source: varchar({ length: 255 }).default(''), data: jsonb().default({}), share: boolean().default(false), - uname: varchar({ length: 255 }).default('), + uname: varchar({ length: 255 }).default(''), uid: uuid(), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), @@ -342,54 +342,41 @@ export const microAppsUpload = pgTable("micro_apps_upload", { export const microMark = pgTable("micro_mark", { id: uuid().primaryKey().notNull(), - title: text().default('), - description: text().default('), + title: text().default(''), + description: text().default(''), tags: jsonb().default([]), data: jsonb().default({}), - uname: varchar({ length: 255 }).default('), + uname: varchar({ length: 255 }).default(''), uid: uuid(), createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), - cover: text().default('), - thumbnail: text().default('), - link: text().default('), - summary: text().default('), + cover: text().default(''), + thumbnail: text().default(''), + link: text().default(''), + summary: text().default(''), markType: text().default('md'), config: jsonb().default({}), puid: uuid(), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), version: integer().default(1), fileList: jsonb().default([]), - key: text().default('), + key: text().default(''), }); -export const prompts = pgTable("prompts", { - id: uuid().primaryKey().notNull(), - title: varchar({ length: 255 }).notNull(), - description: text(), - presetData: json(), - key: varchar({ length: 255 }).notNull(), - createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), - updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), - deletedAt: timestamp({ withTimezone: true, mode: 'string' }), -}, (table) => [ - unique("prompts_key_key").on(table.key), -]); - export const workShareMark = pgTable("work_share_mark", { id: uuid().primaryKey().notNull(), - title: text().default('), - key: text().default('), + title: text().default(''), + key: text().default(''), markType: text().default('md'), - description: text().default('), - cover: text().default('), - link: text().default('), + description: text().default(''), + cover: text().default(''), + link: text().default(''), tags: jsonb().default([]), - summary: text().default('), + summary: text().default(''), config: jsonb().default({}), data: jsonb().default({}), fileList: jsonb().default([]), - uname: varchar({ length: 255 }).default('), + uname: varchar({ length: 255 }).default(''), version: integer().default(1), markedAt: timestamp({ withTimezone: true, mode: 'string' }), uid: uuid(), @@ -398,3 +385,21 @@ export const workShareMark = pgTable("work_share_mark", { updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(), deletedAt: timestamp({ withTimezone: true, mode: 'string' }), }); + + +export const prompts = pgTable('cf_prompts', { + id: uuid('id').primaryKey().defaultRandom(), + uid: uuid('uid'), + parents: jsonb('parents').notNull().default([]), + data: jsonb('data').notNull().default({}), + + title: text('title').default(''), + description: text('description').default(''), + summary: text('summary').default(''), + tags: jsonb('tags').notNull().default([]), + link: text('link').default(''), + + createdAt: timestamp('createdAt').notNull().defaultNow(), + updatedAt: timestamp('updatedAt').notNull().defaultNow(), + deletedAt: timestamp('deletedAt'), +}); \ No newline at end of file diff --git a/src/db/schema.ts b/src/db/schema.ts index 93c261b..1e41f9e 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -1,14 +1,3 @@ -import { pgTable, serial, text, varchar, uuid, boolean, jsonb, timestamp } from "drizzle-orm/pg-core"; -import { InferSelectModel, InferInsertModel } from "drizzle-orm"; - -export const aiUsages = pgTable('cf_ai_usage_cache', { - id: uuid('id').primaryKey().defaultRandom(), - owner: uuid('owner'), - data: jsonb('data').notNull().default({}), - createdAt: timestamp('createdAt').notNull().defaultNow(), - updatedAt: timestamp('updatedAt').notNull().defaultNow(), - deletedAt: timestamp('deletedAt'), -}); - -// 类型推断 -export type AiUsage = InferSelectModel; \ No newline at end of file +import { pgTable, uuid, jsonb, timestamp, text } from "drizzle-orm/pg-core"; +import { InferSelectModel, InferInsertModel, desc } from "drizzle-orm"; +export * from './drizzle/schema.ts'; \ No newline at end of file diff --git a/src/models/user.ts b/src/models/user.ts index 4e6cbd2..e64e49c 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -13,7 +13,6 @@ const init = async () => { await UserSecretInit(null, null).catch((e) => { console.error('UserSecret sync', e); }); - console.log('Models synced'); useContextKey('models-synced', true); }; init(); diff --git a/src/routes/container/index.ts b/src/old-apps/container/index.ts similarity index 100% rename from src/routes/container/index.ts rename to src/old-apps/container/index.ts diff --git a/src/routes/container/list.ts b/src/old-apps/container/list.ts similarity index 100% rename from src/routes/container/list.ts rename to src/old-apps/container/list.ts diff --git a/src/routes/container/models/index.ts b/src/old-apps/container/models/index.ts similarity index 100% rename from src/routes/container/models/index.ts rename to src/old-apps/container/models/index.ts diff --git a/src/routes/container/module/get-container-file.ts b/src/old-apps/container/module/get-container-file.ts similarity index 100% rename from src/routes/container/module/get-container-file.ts rename to src/old-apps/container/module/get-container-file.ts diff --git a/src/routes/container/type.ts b/src/old-apps/container/type.ts similarity index 100% rename from src/routes/container/type.ts rename to src/old-apps/container/type.ts diff --git a/src/routes/page/index.ts b/src/old-apps/page/index.ts similarity index 100% rename from src/routes/page/index.ts rename to src/old-apps/page/index.ts diff --git a/src/routes/page/list.ts b/src/old-apps/page/list.ts similarity index 98% rename from src/routes/page/list.ts rename to src/old-apps/page/list.ts index e492c5d..212ed69 100644 --- a/src/routes/page/list.ts +++ b/src/old-apps/page/list.ts @@ -142,14 +142,6 @@ app path: 'page', key: 'delete', }) - .define({ - validator: { - id: { - required: true, - type: 'string', - }, - }, - }) .define(async (ctx) => { const id = ctx.query.id; const page = await PageModel.findByPk(id); diff --git a/src/routes/page/models/index.ts b/src/old-apps/page/models/index.ts similarity index 100% rename from src/routes/page/models/index.ts rename to src/old-apps/page/models/index.ts diff --git a/src/routes/page/module/cache-file.ts b/src/old-apps/page/module/cache-file.ts similarity index 98% rename from src/routes/page/module/cache-file.ts rename to src/old-apps/page/module/cache-file.ts index b42d129..63bfa7f 100644 --- a/src/routes/page/module/cache-file.ts +++ b/src/old-apps/page/module/cache-file.ts @@ -1,6 +1,6 @@ import { useFileStore } from '@kevisual/use-config/file-store'; import { PageModel } from '../models/index.ts'; -import { ContainerModel } from '@/routes/container/models/index.ts'; +import { ContainerModel } from '@/old-apps/container/models/index.ts'; import { Op } from 'sequelize'; import { getContainerData } from './get-container.ts'; import path from 'node:path'; diff --git a/src/routes/page/module/file-template.ts b/src/old-apps/page/module/file-template.ts similarity index 100% rename from src/routes/page/module/file-template.ts rename to src/old-apps/page/module/file-template.ts diff --git a/src/routes/page/module/get-container.ts b/src/old-apps/page/module/get-container.ts similarity index 100% rename from src/routes/page/module/get-container.ts rename to src/old-apps/page/module/get-container.ts diff --git a/src/routes/page/publish.ts b/src/old-apps/page/publish.ts similarity index 97% rename from src/routes/page/publish.ts rename to src/old-apps/page/publish.ts index 76a2cf0..8466909 100644 --- a/src/routes/page/publish.ts +++ b/src/old-apps/page/publish.ts @@ -1,7 +1,7 @@ import { CustomError } from '@kevisual/router'; import { app } from '../../app.ts'; import { PageModel } from './models/index.ts'; -import { AppListModel, AppModel } from '../app-manager/index.ts'; +import { AppListModel, AppModel } from '../../routes/app-manager/index.ts'; import { cachePage, getZip } from './module/cache-file.ts'; import { uniqBy } from 'lodash-es'; import semver from 'semver'; diff --git a/src/routes-simple/handle-request.ts b/src/routes-simple/handle-request.ts index a3f8830..8fde9a7 100644 --- a/src/routes-simple/handle-request.ts +++ b/src/routes-simple/handle-request.ts @@ -7,7 +7,7 @@ import { app, minioClient } from '@/app.ts'; import { bucketName } from '@/modules/minio.ts'; import { getContentType } from '@/utils/get-content-type.ts'; import { User } from '@/models/user.ts'; -import { getContainerById } from '@/routes/container/module/get-container-file.ts'; +import { getContainerById } from '@/old-apps/container/module/get-container-file.ts'; import { router, error, checkAuth, writeEvents } from './router.ts'; import './index.ts'; import { handleRequest as PageProxy } from './page-proxy.ts'; diff --git a/src/routes/index.ts b/src/routes/index.ts index ce3522f..b61eea9 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -11,4 +11,6 @@ import './config/index.ts'; import './file-listener/index.ts'; -import './ai/index.ts'; \ No newline at end of file +import './ai/index.ts'; + +import './prompts/index.ts' \ No newline at end of file diff --git a/src/routes/prompts/index.ts b/src/routes/prompts/index.ts new file mode 100644 index 0000000..9166f9d --- /dev/null +++ b/src/routes/prompts/index.ts @@ -0,0 +1 @@ +import './list.ts' \ No newline at end of file diff --git a/src/routes/prompts/list.ts b/src/routes/prompts/list.ts new file mode 100644 index 0000000..4113cb6 --- /dev/null +++ b/src/routes/prompts/list.ts @@ -0,0 +1,111 @@ +import { desc, eq, count, or, like, and } from 'drizzle-orm'; +import { schema, app, db } from '@/app.ts' + + +app.route({ + path: 'prompts', + key: 'list', + middleware: ['auth'], + description: '获取提示词列表', +}).define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const uid = tokenUser.id; + const { page = 1, pageSize = 20, search, sort = 'DESC' } = ctx.query || {}; + + const offset = (page - 1) * pageSize; + const orderByField = sort === 'ASC' ? schema.prompts.updatedAt : desc(schema.prompts.updatedAt); + + let whereCondition = eq(schema.prompts.uid, uid); + if (search) { + whereCondition = and( + eq(schema.prompts.uid, uid), + or( + like(schema.prompts.title, `%${search}%`), + like(schema.prompts.summary, `%${search}%`) + ) + ); + } + + const [list, totalCount] = await Promise.all([ + db.select() + .from(schema.prompts) + .where(whereCondition) + .limit(pageSize) + .offset(offset) + .orderBy(orderByField), + db.select({ count: count() }) + .from(schema.prompts) + .where(whereCondition) + ]); + + ctx.body = { + list, + pagination: { + page, + current: page, + pageSize, + total: totalCount[0]?.count || 0, + }, + }; + return ctx; +}).addTo(app); + +const promptUpdate = `创建或更新一个提示词, 参数定义: +title: 提示词标题, 必填 +description: 描述, 选填 +summary: 摘要, 选填 +tags: 标签, 数组, 选填 +link: 链接, 选填 +data: 数据, 对象, 选填 +parents: 父级ID数组, 选填 +`; +app.route({ + path: 'prompts', + key: 'update', + middleware: ['auth'], + description: promptUpdate, +}).define(async (ctx) => { + const { id, uid, updatedAt, ...rest } = ctx.query.data || {}; + const tokenUser = ctx.state.tokenUser; + let prompt; + if (!id) { + prompt = await db.insert(schema.prompts).values({ + title: rest.title, + description: rest.description, + ...rest, + uid: tokenUser.id, + }).returning(); + } else { + const existing = await db.select().from(schema.prompts).where(eq(schema.prompts.id, id)).limit(1); + if (existing.length === 0) { + ctx.throw(404, '没有找到对应的提示词'); + } + prompt = await db.update(schema.prompts).set({ + ...rest, + }).where(eq(schema.prompts.id, id)).returning(); + } + ctx.body = prompt; +}).addTo(app); + + +app.route({ + path: 'prompts', + key: 'delete', + middleware: ['auth'], + description: '删除提示词, 参数: id 提示词ID', +}).define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const { id } = ctx.query.data || {}; + if (!id) { + ctx.throw(400, 'id 参数缺失'); + } + const existing = await db.select().from(schema.prompts).where(eq(schema.prompts.id, id)).limit(1); + if (existing.length === 0) { + ctx.throw(404, '没有找到对应的提示词'); + } + if (existing[0].uid !== tokenUser.id) { + ctx.throw(403, '没有权限删除该提示词'); + } + await db.delete(schema.prompts).where(eq(schema.prompts.id, id)); + ctx.body = { success: true }; +}).addTo(app); \ No newline at end of file diff --git a/src/routes/types.ts b/src/routes/types.ts index 9d6d279..dda5edb 100644 --- a/src/routes/types.ts +++ b/src/routes/types.ts @@ -1 +1 @@ -export * from './container/type.ts' \ No newline at end of file +export * from '../old-apps/container/type.ts' \ No newline at end of file diff --git a/src/test/common-query.ts b/src/test/common-query.ts new file mode 100644 index 0000000..4ad537f --- /dev/null +++ b/src/test/common-query.ts @@ -0,0 +1,27 @@ + + +import { useConfig, useContextKey } from '@kevisual/context'; +import { Query } from '@kevisual/query'; +import util from 'node:util'; +const config = useConfig(); +export const showMore = (res: any) => { + return util.inspect(res, { depth: 6, colors: true }); +} +const token = 'st_r3u38c0jbhoc412ovzeeuaucygt6w5qg'; +export const query = new Query({ + url: 'http://localhost:4005/api/router', +}); +// const loginRes = await query.post({ +// path: 'user', +// key: 'login', +// username: 'root', +// password: config.KEVISUAL_PASSWORD ||'', +// }); +// console.log('login:', showMore(loginRes)); +query.beforeRequest = async (options) => { + options.headers = { + ...options.headers, + 'Authorization': 'Bearer ' + token, + }; + return options; +} \ No newline at end of file diff --git a/src/test/common.ts b/src/test/common.ts index b54bac5..b556ad9 100644 --- a/src/test/common.ts +++ b/src/test/common.ts @@ -3,6 +3,7 @@ import '@/route.ts'; import { useConfig, useContextKey } from '@kevisual/context'; import { Query } from '@kevisual/query'; import util from 'node:util'; + export { app, useContextKey @@ -23,6 +24,9 @@ export const showRes = (res, ...args) => { console.error(res.code, res.message, ...args); } } +export const showMore = (res: any) => { + return util.inspect(res, { depth: 6, colors: true }); +} export const exit = (code = 0) => { process.exit(code); @@ -30,4 +34,4 @@ export const exit = (code = 0) => { export const query = new Query({ url: 'https://kevisual.cn/api/router' -}) \ No newline at end of file +}) diff --git a/src/test/container.ts b/src/test/container.ts index dafc718..97769bc 100644 --- a/src/test/container.ts +++ b/src/test/container.ts @@ -1,4 +1,4 @@ -import { ContainerModel } from '../routes/container/models/index.ts'; +import { ContainerModel } from '../old-apps/container/models/index.ts'; const main = async () => { // await ContainerModel.update( diff --git a/src/test/prompt.ts b/src/test/prompt.ts new file mode 100644 index 0000000..967d415 --- /dev/null +++ b/src/test/prompt.ts @@ -0,0 +1,8 @@ +import { query, showMore } from './common-query.ts'; + +const res = await query.post({ + path: 'prompts', + key: 'list' +}) + +console.log('res:', showMore(res)); \ No newline at end of file