fix: 解决问题
This commit is contained in:
12
drizzle.config.ts
Normal file
12
drizzle.config.ts
Normal 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;
|
||||||
27
package.json
27
package.json
@@ -34,6 +34,9 @@
|
|||||||
"ssl": "ssh -L 5432:localhost:5432 light",
|
"ssl": "ssh -L 5432:localhost:5432 light",
|
||||||
"ssl:redis": "ssh -L 6379:localhost:6379 light",
|
"ssl:redis": "ssh -L 6379:localhost:6379 light",
|
||||||
"ssl:minio": "ssh -L 9000:localhost:9000 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"
|
"pub": "envision pack -p -u -c"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
@@ -48,10 +51,10 @@
|
|||||||
"@types/busboy": "^1.5.4",
|
"@types/busboy": "^1.5.4",
|
||||||
"@types/send": "^1.2.1",
|
"@types/send": "^1.2.1",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"bullmq": "^5.66.2",
|
"bullmq": "^5.66.3",
|
||||||
"busboy": "^1.6.0",
|
"busboy": "^1.6.0",
|
||||||
"commander": "^14.0.2",
|
"commander": "^14.0.2",
|
||||||
"cookie": "^1.1.1",
|
"drizzle-kit": "^0.31.8",
|
||||||
"drizzle-orm": "^0.45.1",
|
"drizzle-orm": "^0.45.1",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"ioredis": "^5.8.2",
|
"ioredis": "^5.8.2",
|
||||||
@@ -59,7 +62,9 @@
|
|||||||
"pg": "^8.16.3",
|
"pg": "^8.16.3",
|
||||||
"pm2": "^6.0.14",
|
"pm2": "^6.0.14",
|
||||||
"send": "^1.2.1",
|
"send": "^1.2.1",
|
||||||
"sequelize": "^6.37.7"
|
"sequelize": "^6.37.7",
|
||||||
|
"ws": "npm:@kevisual/ws",
|
||||||
|
"xml2js": "^0.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kevisual/code-center-module": "0.0.24",
|
"@kevisual/code-center-module": "0.0.24",
|
||||||
@@ -69,7 +74,7 @@
|
|||||||
"@kevisual/logger": "^0.0.4",
|
"@kevisual/logger": "^0.0.4",
|
||||||
"@kevisual/oss": "0.0.13",
|
"@kevisual/oss": "0.0.13",
|
||||||
"@kevisual/permission": "^0.0.3",
|
"@kevisual/permission": "^0.0.3",
|
||||||
"@kevisual/router": "0.0.48",
|
"@kevisual/router": "0.0.50",
|
||||||
"@kevisual/types": "^0.0.10",
|
"@kevisual/types": "^0.0.10",
|
||||||
"@kevisual/use-config": "^1.0.21",
|
"@kevisual/use-config": "^1.0.21",
|
||||||
"@types/archiver": "^7.0.0",
|
"@types/archiver": "^7.0.0",
|
||||||
@@ -79,10 +84,13 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^25.0.3",
|
"@types/node": "^25.0.3",
|
||||||
"@types/semver": "^7.7.1",
|
"@types/semver": "^7.7.1",
|
||||||
|
"@types/xml2js": "^0.4.14",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
|
"better-sqlite3": "^12.5.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
|
"es-toolkit": "^1.43.0",
|
||||||
"ioredis": "^5.8.2",
|
"ioredis": "^5.8.2",
|
||||||
"jsonwebtoken": "^9.0.3",
|
"jsonwebtoken": "^9.0.3",
|
||||||
"lodash-es": "^4.17.22",
|
"lodash-es": "^4.17.22",
|
||||||
@@ -94,10 +102,6 @@
|
|||||||
"pm2": "^6.0.14",
|
"pm2": "^6.0.14",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.3",
|
||||||
"sequelize": "^6.37.7",
|
"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"
|
"zod": "^4.2.1"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
@@ -107,11 +111,8 @@
|
|||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"esbuild",
|
"esbuild",
|
||||||
"sqlite3"
|
"better-sqlite3"
|
||||||
],
|
|
||||||
"ignoredBuiltDependencies": [
|
|
||||||
"msgpackr-extract"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.26.1"
|
"packageManager": "pnpm@10.26.2"
|
||||||
}
|
}
|
||||||
957
pnpm-lock.yaml
generated
957
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
|||||||
packages:
|
packages:
|
||||||
- 'wxmsg/*'
|
- 'wxmsg'
|
||||||
|
|||||||
155
scripts/clear.sql
Normal file
155
scripts/clear.sql
Normal 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 $$;
|
||||||
6987
src/db/drizzle/0000_groovy_red_skull.sql
Normal file
6987
src/db/drizzle/0000_groovy_red_skull.sql
Normal file
File diff suppressed because it is too large
Load Diff
48566
src/db/drizzle/meta/0000_snapshot.json
Normal file
48566
src/db/drizzle/meta/0000_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
13
src/db/drizzle/meta/_journal.json
Normal file
13
src/db/drizzle/meta/_journal.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1766803308366,
|
||||||
|
"tag": "0000_groovy_red_skull",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
src/db/drizzle/relations.ts
Normal file
3
src/db/drizzle/relations.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { relations } from "drizzle-orm/relations";
|
||||||
|
import { } from "./schema";
|
||||||
|
|
||||||
400
src/db/drizzle/schema.ts
Normal file
400
src/db/drizzle/schema.ts
Normal 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
14
src/db/schema.ts
Normal 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>;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { User } from '@/models/user.ts';
|
import { User } from '@/models/user.ts';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import cookie from 'cookie';
|
import * as cookie from '@kevisual/router/src/server/cookie.ts';
|
||||||
import { logger } from './logger.ts';
|
import { logger } from './logger.ts';
|
||||||
export const error = (msg: string, code = 500) => {
|
export const error = (msg: string, code = 500) => {
|
||||||
return JSON.stringify({ code, message: msg });
|
return JSON.stringify({ code, message: msg });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { User } from '@/models/user.ts';
|
import { User } from '@/models/user.ts';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import cookie from 'cookie';
|
import { parse } from '@kevisual/router/src/server/cookie.ts';
|
||||||
export const error = (msg: string, code = 500) => {
|
export const error = (msg: string, code = 500) => {
|
||||||
return JSON.stringify({ code, message: msg });
|
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') || '';
|
token = url.searchParams.get('token') || '';
|
||||||
}
|
}
|
||||||
if (!token) {
|
if (!token) {
|
||||||
const parsedCookies = cookie.parse(req.headers.cookie || '');
|
const parsedCookies = parse(req.headers.cookie || '');
|
||||||
token = parsedCookies.token || '';
|
token = parsedCookies.token || '';
|
||||||
}
|
}
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -44,9 +44,9 @@ export const getLoginUser = async (req: http.IncomingMessage) => {
|
|||||||
token = url.searchParams.get('token') || '';
|
token = url.searchParams.get('token') || '';
|
||||||
}
|
}
|
||||||
if (!token) {
|
if (!token) {
|
||||||
const parsedCookies = cookie.parse(req.headers.cookie || '');
|
const parsedCookies = parse(req.headers.cookie || '');
|
||||||
token = parsedCookies.token || '';
|
token = parsedCookies.token || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
token = token.replace('Bearer ', '');
|
token = token.replace('Bearer ', '');
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export {
|
|||||||
}
|
}
|
||||||
export const config = useConfig();
|
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 sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
export const showRes = (res, ...args) => {
|
export const showRes = (res, ...args) => {
|
||||||
|
|||||||
@@ -23,13 +23,13 @@
|
|||||||
],
|
],
|
||||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"packageManager": "pnpm@10.24.0",
|
"packageManager": "pnpm@10.26.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kevisual/context": "^0.0.4",
|
"@kevisual/context": "^0.0.4",
|
||||||
"@kevisual/query": "^0.0.29",
|
"@kevisual/query": "^0.0.33",
|
||||||
"@kevisual/router": "0.0.33",
|
"@kevisual/router": "0.0.50",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^25.0.3",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"xml2js": "^0.6.2"
|
"xml2js": "^0.6.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { SimpleRouter } from '@kevisual/router/simple';
|
import { SimpleRouter } from '@kevisual/router/simple';
|
||||||
import CryptoJS from 'crypto-js';
|
import CryptoJS from 'crypto-js';
|
||||||
import xml2js from 'xml2js';
|
|
||||||
import { useContextKey } from '@kevisual/context';
|
import { useContextKey } from '@kevisual/context';
|
||||||
import { Redis } from 'ioredis';
|
import { Redis } from 'ioredis';
|
||||||
import http from 'node:http';
|
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 { contextConfig as config } from './modules/config.ts';
|
||||||
import { loginByTicket } from './wx/login-by-ticket.ts';
|
import { loginByTicket } from './wx/login-by-ticket.ts';
|
||||||
import { Queue } from 'bullmq';
|
import { Queue } from 'bullmq';
|
||||||
|
import { parseXml } from './utils/get-json-from-xml.ts';
|
||||||
export const simpleRouter: SimpleRouter = await useContextKey('router');
|
export const simpleRouter: SimpleRouter = await useContextKey('router');
|
||||||
export const redis: Redis = await useContextKey('redis');
|
export const redis: Redis = await useContextKey('redis');
|
||||||
export const wxmsgQueue = useContextKey<Queue>('wxmsgQueue', () => {
|
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) => {
|
simpleRouter.post('/api/wxmsg', async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||||
try {
|
try {
|
||||||
const xml = await getJsonFromXml(req);
|
const xml = await parseXml(req);
|
||||||
const msgOrigin = xml?.xml;
|
const msgOrigin = xml?.xml;
|
||||||
if (!msgOrigin) {
|
if (!msgOrigin) {
|
||||||
console.error('No message received');
|
console.error('No message received');
|
||||||
|
|||||||
52
wxmsg/src/utils/get-json-from-xml.ts
Normal file
52
wxmsg/src/utils/get-json-from-xml.ts
Normal 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
19
wxmsg/src/utils/is-engine.ts
Normal file
19
wxmsg/src/utils/is-engine.ts
Normal 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';
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user