fix: 解决问题

This commit is contained in:
2025-12-28 10:52:04 +08:00
parent 868979a423
commit 9f51d27398
18 changed files with 57061 additions and 201 deletions

12
drizzle.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import type { Config } from 'drizzle-kit';
import 'dotenv/config';
const url = process.env.DATABASE_URL!;
export default {
schema: './src/db/schema.ts',
out: './src/db/drizzle',
dialect: 'postgresql',
dbCredentials: {
url,
},
} satisfies Config;

View File

@@ -34,6 +34,9 @@
"ssl": "ssh -L 5432:localhost:5432 light",
"ssl:redis": "ssh -L 6379:localhost:6379 light",
"ssl:minio": "ssh -L 9000:localhost:9000 light",
"studio": "npx drizzle-kit studio",
"drizzle:migrate": "npx drizzle-kit migrate",
"drizzle:push": "npx drizzle-kit push",
"pub": "envision pack -p -u -c"
},
"keywords": [],
@@ -48,10 +51,10 @@
"@types/busboy": "^1.5.4",
"@types/send": "^1.2.1",
"@types/ws": "^8.18.1",
"bullmq": "^5.66.2",
"bullmq": "^5.66.3",
"busboy": "^1.6.0",
"commander": "^14.0.2",
"cookie": "^1.1.1",
"drizzle-kit": "^0.31.8",
"drizzle-orm": "^0.45.1",
"eventemitter3": "^5.0.1",
"ioredis": "^5.8.2",
@@ -59,7 +62,9 @@
"pg": "^8.16.3",
"pm2": "^6.0.14",
"send": "^1.2.1",
"sequelize": "^6.37.7"
"sequelize": "^6.37.7",
"ws": "npm:@kevisual/ws",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@kevisual/code-center-module": "0.0.24",
@@ -69,7 +74,7 @@
"@kevisual/logger": "^0.0.4",
"@kevisual/oss": "0.0.13",
"@kevisual/permission": "^0.0.3",
"@kevisual/router": "0.0.48",
"@kevisual/router": "0.0.50",
"@kevisual/types": "^0.0.10",
"@kevisual/use-config": "^1.0.21",
"@types/archiver": "^7.0.0",
@@ -79,10 +84,13 @@
"@types/lodash-es": "^4.17.12",
"@types/node": "^25.0.3",
"@types/semver": "^7.7.1",
"@types/xml2js": "^0.4.14",
"archiver": "^7.0.1",
"better-sqlite3": "^12.5.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.19",
"dotenv": "^17.2.3",
"es-toolkit": "^1.43.0",
"ioredis": "^5.8.2",
"jsonwebtoken": "^9.0.3",
"lodash-es": "^4.17.22",
@@ -94,10 +102,6 @@
"pm2": "^6.0.14",
"semver": "^7.7.3",
"sequelize": "^6.37.7",
"socket.io": "^4.8.1",
"strip-ansi": "^7.1.2",
"tar": "^7.5.2",
"ws": "npm:@kevisual/ws",
"zod": "^4.2.1"
},
"resolutions": {
@@ -107,11 +111,8 @@
"pnpm": {
"onlyBuiltDependencies": [
"esbuild",
"sqlite3"
],
"ignoredBuiltDependencies": [
"msgpackr-extract"
"better-sqlite3"
]
},
"packageManager": "pnpm@10.26.1"
"packageManager": "pnpm@10.26.2"
}

957
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,2 @@
packages:
- 'wxmsg/*'
- 'wxmsg'

155
scripts/clear.sql Normal file
View File

@@ -0,0 +1,155 @@
-- =====================================================
-- 删除 cf_orgs 表中所有带数字的重复唯一约束
-- 保留 cf_orgs_username_key不带数字的
-- =====================================================
DO $$
DECLARE
constraint_record RECORD;
BEGIN
FOR constraint_record IN
SELECT conname
FROM pg_constraint
WHERE conrelid = 'cf_orgs'::regclass
AND conname LIKE 'cf_orgs_username_key%'
AND conname != 'cf_orgs_username_key'
AND conname ~ '[0-9]' -- 包含数字的
ORDER BY conname
LOOP
EXECUTE format('ALTER TABLE cf_orgs DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
RAISE NOTICE '已删除约束: %', constraint_record.conname;
END LOOP;
END $$;
-- =====================================================
-- 删除 cf_user 表中所有带数字的重复唯一约束
-- 保留 cf_user_username_key不带数字的
-- =====================================================
DO $$
DECLARE
constraint_record RECORD;
BEGIN
FOR constraint_record IN
SELECT conname
FROM pg_constraint
WHERE conrelid = 'cf_user'::regclass
AND conname LIKE 'cf_user_username_key%'
AND conname != 'cf_user_username_key'
AND conname ~ '[0-9]' -- 包含数字的
ORDER BY conname
LOOP
EXECUTE format('ALTER TABLE cf_user DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
RAISE NOTICE '已删除约束: %', constraint_record.conname;
END LOOP;
END $$;
-- =====================================================
-- 验证删除结果
-- =====================================================
-- 查看 cf_orgs 剩余的 username 约束
SELECT 'cf_orgs 表剩余的 username 约束:' AS info;
SELECT conname
FROM pg_constraint
WHERE conrelid = 'cf_orgs'::regclass
AND conname LIKE 'cf_orgs_username_key%'
ORDER BY conname;
-- 查看 cf_user 剩余的 username 约束
SELECT 'cf_user 表剩余的 username 约束:' AS info;
SELECT conname
FROM pg_constraint
WHERE conrelid = 'cf_user'::regclass
AND conname LIKE 'cf_user_username_key%'
ORDER BY conname;
-- =====================================================
-- 删除 kv_app_domain 表中所有带数字的重复唯一约束
-- 保留 kv_app_domain_domain_key不带数字的
-- =====================================================
DO $$
DECLARE
constraint_record RECORD;
BEGIN
FOR constraint_record IN
SELECT conname
FROM pg_constraint
WHERE conrelid = 'kv_app_domain'::regclass
AND conname LIKE 'kv_app_domain_domain_key%'
AND conname != 'kv_app_domain_domain_key'
AND conname ~ '[0-9]' -- 包含数字的
ORDER BY conname
LOOP
EXECUTE format('ALTER TABLE kv_app_domain DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
RAISE NOTICE '已删除约束: %', constraint_record.conname;
END LOOP;
END $$;
-- =====================================================
-- 删除 prompts 表中所有带数字的重复唯一约束
-- 保留 prompts_key_key不带数字的
-- =====================================================
DO $$
DECLARE
constraint_record RECORD;
BEGIN
FOR constraint_record IN
SELECT conname
FROM pg_constraint
WHERE conrelid = 'prompts'::regclass
AND conname LIKE 'prompts_key_key%'
AND conname != 'prompts_key_key'
AND conname ~ '[0-9]' -- 包含数字的
ORDER BY conname
LOOP
EXECUTE format('ALTER TABLE prompts DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
RAISE NOTICE '已删除约束: %', constraint_record.conname;
END LOOP;
END $$;
-- =====================================================
-- 删除 apps_trades 表中所有带数字的重复唯一约束
-- 保留 apps_trades_out_trade_no_key不带数字的
-- =====================================================
DO $$
DECLARE
constraint_record RECORD;
BEGIN
FOR constraint_record IN
SELECT conname
FROM pg_constraint
WHERE conrelid = 'apps_trades'::regclass
AND conname LIKE 'apps_trades_out_trade_no_key%'
AND conname != 'apps_trades_out_trade_no_key'
AND conname ~ '[0-9]' -- 包含数字的
ORDER BY conname
LOOP
EXECUTE format('ALTER TABLE apps_trades DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
RAISE NOTICE '已删除约束: %', constraint_record.conname;
END LOOP;
END $$;
-- =====================================================
-- 删除 ai_agent 表中所有带数字的重复唯一约束
-- 保留 ai_agent_key_key不带数字的
-- =====================================================
DO $$
DECLARE
constraint_record RECORD;
BEGIN
FOR constraint_record IN
SELECT conname
FROM pg_constraint
WHERE conrelid = 'ai_agent'::regclass
AND conname LIKE 'ai_agent_key_key%'
AND conname != 'ai_agent_key_key'
AND conname ~ '[0-9]' -- 包含数字的
ORDER BY conname
LOOP
EXECUTE format('ALTER TABLE ai_agent DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
RAISE NOTICE '已删除约束: %', constraint_record.conname;
END LOOP;
END $$;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1766803308366,
"tag": "0000_groovy_red_skull",
"breakpoints": true
}
]
}

View File

@@ -0,0 +1,3 @@
import { relations } from "drizzle-orm/relations";
import { } from "./schema";

400
src/db/drizzle/schema.ts Normal file
View File

@@ -0,0 +1,400 @@
import { pgTable, serial, text, jsonb, varchar, timestamp, unique, uuid, doublePrecision, json, integer, boolean, index, uniqueIndex, pgEnum } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"
export const enumCfRouterCodeType = pgEnum("enum_cf_router_code_type", ['route', 'middleware'])
export const testPromptTools = pgTable("TestPromptTools", {
id: serial().primaryKey().notNull(),
template: text().notNull(),
args: jsonb().notNull(),
process: jsonb().notNull(),
type: varchar({ length: 255 }).notNull(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
});
export const aiAgent = pgTable("ai_agent", {
id: uuid().primaryKey().notNull(),
type: varchar({ length: 255 }).notNull(),
baseUrl: varchar({ length: 255 }).notNull(),
apiKey: varchar({ length: 255 }).notNull(),
temperature: doublePrecision(),
cache: varchar({ length: 255 }),
cacheName: varchar({ length: 255 }),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
model: varchar({ length: 255 }).notNull(),
data: json().default({}),
status: varchar({ length: 255 }).default('open'),
key: varchar({ length: 255 }).notNull(),
description: text(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
}, (table) => [
unique("ai_agent_key_key").on(table.key),
]);
export const appsTrades = pgTable("apps_trades", {
id: uuid().primaryKey().notNull(),
outTradeNo: varchar("out_trade_no", { length: 255 }).notNull(),
money: integer().notNull(),
subject: text().notNull(),
status: varchar({ length: 255 }).default('WAIT_BUYER_PAY').notNull(),
type: varchar({ length: 255 }).default('alipay').notNull(),
data: jsonb().default({"list":[]}),
uid: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
}, (table) => [
unique("apps_trades_out_trade_no_key").on(table.outTradeNo),
]);
export const cfOrgs = pgTable("cf_orgs", {
id: uuid().primaryKey().notNull(),
username: varchar({ length: 255 }).notNull(),
users: jsonb().default([]),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
description: varchar({ length: 255 }),
}, (table) => [
unique("cf_orgs_username_key").on(table.username),
]);
export const cfRouterCode = pgTable("cf_router_code", {
id: uuid().primaryKey().notNull(),
path: varchar({ length: 255 }).notNull(),
key: varchar({ length: 255 }).notNull(),
active: boolean().default(false),
project: varchar({ length: 255 }).default('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('),
data: json().default({}),
validator: json().default({}),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
});
export const cfUser = pgTable("cf_user", {
id: uuid().primaryKey().notNull(),
username: varchar({ length: 255 }).notNull(),
password: varchar({ length: 255 }),
salt: varchar({ length: 255 }),
needChangePassword: boolean().default(false),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
description: text(),
data: jsonb().default({}),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
type: varchar({ length: 255 }).default('user'),
owner: uuid(),
orgId: uuid(),
email: varchar({ length: 255 }),
avatar: text(),
nickname: text(),
}, (table) => [
unique("cf_user_username_key").on(table.username),
]);
export const cfUserSecrets = pgTable("cf_user_secrets", {
id: uuid().primaryKey().notNull(),
description: text(),
status: varchar({ length: 255 }).default('active'),
title: text(),
expiredTime: timestamp({ withTimezone: true, mode: 'string' }),
token: varchar({ length: 255 }).default(').notNull(),
userId: uuid(),
data: jsonb().default({}),
orgId: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
});
export const chatHistories = pgTable("chat_histories", {
id: uuid().primaryKey().notNull(),
data: json(),
chatId: uuid(),
chatPromptId: uuid(),
root: boolean().default(false),
show: boolean().default(true),
uid: varchar({ length: 255 }),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
role: varchar({ length: 255 }).default('user'),
});
export const chatPrompts = pgTable("chat_prompts", {
id: uuid().primaryKey().notNull(),
title: varchar({ length: 255 }).notNull(),
description: text(),
data: json(),
key: varchar({ length: 255 }).default(').notNull(),
uid: varchar({ length: 255 }),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
});
export const chatSessions = pgTable("chat_sessions", {
id: uuid().primaryKey().notNull(),
data: json().default({}),
chatPromptId: uuid(),
type: varchar({ length: 255 }).default('production'),
uid: varchar({ length: 255 }),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
title: varchar({ length: 255 }).default('),
key: varchar({ length: 255 }),
});
export const fileSync = pgTable("file_sync", {
id: uuid().primaryKey().notNull(),
name: varchar({ length: 255 }),
hash: varchar({ length: 255 }),
stat: jsonb().default({}),
data: jsonb().default({}),
checkedAt: timestamp({ withTimezone: true, mode: 'string' }),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
}, (table) => [
index("file_sync_name_idx").using("btree", table.name.asc().nullsLast().op("text_ops")),
]);
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(),
messages: jsonb().default([]).notNull(),
promptTokens: integer("prompt_tokens").default(0),
totalTokens: integer("total_tokens").default(0),
completionTokens: integer("completion_tokens").default(0),
data: jsonb().default({}),
uid: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
version: integer().default(0),
type: varchar({ length: 255 }).default('keep').notNull(),
});
export const kvApp = pgTable("kv_app", {
id: uuid().primaryKey().notNull(),
data: jsonb().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('),
user: varchar({ length: 255 }),
status: varchar({ length: 255 }).default('running'),
pid: uuid(),
proxy: boolean().default(false),
}, (table) => [
uniqueIndex("kv_app_key_uid").using("btree", table.key.asc().nullsLast().op("text_ops"), table.uid.asc().nullsLast().op("text_ops")),
unique("key_uid_unique").on(table.key, table.uid),
]);
export const kvAppDomain = pgTable("kv_app_domain", {
id: uuid().primaryKey().notNull(),
domain: varchar({ length: 255 }).notNull(),
appId: varchar({ length: 255 }),
uid: varchar({ length: 255 }),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
data: jsonb(),
status: varchar({ length: 255 }).default('running').notNull(),
}, (table) => [
unique("kv_app_domain_domain_key").on(table.domain),
]);
export const kvAppList = pgTable("kv_app_list", {
id: uuid().primaryKey().notNull(),
data: json().default({}),
version: varchar({ length: 255 }).default('),
uid: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
key: varchar({ length: 255 }),
status: varchar({ length: 255 }).default('running'),
});
export const kvConfig = pgTable("kv_config", {
id: uuid().primaryKey().notNull(),
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('),
});
export const kvContainer = pgTable("kv_container", {
id: uuid().primaryKey().notNull(),
title: text().default('),
description: text().default('),
type: varchar({ length: 255 }).default('render-js'),
code: text().default('),
data: json().default({}),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
uid: uuid(),
publish: json().default({}),
tags: json().default([]),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
hash: text().default('),
});
export const kvGithub = pgTable("kv_github", {
id: uuid().primaryKey().notNull(),
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(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
});
export const kvPackages = pgTable("kv_packages", {
id: uuid().primaryKey().notNull(),
title: text().default('),
description: text().default('),
tags: jsonb().default([]),
data: jsonb().default({}),
publish: jsonb().default({}),
expand: jsonb().default({}),
uid: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
});
export const kvPage = pgTable("kv_page", {
id: uuid().primaryKey().notNull(),
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(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
publish: json().default({}),
});
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('),
version: varchar({ length: 255 }).default('0.0.0'),
data: json().default({}),
uid: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
});
export const kvVip = pgTable("kv_vip", {
id: uuid().primaryKey().notNull(),
userId: uuid().notNull(),
level: varchar({ length: 255 }).default('free'),
category: varchar({ length: 255 }).notNull(),
startDate: timestamp({ withTimezone: true, mode: 'string' }),
endDate: timestamp({ withTimezone: true, mode: 'string' }),
data: jsonb().default({}),
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(),
});
export const microAppsUpload = pgTable("micro_apps_upload", {
id: uuid().primaryKey().notNull(),
title: varchar({ length: 255 }).default('),
description: varchar({ length: 255 }).default('),
tags: jsonb().default([]),
type: varchar({ length: 255 }).default('),
source: varchar({ length: 255 }).default('),
data: jsonb().default({}),
share: boolean().default(false),
uname: varchar({ length: 255 }).default('),
uid: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
});
export const microMark = pgTable("micro_mark", {
id: uuid().primaryKey().notNull(),
title: text().default('),
description: text().default('),
tags: jsonb().default([]),
data: jsonb().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('),
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('),
});
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('),
markType: text().default('md'),
description: text().default('),
cover: text().default('),
link: text().default('),
tags: jsonb().default([]),
summary: text().default('),
config: jsonb().default({}),
data: jsonb().default({}),
fileList: jsonb().default([]),
uname: varchar({ length: 255 }).default('),
version: integer().default(1),
markedAt: timestamp({ withTimezone: true, mode: 'string' }),
uid: uuid(),
puid: uuid(),
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
});

14
src/db/schema.ts Normal file
View File

@@ -0,0 +1,14 @@
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<typeof aiUsages>;

View File

@@ -1,6 +1,6 @@
import { User } from '@/models/user.ts';
import http from 'http';
import cookie from 'cookie';
import * as cookie from '@kevisual/router/src/server/cookie.ts';
import { logger } from './logger.ts';
export const error = (msg: string, code = 500) => {
return JSON.stringify({ code, message: msg });

View File

@@ -1,6 +1,6 @@
import { User } from '@/models/user.ts';
import http from 'http';
import cookie from 'cookie';
import { parse } from '@kevisual/router/src/server/cookie.ts';
export const error = (msg: string, code = 500) => {
return JSON.stringify({ code, message: msg });
};
@@ -16,7 +16,7 @@ export const checkAuth = async (req: http.IncomingMessage, res: http.ServerRespo
token = url.searchParams.get('token') || '';
}
if (!token) {
const parsedCookies = cookie.parse(req.headers.cookie || '');
const parsedCookies = parse(req.headers.cookie || '');
token = parsedCookies.token || '';
}
if (!token) {
@@ -44,9 +44,9 @@ export const getLoginUser = async (req: http.IncomingMessage) => {
token = url.searchParams.get('token') || '';
}
if (!token) {
const parsedCookies = cookie.parse(req.headers.cookie || '');
const parsedCookies = parse(req.headers.cookie || '');
token = parsedCookies.token || '';
}
}
if (token) {
token = token.replace('Bearer ', '');

View File

@@ -9,7 +9,7 @@ export {
}
export const config = useConfig();
export const token = config.TOKEN || '';
export const token = config.KEVISUAL_TOKEN || '';
export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
export const showRes = (res, ...args) => {

View File

@@ -23,13 +23,13 @@
],
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
"license": "MIT",
"packageManager": "pnpm@10.24.0",
"packageManager": "pnpm@10.26.2",
"type": "module",
"dependencies": {
"@kevisual/context": "^0.0.4",
"@kevisual/query": "^0.0.29",
"@kevisual/router": "0.0.33",
"@types/node": "^24.10.1",
"@kevisual/query": "^0.0.33",
"@kevisual/router": "0.0.50",
"@types/node": "^25.0.3",
"crypto-js": "^4.2.0",
"xml2js": "^0.6.2"
},

View File

@@ -1,6 +1,5 @@
import { SimpleRouter } from '@kevisual/router/simple';
import CryptoJS from 'crypto-js';
import xml2js from 'xml2js';
import { useContextKey } from '@kevisual/context';
import { Redis } from 'ioredis';
import http from 'node:http';
@@ -8,6 +7,7 @@ import { Wx, WxMsgEvent, parseWxMessage } from './wx/index.ts';
import { contextConfig as config } from './modules/config.ts';
import { loginByTicket } from './wx/login-by-ticket.ts';
import { Queue } from 'bullmq';
import { parseXml } from './utils/get-json-from-xml.ts';
export const simpleRouter: SimpleRouter = await useContextKey('router');
export const redis: Redis = await useContextKey('redis');
export const wxmsgQueue = useContextKey<Queue>('wxmsgQueue', () => {
@@ -36,40 +36,9 @@ simpleRouter.get('/api/wxmsg', async (req: http.IncomingMessage, res: http.Serve
}
});
export const getJsonFromXml = async (req: http.IncomingMessage): Promise<any> => {
return await new Promise((resolve) => {
// 读取请求数据
let data = '';
req.setEncoding('utf8');
// 监听data事件接收数据片段
req.on('data', (chunk: string) => {
data += chunk;
});
// 当请求结束时处理数据
req.on('end', () => {
try {
// 使用xml2js解析XML
xml2js.parseString(data, function (err, result) {
if (err) {
console.error('XML解析错误:', err);
resolve(null);
} else {
resolve(result);
}
});
} catch (error) {
console.error('处理请求时出错:', error);
resolve(null);
}
});
});
};
simpleRouter.post('/api/wxmsg', async (req: http.IncomingMessage, res: http.ServerResponse) => {
try {
const xml = await getJsonFromXml(req);
const xml = await parseXml(req);
const msgOrigin = xml?.xml;
if (!msgOrigin) {
console.error('No message received');

View File

@@ -0,0 +1,52 @@
import xml2js from 'xml2js';
import { isBun } from '../utils/is-engine.ts';
import http from 'http';
export const xms2jsParser = async (data: string): Promise<any> => {
try {
// 使用xml2js解析XML
const xml = await xml2js.parseStringPromise(data);
return xml;
} catch (error) {
console.error('XML解析错误:', error);
return null;
}
}
export const parseXml = async (req: http.IncomingMessage): Promise<any> => {
if (isBun) {
// @ts-ignore
const body = req.body;
let xmlString = '';
if (body) {
xmlString = body;
}
if (!xmlString) {
// @ts-ignore
xmlString = await req.bun?.request?.text?.();
}
if (xmlString) {
return await xms2jsParser(xmlString)
}
console.error('没有读取到请求体');
return null;
}
return await new Promise((resolve) => {
// 读取请求数据
let data = '';
req.setEncoding('utf8');
// 监听data事件接收数据片段
req.on('data', (chunk) => {
data += chunk;
});
// 当请求结束时处理数据
req.on('end', () => {
try {
xms2jsParser(data).then((result) => {
resolve(result);
});
} catch (error) {
console.error('处理请求时出错:', error);
resolve(null);
}
});
});
};

View File

@@ -0,0 +1,19 @@
export const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
export const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.createElement === 'function';
// @ts-ignore
export const isDeno = typeof Deno !== 'undefined' && typeof Deno.version === 'object' && typeof Deno.version.deno === 'string';
// @ts-ignore
export const isBun = typeof Bun !== 'undefined' && typeof Bun.version === 'string';
export const getEngine = () => {
if (isBun) {
return 'bun';
} else if (isNode) {
return 'node';
} else if (isBrowser) {
return 'browser';
} else if (isDeno) {
return 'deno';
}
return 'unknown';
};