@huyooo/ai-chat-storage 0.2.45 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/adapters/postgres/backups.d.ts +12 -0
  2. package/dist/adapters/postgres/backups.d.ts.map +1 -0
  3. package/dist/adapters/postgres/base.d.ts +12 -0
  4. package/dist/adapters/postgres/base.d.ts.map +1 -0
  5. package/dist/adapters/postgres/embeddings.d.ts +16 -0
  6. package/dist/adapters/postgres/embeddings.d.ts.map +1 -0
  7. package/dist/adapters/postgres/index.d.ts +55 -0
  8. package/dist/adapters/postgres/index.d.ts.map +1 -0
  9. package/dist/adapters/postgres/messages.d.ts +25 -0
  10. package/dist/adapters/postgres/messages.d.ts.map +1 -0
  11. package/dist/adapters/postgres/operations.d.ts +16 -0
  12. package/dist/adapters/postgres/operations.d.ts.map +1 -0
  13. package/dist/adapters/postgres/sessions.d.ts +16 -0
  14. package/dist/adapters/postgres/sessions.d.ts.map +1 -0
  15. package/dist/adapters/postgres/trash.d.ts +14 -0
  16. package/dist/adapters/postgres/trash.d.ts.map +1 -0
  17. package/dist/adapters/sqlite/backups.d.ts +12 -0
  18. package/dist/adapters/sqlite/backups.d.ts.map +1 -0
  19. package/dist/adapters/sqlite/base.d.ts +22 -0
  20. package/dist/adapters/sqlite/base.d.ts.map +1 -0
  21. package/dist/adapters/sqlite/embeddings.d.ts +16 -0
  22. package/dist/adapters/sqlite/embeddings.d.ts.map +1 -0
  23. package/dist/adapters/sqlite/index.d.ts +55 -0
  24. package/dist/adapters/sqlite/index.d.ts.map +1 -0
  25. package/dist/adapters/sqlite/messages.d.ts +25 -0
  26. package/dist/adapters/sqlite/messages.d.ts.map +1 -0
  27. package/dist/adapters/sqlite/operations.d.ts +16 -0
  28. package/dist/adapters/sqlite/operations.d.ts.map +1 -0
  29. package/dist/adapters/sqlite/sessions.d.ts +16 -0
  30. package/dist/adapters/sqlite/sessions.d.ts.map +1 -0
  31. package/dist/adapters/sqlite/trash.d.ts +14 -0
  32. package/dist/adapters/sqlite/trash.d.ts.map +1 -0
  33. package/dist/adapters/sqlite/user-settings.d.ts +22 -0
  34. package/dist/adapters/sqlite/user-settings.d.ts.map +1 -0
  35. package/dist/index.d.ts +13 -1567
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +545 -1
  38. package/dist/schema.d.ts +1410 -0
  39. package/dist/schema.d.ts.map +1 -0
  40. package/dist/types.d.ts +195 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/package.json +8 -4
  43. package/dist/chunk-EXGLTJH4.js +0 -268
  44. package/dist/chunk-V5E7YX6J.js +0 -1
  45. package/dist/postgres-JFFEO52T.js +0 -1
  46. package/dist/sqlite-BVA3FN4Z.js +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,UAAU;AACV,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBnB,CAAC;AAEH,UAAU;AACV,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmCnB,CAAC;AAEH,iBAAiB;AACjB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQvB,CAAC;AAEH,YAAY;AACZ,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBrB,CAAC;AAEH,YAAY;AACZ,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYlB,CAAC;AAEH,WAAW;AACX,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYhB,CAAC;AAEH,+BAA+B;AAC/B,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcrB,CAAC"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * 存储层类型定义
3
+ */
4
+ import type BetterSqlite3 from 'better-sqlite3';
5
+ import type { AtChatContextItem, AtContextItem, GetMessagesPageParams, MessagePage, MessagePartInput, MessagePartRecord } from '@huyooo/ai-chat-types';
6
+ export interface StorageContext {
7
+ /** 租户 ID(多租户模式) */
8
+ appId?: string;
9
+ /** 用户 ID(多用户模式) */
10
+ userId?: string;
11
+ }
12
+ export interface SessionRecord {
13
+ id: string;
14
+ appId: string | null;
15
+ userId: string | null;
16
+ title: string;
17
+ model: string;
18
+ mode: 'agent' | 'ask';
19
+ webSearchEnabled: boolean;
20
+ thinkingEnabled: boolean;
21
+ /** 是否在 tab 栏隐藏(关闭但不删除) */
22
+ hidden: boolean;
23
+ createdAt: Date;
24
+ updatedAt: Date;
25
+ }
26
+ export type CreateSessionInput = Omit<SessionRecord, 'createdAt' | 'updatedAt' | 'appId' | 'userId'>;
27
+ export type UpdateSessionInput = Partial<Pick<SessionRecord, 'title' | 'model' | 'mode' | 'webSearchEnabled' | 'thinkingEnabled' | 'hidden'>>;
28
+ export interface MessageRecord {
29
+ id: string;
30
+ /** 前端关联 ID(本地模式与 id 相同,云端模式为前端生成的 UUID) */
31
+ clientId: string | null;
32
+ sessionId: string;
33
+ appId: string | null;
34
+ userId: string | null;
35
+ role: 'user' | 'assistant' | 'system';
36
+ content: string;
37
+ /** 用户通过 @ 选择的上下文资源 */
38
+ atContextItems: AtContextItem[] | null;
39
+ /** 用户消息附带的图片(data URL 或 base64) */
40
+ images: string[];
41
+ /** 生成此消息时使用的模型 */
42
+ model: string | null;
43
+ /** 生成此消息时使用的模式 (ask/agent) */
44
+ mode: string | null;
45
+ /** 生成此消息时是否启用 web 搜索 */
46
+ webSearchEnabled: boolean | null;
47
+ /** 生成此消息时是否启用深度思考 */
48
+ thinkingEnabled: boolean | null;
49
+ /** 子表中的消息内容 Part */
50
+ parts: MessagePartRecord[];
51
+ operationIds: string | null;
52
+ /** Token 使用统计(JSON 字符串) */
53
+ usage: string | null;
54
+ /** 响应耗时(毫秒) */
55
+ duration: number | null;
56
+ /** 结束原因(done 事件携带) */
57
+ finishReason: import('@huyooo/ai-chat-types').FinishReason | null;
58
+ /** 消息序号(会话内递增,用于分叉删除,必须) */
59
+ sequence: number;
60
+ /** 时间戳(毫秒,Unix 时间戳,不受 JSON 序列化影响) */
61
+ timestamp: number;
62
+ }
63
+ export type CreateMessageInput = Omit<MessageRecord, 'timestamp' | 'appId' | 'userId' | 'sequence' | 'usage' | 'duration' | 'finishReason' | 'parts'> & {
64
+ parts?: MessagePartInput[];
65
+ finishReason?: MessageRecord['finishReason'];
66
+ };
67
+ /** 更新消息输入 */
68
+ export type UpdateMessageInput = Partial<Pick<MessageRecord, 'content' | 'atContextItems' | 'operationIds' | 'usage' | 'duration' | 'finishReason'>> & {
69
+ parts?: MessagePartInput[];
70
+ };
71
+ export type OperationStatus = 'pending' | 'confirmed' | 'executed' | 'reverted' | 'failed';
72
+ export interface OperationRecord {
73
+ id: string;
74
+ sessionId: string;
75
+ messageId: string | null;
76
+ appId: string | null;
77
+ userId: string | null;
78
+ command: string;
79
+ operationType: string;
80
+ affectedFiles: string;
81
+ backupPath: string | null;
82
+ status: OperationStatus;
83
+ errorMessage: string | null;
84
+ timestamp: Date;
85
+ }
86
+ export type CreateOperationInput = Omit<OperationRecord, 'timestamp' | 'appId' | 'userId' | 'status' | 'errorMessage'> & {
87
+ status?: OperationStatus;
88
+ };
89
+ export interface BackupRecord {
90
+ id: string;
91
+ operationId: string;
92
+ originalPath: string;
93
+ backupPath: string;
94
+ fileSize: number;
95
+ fileHash: string;
96
+ createdAt: Date;
97
+ expiresAt: Date;
98
+ }
99
+ export interface TrashRecord {
100
+ id: string;
101
+ sessionId: string;
102
+ appId: string | null;
103
+ userId: string | null;
104
+ originalPath: string;
105
+ trashPath: string;
106
+ deletedAt: Date;
107
+ autoDeleteAt: Date;
108
+ }
109
+ export interface EmbeddingRecord {
110
+ id: string;
111
+ sessionId: string;
112
+ messageId: string | null;
113
+ appId: string | null;
114
+ userId: string | null;
115
+ content: string;
116
+ contentType: 'message' | 'file' | 'summary';
117
+ embedding: number[];
118
+ metadata: string | null;
119
+ createdAt: Date;
120
+ }
121
+ export interface VectorSearchResult {
122
+ id: string;
123
+ content: string;
124
+ contentType: string;
125
+ similarity: number;
126
+ metadata?: Record<string, unknown>;
127
+ }
128
+ export interface VectorSearchOptions {
129
+ limit?: number;
130
+ threshold?: number;
131
+ sessionId?: string;
132
+ }
133
+ export interface StorageAdapter {
134
+ getSessions(ctx: StorageContext): Promise<SessionRecord[]>;
135
+ getSession(id: string, ctx: StorageContext): Promise<SessionRecord | null>;
136
+ createSession(session: CreateSessionInput, ctx: StorageContext): Promise<SessionRecord>;
137
+ updateSession(id: string, data: UpdateSessionInput, ctx: StorageContext): Promise<void>;
138
+ deleteSession(id: string, ctx: StorageContext): Promise<void>;
139
+ getMessages(sessionId: string, ctx: StorageContext): Promise<MessageRecord[]>;
140
+ getMessagesPage(sessionId: string, params: GetMessagesPageParams | undefined, ctx: StorageContext): Promise<MessagePage>;
141
+ searchAtChats(query: string, options: {
142
+ limit?: number;
143
+ } | undefined, ctx: StorageContext): Promise<AtChatContextItem[]>;
144
+ getMessage(id: string, ctx: StorageContext): Promise<MessageRecord | null>;
145
+ saveMessage(message: CreateMessageInput, ctx: StorageContext): Promise<MessageRecord>;
146
+ /** 更新消息(用于增量保存助手消息) */
147
+ updateMessage(id: string, data: UpdateMessageInput, ctx: StorageContext): Promise<void>;
148
+ deleteMessagesAfter(sessionId: string, timestamp: Date, ctx: StorageContext): Promise<void>;
149
+ /**
150
+ * 删除指定消息之后的所有消息(用于分叉/重新发送)
151
+ *
152
+ * 说明:
153
+ * - 前端/IPC 里 timestamp 可能出现 Date/string 等序列化差异
154
+ * - 用 messageId 作为锚点更稳定:后端根据 messageId 查出 timestamp,再执行 deleteMessagesAfter
155
+ */
156
+ deleteMessagesAfterMessageId(sessionId: string, messageId: string, ctx: StorageContext): Promise<void>;
157
+ getOperations(sessionId: string, ctx: StorageContext): Promise<OperationRecord[]>;
158
+ getOperationsByMessage(messageId: string, ctx: StorageContext): Promise<OperationRecord[]>;
159
+ saveOperation(operation: CreateOperationInput, ctx: StorageContext): Promise<OperationRecord>;
160
+ updateOperationStatus(id: string, status: OperationStatus, errorMessage?: string): Promise<void>;
161
+ getBackups?(operationId: string): Promise<BackupRecord[]>;
162
+ saveBackup?(backup: Omit<BackupRecord, 'createdAt'>): Promise<BackupRecord>;
163
+ deleteExpiredBackups?(): Promise<number>;
164
+ getTrashItems?(ctx: StorageContext): Promise<TrashRecord[]>;
165
+ moveToTrash?(item: Omit<TrashRecord, 'deletedAt' | 'autoDeleteAt' | 'appId' | 'userId'>, ctx: StorageContext): Promise<TrashRecord>;
166
+ restoreFromTrash?(id: string, ctx: StorageContext): Promise<TrashRecord>;
167
+ emptyExpiredTrash?(): Promise<number>;
168
+ getUserSetting(key: string, ctx: StorageContext): Promise<string | null>;
169
+ setUserSetting(key: string, value: string, ctx: StorageContext): Promise<void>;
170
+ getUserSettings(ctx: StorageContext): Promise<Record<string, string>>;
171
+ deleteUserSetting(key: string, ctx: StorageContext): Promise<void>;
172
+ saveEmbedding?(id: string, content: string, embedding: number[], metadata: {
173
+ sessionId: string;
174
+ messageId?: string;
175
+ contentType: EmbeddingRecord['contentType'];
176
+ }, ctx: StorageContext): Promise<void>;
177
+ searchSimilar?(embedding: number[], options: VectorSearchOptions, ctx: StorageContext): Promise<VectorSearchResult[]>;
178
+ close(): Promise<void>;
179
+ }
180
+ export type SqliteDatabaseFactory = (sqlitePath: string) => BetterSqlite3.Database;
181
+ export interface StorageBaseConfig {
182
+ backupRetentionDays?: number;
183
+ trashRetentionDays?: number;
184
+ }
185
+ export interface SqliteStorageConfig extends StorageBaseConfig {
186
+ type: 'sqlite';
187
+ sqlitePath: string;
188
+ sqliteFactory: SqliteDatabaseFactory;
189
+ }
190
+ export interface PostgresStorageConfig extends StorageBaseConfig {
191
+ type: 'postgres';
192
+ postgresUrl: string;
193
+ }
194
+ export type StorageConfig = SqliteStorageConfig | PostgresStorageConfig;
195
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huyooo/ai-chat-storage",
3
- "version": "0.2.45",
3
+ "version": "0.3.2",
4
4
  "description": "AI Chat 统一存储层 - SQLite",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,13 +16,17 @@
16
16
  "dist"
17
17
  ],
18
18
  "scripts": {
19
- "build": "tsup",
20
- "dev": "tsup --watch",
19
+ "build": "npm run clean && npm run build:js && npm run build:types",
20
+ "build:js": "tsdown",
21
+ "build:types": "tsc -b tsconfig.json --emitDeclarationOnly",
22
+ "dev": "tsdown --watch",
21
23
  "typecheck": "tsc --noEmit",
24
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
22
25
  "test": "vitest run",
23
26
  "test:watch": "vitest"
24
27
  },
25
28
  "dependencies": {
29
+ "@huyooo/ai-chat-types": "^0.3.2",
26
30
  "drizzle-orm": "^0.38.0",
27
31
  "postgres": "^3.4.7"
28
32
  },
@@ -36,7 +40,7 @@
36
40
  },
37
41
  "devDependencies": {
38
42
  "@types/better-sqlite3": "^7.6.11",
39
- "tsup": "^8.3.0",
43
+ "tsdown": "^0.21.0",
40
44
  "typescript": "^5.6.3",
41
45
  "vitest": "^4.0.18"
42
46
  },
@@ -1,268 +0,0 @@
1
- import e from"postgres";function s(e){return{id:e.id,appId:e.app_id,userId:e.user_id,title:e.title,model:e.model,mode:e.mode,webSearchEnabled:e.web_search_enabled,thinkingEnabled:e.thinking_enabled,hidden:e.hidden,createdAt:new Date(e.created_at),updatedAt:new Date(e.updated_at)}}function i(e){if(null===e.sequence||void 0===e.sequence)throw new Error(`消息 ${e.id} 缺少序号,数据损坏`);let s=[];if(e.images)try{const i=JSON.parse(e.images);Array.isArray(i)&&(s=i)}catch{}return{id:e.id,clientId:e.client_id||e.id,sessionId:e.session_id,appId:e.app_id,userId:e.user_id,role:e.role,content:e.content,images:s,model:e.model,mode:e.mode,webSearchEnabled:e.web_search_enabled,thinkingEnabled:e.thinking_enabled,steps:e.steps,operationIds:e.operation_ids,usage:e.usage,duration:null!=e.duration?Number(e.duration):null,sequence:(s=>{if("number"==typeof s&&Number.isFinite(s))return s;if("string"==typeof s){const e=Number(s);if(Number.isFinite(e))return e}throw new Error(`消息 ${e.id} 的序号无效: ${s}`)})(e.sequence),timestamp:(s=>{if("number"==typeof s&&Number.isFinite(s))return s;if(s instanceof Date)return s.getTime();if("string"==typeof s){const e=Date.parse(s);if(!Number.isNaN(e))return e;const i=Number(s);if(Number.isFinite(i))return i}throw new Error(`消息 ${e.id} 的时间戳无效: ${s}`)})(e.timestamp)}}function t(e){return{id:e.id,sessionId:e.session_id,messageId:e.message_id,appId:e.app_id,userId:e.user_id,command:e.command,operationType:e.operation_type,affectedFiles:e.affected_files,backupPath:e.backup_path,status:e.status,errorMessage:e.error_message,timestamp:new Date(e.timestamp)}}function a(e){return{id:e.id,operationId:e.operation_id,originalPath:e.original_path,backupPath:e.backup_path,fileSize:e.file_size,fileHash:e.file_hash,createdAt:new Date(e.created_at),expiresAt:new Date(e.expires_at)}}function n(e){return{id:e.id,sessionId:e.session_id,appId:e.app_id,userId:e.user_id,originalPath:e.original_path,trashPath:e.trash_path,deletedAt:new Date(e.deleted_at),autoDeleteAt:new Date(e.auto_delete_at)}}async function d(e,s,i,t){const{limit:a=10,threshold:n=.7,sessionId:d}=i,r=`[${s.join(",")}]`;try{return(await(e`
2
- SELECT id, content, content_type, metadata,
3
- 1 - (embedding <=> ${r}::vector) as similarity
4
- FROM embeddings
5
- WHERE (${t.appId||null}::TEXT IS NULL OR app_id = ${t.appId||null})
6
- AND (${t.userId||null}::TEXT IS NULL OR user_id = ${t.userId||null})
7
- AND (${d||null}::TEXT IS NULL OR session_id = ${d||null})
8
- AND 1 - (embedding <=> ${r}::vector) > ${n}
9
- ORDER BY embedding <=> ${r}::vector
10
- LIMIT ${a}
11
- `)).map(e=>({id:e.id,content:e.content,contentType:e.content_type,similarity:e.similarity||0,metadata:e.metadata}))}catch{return(await(e`
12
- SELECT id, content, content_type, embedding, metadata
13
- FROM embeddings
14
- WHERE (${t.appId||null}::TEXT IS NULL OR app_id = ${t.appId||null})
15
- AND (${t.userId||null}::TEXT IS NULL OR user_id = ${t.userId||null})
16
- AND (${d||null}::TEXT IS NULL OR session_id = ${d||null})
17
- `)).map(e=>{let i=[];if("string"==typeof e.embedding)try{i=JSON.parse(e.embedding.replace(/^\[|\]$/g,"").split(",").map(Number).join(","))}catch{i=e.embedding.slice(1,-1).split(",").map(Number)}else Array.isArray(e.embedding)&&(i=e.embedding);const t=function(e,s){if(!e||!s||e.length!==s.length)return 0;let i=0,t=0,a=0;for(let n=0;n<e.length;n++)i+=e[n]*s[n],t+=e[n]*e[n],a+=s[n]*s[n];return 0===t||0===a?0:i/(Math.sqrt(t)*Math.sqrt(a))}(s,i);return{id:e.id,content:e.content,contentType:e.content_type,similarity:t,metadata:e.metadata}}).filter(e=>e.similarity>=n).sort((e,s)=>s.similarity-e.similarity).slice(0,a)}}var r=class{sql;config;initialized=!1;constructor(s,i={type:"postgres"}){this.sql=e(s),this.config=i}async ensureInitialized(){this.initialized||(await async function(e){try{await(e`CREATE EXTENSION IF NOT EXISTS vector`)}catch{}await(e`
18
- CREATE TABLE IF NOT EXISTS sessions (
19
- id TEXT PRIMARY KEY,
20
- app_id TEXT,
21
- user_id TEXT,
22
- title TEXT NOT NULL,
23
- model TEXT NOT NULL,
24
- mode TEXT NOT NULL,
25
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
26
- updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
27
- )
28
- `),await(e`
29
- CREATE TABLE IF NOT EXISTS messages (
30
- id TEXT PRIMARY KEY,
31
- session_id TEXT NOT NULL,
32
- app_id TEXT,
33
- user_id TEXT,
34
- role TEXT NOT NULL,
35
- content TEXT NOT NULL,
36
- images TEXT,
37
- model TEXT,
38
- mode TEXT,
39
- web_search_enabled BOOLEAN,
40
- thinking_enabled BOOLEAN,
41
- steps TEXT,
42
- operation_ids TEXT,
43
- sequence INTEGER,
44
- timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
45
- )
46
- `);try{await(e`ALTER TABLE messages ADD COLUMN IF NOT EXISTS sequence INTEGER`)}catch{}try{await(e`ALTER TABLE messages ADD COLUMN IF NOT EXISTS images TEXT`)}catch{}try{await(e`ALTER TABLE messages ADD COLUMN IF NOT EXISTS usage TEXT`)}catch{}try{await(e`ALTER TABLE messages ADD COLUMN IF NOT EXISTS duration INTEGER`)}catch{}try{await(e`
47
- UPDATE messages
48
- SET sequence = sub.rank
49
- FROM (
50
- SELECT id, ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY timestamp, id) as rank
51
- FROM messages
52
- WHERE sequence IS NULL
53
- ) sub
54
- WHERE messages.id = sub.id
55
- `),await(e`
56
- UPDATE messages
57
- SET sequence = (
58
- SELECT COALESCE(MAX(sequence), 0) + 1
59
- FROM messages m2
60
- WHERE m2.session_id = messages.session_id
61
- )
62
- WHERE sequence IS NULL
63
- `)}catch{}try{await(e`CREATE INDEX IF NOT EXISTS idx_messages_sequence ON messages(session_id, sequence)`)}catch{}await(e`
64
- CREATE TABLE IF NOT EXISTS operations (
65
- id TEXT PRIMARY KEY,
66
- session_id TEXT NOT NULL,
67
- message_id TEXT,
68
- app_id TEXT,
69
- user_id TEXT,
70
- command TEXT NOT NULL,
71
- operation_type TEXT NOT NULL,
72
- affected_files TEXT NOT NULL,
73
- backup_path TEXT,
74
- status TEXT NOT NULL DEFAULT 'pending',
75
- error_message TEXT,
76
- timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
77
- )
78
- `),await(e`
79
- CREATE TABLE IF NOT EXISTS backups (
80
- id TEXT PRIMARY KEY,
81
- operation_id TEXT NOT NULL,
82
- original_path TEXT NOT NULL,
83
- backup_path TEXT NOT NULL,
84
- file_size INTEGER NOT NULL,
85
- file_hash TEXT NOT NULL,
86
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
87
- expires_at TIMESTAMPTZ NOT NULL
88
- )
89
- `),await(e`
90
- CREATE TABLE IF NOT EXISTS trash (
91
- id TEXT PRIMARY KEY,
92
- session_id TEXT NOT NULL,
93
- app_id TEXT,
94
- user_id TEXT,
95
- original_path TEXT NOT NULL,
96
- trash_path TEXT NOT NULL,
97
- deleted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
98
- auto_delete_at TIMESTAMPTZ NOT NULL
99
- )
100
- `),await(e`
101
- CREATE TABLE IF NOT EXISTS user_settings (
102
- id TEXT PRIMARY KEY,
103
- app_id TEXT,
104
- user_id TEXT,
105
- key TEXT NOT NULL,
106
- value TEXT NOT NULL,
107
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
108
- updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
109
- UNIQUE(app_id, user_id, key)
110
- )
111
- `),await(e`
112
- CREATE INDEX IF NOT EXISTS idx_user_settings_tenant ON user_settings(app_id, user_id);
113
- `),await(e`
114
- CREATE INDEX IF NOT EXISTS idx_user_settings_key ON user_settings(key);
115
- `);try{await(e`
116
- CREATE TABLE IF NOT EXISTS embeddings (
117
- id TEXT PRIMARY KEY,
118
- session_id TEXT NOT NULL,
119
- message_id TEXT,
120
- app_id TEXT,
121
- user_id TEXT,
122
- content TEXT NOT NULL,
123
- content_type TEXT NOT NULL,
124
- embedding vector(1536),
125
- metadata JSONB,
126
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
127
- )
128
- `)}catch{await(e`
129
- CREATE TABLE IF NOT EXISTS embeddings (
130
- id TEXT PRIMARY KEY,
131
- session_id TEXT NOT NULL,
132
- message_id TEXT,
133
- app_id TEXT,
134
- user_id TEXT,
135
- content TEXT NOT NULL,
136
- content_type TEXT NOT NULL,
137
- embedding TEXT,
138
- metadata JSONB,
139
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
140
- )
141
- `)}await(e`CREATE INDEX IF NOT EXISTS idx_sessions_tenant ON sessions(app_id, user_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC)`),await(e`CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_messages_tenant ON messages(app_id, user_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_operations_session ON operations(session_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_operations_message ON operations(message_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_backups_operation ON backups(operation_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_backups_expires ON backups(expires_at)`),await(e`CREATE INDEX IF NOT EXISTS idx_trash_tenant ON trash(app_id, user_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_trash_auto_delete ON trash(auto_delete_at)`),await(e`CREATE INDEX IF NOT EXISTS idx_embeddings_session ON embeddings(session_id)`),await(e`CREATE INDEX IF NOT EXISTS idx_embeddings_tenant ON embeddings(app_id, user_id)`);try{await(e`CREATE INDEX IF NOT EXISTS idx_embeddings_vector ON embeddings USING hnsw (embedding vector_cosine_ops)`)}catch{}}(this.sql),this.initialized=!0)}async getSessions(e){return await this.ensureInitialized(),async function(e,i){return(await(e`
142
- SELECT id, app_id, user_id, title, model, mode, web_search_enabled, thinking_enabled, hidden, created_at, updated_at
143
- FROM sessions
144
- WHERE (${i.appId||null}::TEXT IS NULL OR app_id = ${i.appId||null})
145
- AND (${i.userId||null}::TEXT IS NULL OR user_id = ${i.userId||null})
146
- ORDER BY updated_at DESC
147
- `)).map(s)}(this.sql,e)}async getSession(e,i){return await this.ensureInitialized(),async function(e,i,t){const a=await(e`
148
- SELECT id, app_id, user_id, title, model, mode, web_search_enabled, thinking_enabled, hidden, created_at, updated_at
149
- FROM sessions
150
- WHERE id = ${i}
151
- AND (${t.appId||null}::TEXT IS NULL OR app_id = ${t.appId||null})
152
- AND (${t.userId||null}::TEXT IS NULL OR user_id = ${t.userId||null})
153
- `);return a[0]?s(a[0]):null}(this.sql,e,i)}async createSession(e,s){return await this.ensureInitialized(),async function(e,s,i){const t=new Date,a=s.hidden??!1;return await(e`
154
- INSERT INTO sessions (id, app_id, user_id, title, model, mode, web_search_enabled, thinking_enabled, hidden, created_at, updated_at)
155
- VALUES (${s.id}, ${i.appId||null}, ${i.userId||null}, ${s.title}, ${s.model}, ${s.mode}, ${s.webSearchEnabled}, ${s.thinkingEnabled}, ${a}, ${t}, ${t})
156
- `),{id:s.id,appId:i.appId||null,userId:i.userId||null,title:s.title,model:s.model,mode:s.mode,webSearchEnabled:s.webSearchEnabled,thinkingEnabled:s.thinkingEnabled,hidden:a,createdAt:t,updatedAt:t}}(this.sql,e,s)}async updateSession(e,s,i){await this.ensureInitialized(),await async function(e,s,i,t){const a=new Date;await(e`
157
- UPDATE sessions
158
- SET updated_at = ${a},
159
- title = COALESCE(${i.title??null}, title),
160
- model = COALESCE(${i.model??null}, model),
161
- mode = COALESCE(${i.mode??null}, mode),
162
- web_search_enabled = COALESCE(${i.webSearchEnabled??null}, web_search_enabled),
163
- thinking_enabled = COALESCE(${i.thinkingEnabled??null}, thinking_enabled),
164
- hidden = COALESCE(${i.hidden??null}, hidden)
165
- WHERE id = ${s}
166
- AND (${t.appId||null}::TEXT IS NULL OR app_id = ${t.appId||null})
167
- AND (${t.userId||null}::TEXT IS NULL OR user_id = ${t.userId||null})
168
- `)}(this.sql,e,s,i)}async deleteSession(e,s){await this.ensureInitialized(),await async function(e,s){await(e`DELETE FROM messages WHERE session_id = ${s}`)}(this.sql,e),await async function(e,s){await(e`DELETE FROM operations WHERE session_id = ${s}`)}(this.sql,e),await async function(e,s){await(e`DELETE FROM embeddings WHERE session_id = ${s}`)}(this.sql,e),await async function(e,s,i){await(e`
169
- DELETE FROM sessions
170
- WHERE id = ${s}
171
- AND (${i.appId||null}::TEXT IS NULL OR app_id = ${i.appId||null})
172
- AND (${i.userId||null}::TEXT IS NULL OR user_id = ${i.userId||null})
173
- `)}(this.sql,e,s)}async getMessages(e,s){await this.ensureInitialized();return await this.getSession(e,s)?async function(e,s){return(await(e`
174
- SELECT id, client_id, session_id, app_id, user_id, role, content, images, model, mode,
175
- web_search_enabled, thinking_enabled, steps, operation_ids, usage, duration, sequence, timestamp
176
- FROM messages
177
- WHERE session_id = ${s}
178
- ORDER BY sequence NULLS LAST, timestamp
179
- `)).map(i)}(this.sql,e):[]}async getMessage(e,s){return await this.ensureInitialized(),async function(e,s,t){const a=await(e`
180
- SELECT id, client_id, session_id, app_id, user_id, role, content, images, model, mode,
181
- web_search_enabled, thinking_enabled, steps, operation_ids, usage, duration, sequence, timestamp
182
- FROM messages
183
- WHERE id = ${s}
184
- AND (${t.appId||null}::TEXT IS NULL OR app_id = ${t.appId||null})
185
- AND (${t.userId||null}::TEXT IS NULL OR user_id = ${t.userId||null})
186
- `);return a[0]?i(a[0]):null}(this.sql,e,s)}async saveMessage(e,s){return await this.ensureInitialized(),async function(e,s,i){const t=Date.now(),a=new Date(t),n=await async function(e,s){const i=await(e`
187
- SELECT MAX(sequence) as max_seq
188
- FROM messages
189
- WHERE session_id = ${s}
190
- `),t=i[0]?.max_seq;return null!=t?t:0}(e,s.sessionId),d=n+1,r=s.images&&s.images.length>0?JSON.stringify(s.images):null,u=s.clientId||s.id;return await(e`
191
- INSERT INTO messages (id, client_id, session_id, app_id, user_id, role, content, images, model, mode, web_search_enabled, thinking_enabled, steps, operation_ids, sequence, timestamp)
192
- VALUES (${s.id}, ${u}, ${s.sessionId}, ${i.appId||null}, ${i.userId||null}, ${s.role}, ${s.content}, ${r}, ${s.model}, ${s.mode}, ${s.webSearchEnabled}, ${s.thinkingEnabled}, ${s.steps}, ${s.operationIds}, ${d}, ${a})
193
- `),await(e`UPDATE sessions SET updated_at = ${a} WHERE id = ${s.sessionId}`),{id:s.id,clientId:u,sessionId:s.sessionId,appId:i.appId||null,userId:i.userId||null,role:s.role,content:s.content,images:s.images||[],model:s.model,mode:s.mode,webSearchEnabled:s.webSearchEnabled,thinkingEnabled:s.thinkingEnabled,steps:s.steps,operationIds:s.operationIds,sequence:d,timestamp:t}}(this.sql,e,s)}async updateMessage(e,s,i){await this.ensureInitialized(),await async function(e,s,i,t){const a=[],n=[];let d=1;if(void 0!==i.content&&(a.push("content = $"+d++),n.push(i.content)),void 0!==i.steps&&(a.push("steps = $"+d++),n.push(i.steps)),void 0!==i.operationIds&&(a.push("operation_ids = $"+d++),n.push(i.operationIds)),void 0!==i.usage&&(a.push("usage = $"+d++),n.push(i.usage)),void 0!==i.duration&&(a.push("duration = $"+d++),n.push(i.duration)),0===a.length)return;const r=`WHERE id = $${d++}${t.appId?" AND app_id = $"+d++:""}${t.userId?" AND user_id = $"+d++:""}`;n.push(s),t.appId&&n.push(t.appId),t.userId&&n.push(t.userId),await e.unsafe(`UPDATE messages SET ${a.join(", ")} ${r}`,n)}(this.sql,e,s,i)}async deleteMessagesAfter(e,s,i){await this.ensureInitialized();await this.getSession(e,i)&&await async function(e,s,i){await(e`
194
- DELETE FROM messages
195
- WHERE session_id = ${s}
196
- AND timestamp > ${i}
197
- `)}(this.sql,e,s)}async deleteMessagesAfterMessageId(e,s,i){await this.ensureInitialized();if(!await this.getSession(e,i))return;const t=await this.getMessage(s,i);if(t&&t.sessionId===e){if(null===t.sequence||void 0===t.sequence)throw new Error(`消息 ${s} 缺少序号,无法删除后续消息`);await async function(e,s,i,t){if(null==t)throw new Error(`消息 ${i} 缺少序号,无法删除后续消息`);await(e`
198
- DELETE FROM messages
199
- WHERE session_id = ${s}
200
- AND sequence > ${t}
201
- `)}(this.sql,e,s,t.sequence)}}async getOperations(e,s){await this.ensureInitialized();return await this.getSession(e,s)?async function(e,s){return(await(e`
202
- SELECT id, session_id, message_id, app_id, user_id, command, operation_type,
203
- affected_files, backup_path, status, error_message, timestamp
204
- FROM operations
205
- WHERE session_id = ${s}
206
- ORDER BY timestamp
207
- `)).map(t)}(this.sql,e):[]}async getOperationsByMessage(e,s){return await this.ensureInitialized(),async function(e,s,i){return(await(e`
208
- SELECT id, session_id, message_id, app_id, user_id, command, operation_type,
209
- affected_files, backup_path, status, error_message, timestamp
210
- FROM operations
211
- WHERE message_id = ${s}
212
- AND (${i.appId||null}::TEXT IS NULL OR app_id = ${i.appId||null})
213
- AND (${i.userId||null}::TEXT IS NULL OR user_id = ${i.userId||null})
214
- `)).map(t)}(this.sql,e,s)}async saveOperation(e,s){return await this.ensureInitialized(),async function(e,s,i){const t=new Date,a=s.status||"pending";return await(e`
215
- INSERT INTO operations (id, session_id, message_id, app_id, user_id, command, operation_type, affected_files, backup_path, status, timestamp)
216
- VALUES (${s.id}, ${s.sessionId}, ${s.messageId||null}, ${i.appId||null}, ${i.userId||null}, ${s.command}, ${s.operationType}, ${s.affectedFiles}, ${s.backupPath||null}, ${a}, ${t})
217
- `),{id:s.id,sessionId:s.sessionId,messageId:s.messageId,appId:i.appId||null,userId:i.userId||null,command:s.command,operationType:s.operationType,affectedFiles:s.affectedFiles,backupPath:s.backupPath,status:a,errorMessage:null,timestamp:t}}(this.sql,e,s)}async updateOperationStatus(e,s,i){await this.ensureInitialized(),await async function(e,s,i,t){await(e`
218
- UPDATE operations
219
- SET status = ${i}, error_message = ${t||null}
220
- WHERE id = ${s}
221
- `)}(this.sql,e,s,i)}async getBackups(e){return await this.ensureInitialized(),async function(e,s){return(await(e`
222
- SELECT id, operation_id, original_path, backup_path, file_size, file_hash, created_at, expires_at
223
- FROM backups
224
- WHERE operation_id = ${s}
225
- `)).map(a)}(this.sql,e)}async saveBackup(e){return await this.ensureInitialized(),async function(e,s){const i=new Date;return await(e`
226
- INSERT INTO backups (id, operation_id, original_path, backup_path, file_size, file_hash, created_at, expires_at)
227
- VALUES (${s.id}, ${s.operationId}, ${s.originalPath}, ${s.backupPath}, ${s.fileSize}, ${s.fileHash}, ${i}, ${s.expiresAt})
228
- `),{...s,createdAt:i}}(this.sql,e)}async deleteExpiredBackups(){return await this.ensureInitialized(),async function(e){return(await(e`DELETE FROM backups WHERE expires_at < NOW()`)).count}(this.sql)}async getTrashItems(e){return await this.ensureInitialized(),async function(e,s){return(await(e`
229
- SELECT id, session_id, app_id, user_id, original_path, trash_path, deleted_at, auto_delete_at
230
- FROM trash
231
- WHERE (${s.appId||null}::TEXT IS NULL OR app_id = ${s.appId||null})
232
- AND (${s.userId||null}::TEXT IS NULL OR user_id = ${s.userId||null})
233
- ORDER BY deleted_at DESC
234
- `)).map(n)}(this.sql,e)}async moveToTrash(e,s){return await this.ensureInitialized(),async function(e,s,i,t){const a=new Date,n=t.trashRetentionDays||30,d=new Date(a.getTime()+24*n*60*60*1e3);return await(e`
235
- INSERT INTO trash (id, session_id, app_id, user_id, original_path, trash_path, deleted_at, auto_delete_at)
236
- VALUES (${s.id}, ${s.sessionId}, ${i.appId||null}, ${i.userId||null}, ${s.originalPath}, ${s.trashPath}, ${a}, ${d})
237
- `),{...s,appId:i.appId||null,userId:i.userId||null,deletedAt:a,autoDeleteAt:d}}(this.sql,e,s,this.config)}async restoreFromTrash(e,s){return await this.ensureInitialized(),async function(e,s,i){const t=await(e`
238
- SELECT id, session_id, app_id, user_id, original_path, trash_path, deleted_at, auto_delete_at
239
- FROM trash
240
- WHERE id = ${s}
241
- AND (${i.appId||null}::TEXT IS NULL OR app_id = ${i.appId||null})
242
- AND (${i.userId||null}::TEXT IS NULL OR user_id = ${i.userId||null})
243
- `);if(!t[0])throw new Error("回收站记录不存在");return await(e`DELETE FROM trash WHERE id = ${s}`),n(t[0])}(this.sql,e,s)}async emptyExpiredTrash(){return await this.ensureInitialized(),async function(e){return(await(e`DELETE FROM trash WHERE auto_delete_at < NOW()`)).count}(this.sql)}async saveEmbedding(e,s,i,t,a){await this.ensureInitialized(),await async function(e,s,i,t,a,n){const d=`[${t.join(",")}]`;try{await(e`
244
- INSERT INTO embeddings (id, session_id, message_id, app_id, user_id, content, content_type, embedding, metadata, created_at)
245
- VALUES (${s}, ${a.sessionId}, ${a.messageId||null}, ${n.appId||null}, ${n.userId||null}, ${i}, ${a.contentType}, ${d}::vector, ${JSON.stringify(a)}, NOW())
246
- `)}catch{await(e`
247
- INSERT INTO embeddings (id, session_id, message_id, app_id, user_id, content, content_type, embedding, metadata, created_at)
248
- VALUES (${s}, ${a.sessionId}, ${a.messageId||null}, ${n.appId||null}, ${n.userId||null}, ${i}, ${a.contentType}, ${d}, ${JSON.stringify(a)}, NOW())
249
- `)}}(this.sql,e,s,i,t,a)}async searchSimilar(e,s,i){return await this.ensureInitialized(),d(this.sql,e,s,i)}async getUserSetting(e,s){await this.ensureInitialized();const i=`${s.appId||"default"}_${s.userId||"default"}_${e}`,t=await(this.sql`
250
- SELECT value FROM user_settings
251
- WHERE id = ${i}
252
- LIMIT 1
253
- `);return t.length>0?t[0].value:null}async setUserSetting(e,s,i){await this.ensureInitialized();const t=`${i.appId||"default"}_${i.userId||"default"}_${e}`;await(this.sql`
254
- INSERT INTO user_settings (id, app_id, user_id, key, value, created_at, updated_at)
255
- VALUES (${t}, ${i.appId||null}, ${i.userId||null}, ${e}, ${s}, NOW(), NOW())
256
- ON CONFLICT (id) DO UPDATE SET
257
- value = ${s},
258
- updated_at = NOW()
259
- `)}async getUserSettings(e){await this.ensureInitialized();const s=await(this.sql`
260
- SELECT key, value FROM user_settings
261
- WHERE app_id IS NOT DISTINCT FROM ${e.appId||null}
262
- AND user_id IS NOT DISTINCT FROM ${e.userId||null}
263
- `),i={};for(const e of s)i[e.key]=e.value;return i}async deleteUserSetting(e,s){await this.ensureInitialized(),await(this.sql`
264
- DELETE FROM user_settings
265
- WHERE key = ${e}
266
- AND app_id IS NOT DISTINCT FROM ${s.appId||null}
267
- AND user_id IS NOT DISTINCT FROM ${s.userId||null}
268
- `)}async close(){await this.sql.end()}};export{r as PostgresAdapter};
@@ -1 +0,0 @@
1
- import{drizzle as e}from"drizzle-orm/better-sqlite3";import s from"better-sqlite3";import{sqliteTable as t,text as n,integer as i,index as a}from"drizzle-orm/sqlite-core";var d=t("sessions",{id:n("id").primaryKey(),appId:n("app_id"),userId:n("user_id"),title:n("title").notNull(),model:n("model").notNull(),mode:n("mode").notNull(),webSearchEnabled:i("web_search_enabled",{mode:"boolean"}).notNull().default(!0),thinkingEnabled:i("thinking_enabled",{mode:"boolean"}).notNull().default(!0),hidden:i("hidden",{mode:"boolean"}).notNull().default(!1),createdAt:i("created_at",{mode:"timestamp"}).notNull(),updatedAt:i("updated_at",{mode:"timestamp"}).notNull()},e=>[a("idx_sessions_tenant").on(e.appId,e.userId),a("idx_sessions_updated").on(e.updatedAt)]),r=t("messages",{id:n("id").primaryKey(),clientId:n("client_id"),sessionId:n("session_id").notNull(),appId:n("app_id"),userId:n("user_id"),role:n("role").notNull(),content:n("content").notNull(),images:n("images"),model:n("model"),mode:n("mode"),webSearchEnabled:i("web_search_enabled",{mode:"boolean"}),thinkingEnabled:i("thinking_enabled",{mode:"boolean"}),steps:n("steps"),operationIds:n("operation_ids"),usage:n("usage"),duration:i("duration"),sequence:i("sequence").notNull(),timestamp:i("timestamp",{mode:"timestamp"}).notNull()},e=>[a("idx_messages_session").on(e.sessionId),a("idx_messages_tenant").on(e.appId,e.userId),a("idx_messages_sequence").on(e.sessionId,e.sequence)]),o=t("operations",{id:n("id").primaryKey(),sessionId:n("session_id").notNull(),messageId:n("message_id"),appId:n("app_id"),userId:n("user_id"),command:n("command").notNull(),operationType:n("operation_type").notNull(),affectedFiles:n("affected_files").notNull(),backupPath:n("backup_path"),status:n("status").notNull().default("pending"),errorMessage:n("error_message"),timestamp:i("timestamp",{mode:"timestamp"}).notNull()},e=>[a("idx_operations_session").on(e.sessionId),a("idx_operations_message").on(e.messageId),a("idx_operations_tenant").on(e.appId,e.userId)]),u=t("backups",{id:n("id").primaryKey(),operationId:n("operation_id").notNull(),originalPath:n("original_path").notNull(),backupPath:n("backup_path").notNull(),fileSize:i("file_size").notNull(),fileHash:n("file_hash").notNull(),createdAt:i("created_at",{mode:"timestamp"}).notNull(),expiresAt:i("expires_at",{mode:"timestamp"}).notNull()},e=>[a("idx_backups_operation").on(e.operationId),a("idx_backups_expires").on(e.expiresAt)]),l=t("trash",{id:n("id").primaryKey(),sessionId:n("session_id").notNull(),appId:n("app_id"),userId:n("user_id"),originalPath:n("original_path").notNull(),trashPath:n("trash_path").notNull(),deletedAt:i("deleted_at",{mode:"timestamp"}).notNull(),autoDeleteAt:i("auto_delete_at",{mode:"timestamp"}).notNull()},e=>[a("idx_trash_tenant").on(e.appId,e.userId),a("idx_trash_auto_delete").on(e.autoDeleteAt)]),p=t("embeddings",{id:n("id").primaryKey(),sessionId:n("session_id").notNull(),messageId:n("message_id"),appId:n("app_id"),userId:n("user_id"),content:n("content").notNull(),contentType:n("content_type").notNull(),embedding:n("embedding"),metadata:n("metadata"),createdAt:i("created_at",{mode:"timestamp"}).notNull()},e=>[a("idx_embeddings_session").on(e.sessionId),a("idx_embeddings_tenant").on(e.appId,e.userId)]);import{eq as c,and as T}from"drizzle-orm";function E(e){const s=[];return e.appId&&s.push(c(d.appId,e.appId)),e.userId&&s.push(c(d.userId,e.userId)),s.length>0?T(...s):void 0}function m(e){const s=[];return e.appId&&s.push(c(r.appId,e.appId)),e.userId&&s.push(c(r.userId,e.userId)),s.length>0?T(...s):void 0}function I(e){const s=[];return e.appId&&s.push(c(l.appId,e.appId)),e.userId&&s.push(c(l.userId,e.userId)),s.length>0?T(...s):void 0}import{eq as h,and as N,desc as _}from"drizzle-orm";function g(e){return{id:e.id,appId:e.appId,userId:e.userId,title:e.title,model:e.model,mode:e.mode,webSearchEnabled:e.webSearchEnabled,thinkingEnabled:e.thinkingEnabled,hidden:e.hidden,createdAt:e.createdAt,updatedAt:e.updatedAt}}import{eq as b,and as L,gt as A,max as f}from"drizzle-orm";function O(e){if(null===e.sequence||void 0===e.sequence)throw new Error(`消息 ${e.id} 缺少序号,数据损坏`);let s=[];if(e.images)try{const t=JSON.parse(e.images);Array.isArray(t)&&(s=t)}catch{}return{id:e.id,clientId:e.clientId||e.id,sessionId:e.sessionId,appId:e.appId,userId:e.userId,role:e.role,content:e.content,images:s,model:e.model,mode:e.mode,webSearchEnabled:e.webSearchEnabled,thinkingEnabled:e.thinkingEnabled,steps:e.steps,operationIds:e.operationIds,usage:e.usage,duration:e.duration,sequence:(s=>{if("number"==typeof s&&Number.isFinite(s))return s;if("string"==typeof s){const e=Number(s);if(Number.isFinite(e))return e}throw new Error(`消息 ${e.id} 的序号无效: ${s}`)})(e.sequence),timestamp:(s=>{if("number"==typeof s&&Number.isFinite(s))return s;if(s instanceof Date)return s.getTime();if("string"==typeof s){const e=Date.parse(s);if(!Number.isNaN(e))return e;const t=Number(s);if(Number.isFinite(t))return t}throw new Error(`消息 ${e.id} 的时间戳无效: ${s}`)})(e.timestamp)}}function S(e,s,t){const n=Date.now(),i=function(e,s){const t=e.select({maxSeq:f(r.sequence)}).from(r).where(b(r.sessionId,s)).get();return t?.maxSeq??0}(e,s.sessionId)+1,a={id:s.id,clientId:s.clientId||s.id,sessionId:s.sessionId,appId:t.appId||null,userId:t.userId||null,role:s.role,content:s.content,images:s.images||[],model:s.model,mode:s.mode,webSearchEnabled:s.webSearchEnabled,thinkingEnabled:s.thinkingEnabled,steps:s.steps,operationIds:s.operationIds,sequence:i,timestamp:n};return e.insert(r).values({id:a.id,clientId:a.clientId,sessionId:a.sessionId,appId:a.appId,userId:a.userId,role:a.role,content:a.content,images:a.images.length>0?JSON.stringify(a.images):null,model:a.model,mode:a.mode,webSearchEnabled:a.webSearchEnabled,thinkingEnabled:a.thinkingEnabled,steps:a.steps,operationIds:a.operationIds,sequence:a.sequence,timestamp:new Date(a.timestamp)}).run(),e.update(d).set({updatedAt:new Date(n)}).where(b(d.id,s.sessionId)).run(),a}import{eq as y,and as R}from"drizzle-orm";function X(e){return{id:e.id,sessionId:e.sessionId,messageId:e.messageId,appId:e.appId,userId:e.userId,command:e.command,operationType:e.operationType,affectedFiles:e.affectedFiles,backupPath:e.backupPath,status:e.status,errorMessage:e.errorMessage,timestamp:e.timestamp}}function D(e,s,t){const n=function(e){const s=[];return e.appId&&s.push(c(o.appId,e.appId)),e.userId&&s.push(c(o.userId,e.userId)),s.length>0?T(...s):void 0}(t),i=n?R(y(o.messageId,s),n):y(o.messageId,s);return e.select().from(o).where(i).all().map(X)}import{eq as w,lt as U}from"drizzle-orm";function x(e){return{id:e.id,operationId:e.operationId,originalPath:e.originalPath,backupPath:e.backupPath,fileSize:e.fileSize,fileHash:e.fileHash,createdAt:e.createdAt,expiresAt:e.expiresAt}}import{eq as k,and as q,desc as F,lt as M}from"drizzle-orm";function C(e){return{id:e.id,sessionId:e.sessionId,appId:e.appId,userId:e.userId,originalPath:e.originalPath,trashPath:e.trashPath,deletedAt:e.deletedAt,autoDeleteAt:e.autoDeleteAt}}import{eq as v,and as P}from"drizzle-orm";function B(e,s,t,n){const{limit:i=10,threshold:a=.7,sessionId:d}=t,r=[];n.appId&&r.push(v(p.appId,n.appId)),n.userId&&r.push(v(p.userId,n.userId)),d&&r.push(v(p.sessionId,d));return e.select().from(p).where(r.length>0?P(...r):void 0).all().map(e=>{const t=e.embedding?JSON.parse(e.embedding):[],n=function(e,s){if(e.length!==s.length)return 0;let t=0,n=0,i=0;for(let a=0;a<e.length;a++)t+=e[a]*s[a],n+=e[a]*e[a],i+=s[a]*s[a];return 0===n||0===i?0:t/(Math.sqrt(n)*Math.sqrt(i))}(s,t);return{id:e.id,content:e.content,contentType:e.contentType,similarity:n,metadata:e.metadata?JSON.parse(e.metadata):void 0}}).filter(e=>e.similarity>=a).sort((e,s)=>s.similarity-e.similarity).slice(0,i)}var G=class{sqlite;db;config;get sqliteInstance(){return this.sqlite}constructor(t,n={type:"sqlite"}){this.sqlite=new s(t),this.db=e(this.sqlite),this.config=n,function(e){e.exec("\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n app_id TEXT,\n user_id TEXT,\n title TEXT NOT NULL,\n model TEXT NOT NULL,\n mode TEXT NOT NULL,\n web_search_enabled INTEGER NOT NULL DEFAULT 1,\n thinking_enabled INTEGER NOT NULL DEFAULT 1,\n hidden INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n client_id TEXT,\n session_id TEXT NOT NULL,\n app_id TEXT,\n user_id TEXT,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n images TEXT,\n model TEXT,\n mode TEXT,\n web_search_enabled INTEGER,\n thinking_enabled INTEGER,\n steps TEXT,\n operation_ids TEXT,\n usage TEXT,\n duration INTEGER,\n sequence INTEGER,\n timestamp INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS operations (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n message_id TEXT,\n app_id TEXT,\n user_id TEXT,\n command TEXT NOT NULL,\n operation_type TEXT NOT NULL,\n affected_files TEXT NOT NULL,\n backup_path TEXT,\n status TEXT NOT NULL DEFAULT 'pending',\n error_message TEXT,\n timestamp INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS backups (\n id TEXT PRIMARY KEY,\n operation_id TEXT NOT NULL,\n original_path TEXT NOT NULL,\n backup_path TEXT NOT NULL,\n file_size INTEGER NOT NULL,\n file_hash TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS trash (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n app_id TEXT,\n user_id TEXT,\n original_path TEXT NOT NULL,\n trash_path TEXT NOT NULL,\n deleted_at INTEGER NOT NULL,\n auto_delete_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS embeddings (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n message_id TEXT,\n app_id TEXT,\n user_id TEXT,\n content TEXT NOT NULL,\n content_type TEXT NOT NULL,\n embedding TEXT,\n metadata TEXT,\n created_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS user_settings (\n id TEXT PRIMARY KEY,\n app_id TEXT,\n user_id TEXT,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n UNIQUE(app_id, user_id, key)\n );\n\n -- 索引\n CREATE INDEX IF NOT EXISTS idx_sessions_tenant ON sessions(app_id, user_id);\n CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at);\n CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);\n CREATE INDEX IF NOT EXISTS idx_messages_tenant ON messages(app_id, user_id);\n CREATE INDEX IF NOT EXISTS idx_operations_session ON operations(session_id);\n CREATE INDEX IF NOT EXISTS idx_operations_message ON operations(message_id);\n CREATE INDEX IF NOT EXISTS idx_backups_operation ON backups(operation_id);\n CREATE INDEX IF NOT EXISTS idx_backups_expires ON backups(expires_at);\n CREATE INDEX IF NOT EXISTS idx_trash_tenant ON trash(app_id, user_id);\n CREATE INDEX IF NOT EXISTS idx_trash_auto_delete ON trash(auto_delete_at);\n CREATE INDEX IF NOT EXISTS idx_embeddings_session ON embeddings(session_id);\n CREATE INDEX IF NOT EXISTS idx_user_settings_tenant ON user_settings(app_id, user_id);\n CREATE INDEX IF NOT EXISTS idx_user_settings_key ON user_settings(key);\n ");try{e.exec("ALTER TABLE messages ADD COLUMN client_id TEXT")}catch{}try{e.exec("ALTER TABLE sessions ADD COLUMN web_search_enabled INTEGER NOT NULL DEFAULT 1")}catch{}try{e.exec("ALTER TABLE sessions ADD COLUMN thinking_enabled INTEGER NOT NULL DEFAULT 1")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN model TEXT")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN mode TEXT")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN web_search_enabled INTEGER")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN thinking_enabled INTEGER")}catch{}try{e.exec("ALTER TABLE sessions ADD COLUMN hidden INTEGER NOT NULL DEFAULT 0")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN steps TEXT")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN sequence INTEGER")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN images TEXT")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN usage TEXT")}catch{}try{e.exec("ALTER TABLE messages ADD COLUMN duration INTEGER")}catch{}try{e.exec("\n UPDATE messages\n SET sequence = (\n SELECT COUNT(*) + 1\n FROM messages m2\n WHERE m2.session_id = messages.session_id\n AND (m2.timestamp < messages.timestamp\n OR (m2.timestamp = messages.timestamp AND m2.id < messages.id))\n )\n WHERE sequence IS NULL\n ")}catch{}try{e.exec("\n UPDATE messages\n SET sequence = (\n SELECT COUNT(*) + 1\n FROM messages m2\n WHERE m2.session_id = messages.session_id\n AND (m2.timestamp < messages.timestamp\n OR (m2.timestamp = messages.timestamp AND m2.id < messages.id))\n )\n WHERE sequence IS NULL\n "),e.exec("\n UPDATE messages\n SET sequence = (\n SELECT COALESCE(MAX(sequence), 0) + 1\n FROM messages m2\n WHERE m2.session_id = messages.session_id\n )\n WHERE sequence IS NULL\n ")}catch{}try{e.exec("CREATE INDEX IF NOT EXISTS idx_messages_sequence ON messages(session_id, sequence)")}catch{}}(this.sqlite)}async getSessions(e){return function(e,s){const t=E(s);return e.select().from(d).where(t).orderBy(_(d.updatedAt)).all().map(g)}(this.db,e)}async getSession(e,s){return function(e,s,t){const n=E(t),i=n?N(h(d.id,s),n):h(d.id,s),a=e.select().from(d).where(i).get();return a?g(a):null}(this.db,e,s)}async createSession(e,s){return function(e,s,t){const n=new Date,i={id:s.id,appId:t.appId||null,userId:t.userId||null,title:s.title,model:s.model,mode:s.mode,webSearchEnabled:s.webSearchEnabled,thinkingEnabled:s.thinkingEnabled,hidden:s.hidden??!1,createdAt:n,updatedAt:n};return e.insert(d).values({id:i.id,appId:i.appId,userId:i.userId,title:i.title,model:i.model,mode:i.mode,webSearchEnabled:i.webSearchEnabled,thinkingEnabled:i.thinkingEnabled,hidden:i.hidden,createdAt:i.createdAt,updatedAt:i.updatedAt}).run(),i}(this.db,e,s)}async updateSession(e,s,t){!function(e,s,t,n){const i=E(n),a=i?N(h(d.id,s),i):h(d.id,s),r={updatedAt:new Date};void 0!==t.title&&(r.title=t.title),void 0!==t.model&&(r.model=t.model),void 0!==t.mode&&(r.mode=t.mode),void 0!==t.webSearchEnabled&&(r.webSearchEnabled=t.webSearchEnabled),void 0!==t.thinkingEnabled&&(r.thinkingEnabled=t.thinkingEnabled),void 0!==t.hidden&&(r.hidden=t.hidden),e.update(d).set(r).where(a).run()}(this.db,e,s,t)}async deleteSession(e,s){var t,n;t=this.db,n=e,t.delete(r).where(b(r.sessionId,n)).run(),function(e,s){e.delete(o).where(y(o.sessionId,s)).run()}(this.db,e),function(e,s){e.delete(p).where(v(p.sessionId,s)).run()}(this.db,e),function(e,s,t){const n=E(t),i=n?N(h(d.id,s),n):h(d.id,s);e.delete(d).where(i).run()}(this.db,e,s)}async getMessages(e,s){return await this.getSession(e,s)?function(e,s){return e.select().from(r).where(b(r.sessionId,s)).orderBy(r.sequence,r.timestamp).all().map(O)}(this.db,e):[]}async getMessage(e,s){return function(e,s,t){const n=m(t),i=n?L(b(r.id,s),n):b(r.id,s),a=e.select().from(r).where(i).get();return a?O(a):null}(this.db,e,s)}async saveMessage(e,s){return S(this.db,e,s)}async updateMessage(e,s,t){!function(e,s,t,n){const i=m(n),a=i?L(b(r.id,s),i):b(r.id,s),d={};void 0!==t.content&&(d.content=t.content),void 0!==t.steps&&(d.steps=t.steps),void 0!==t.operationIds&&(d.operationIds=t.operationIds),void 0!==t.usage&&(d.usage=t.usage),void 0!==t.duration&&(d.duration=t.duration),Object.keys(d).length>0&&e.update(r).set(d).where(a).run()}(this.db,e,s,t)}async deleteMessagesAfter(e,s,t){await this.getSession(e,t)&&function(e,s,t){e.delete(r).where(L(b(r.sessionId,s),A(r.timestamp,t))).run()}(this.db,e,s)}async deleteMessagesAfterMessageId(e,s,t){if(!await this.getSession(e,t))return;const n=await this.getMessage(s,t);if(n&&n.sessionId===e){if(null===n.sequence||void 0===n.sequence)throw new Error(`消息 ${s} 缺少序号,无法删除后续消息`);!function(e,s,t,n){if(null==n)throw new Error(`消息 ${t} 缺少序号,无法删除后续消息`);e.delete(r).where(L(b(r.sessionId,s),A(r.sequence,n))).run()}(this.db,e,s,n.sequence)}}async getOperations(e,s){return await this.getSession(e,s)?function(e,s){return e.select().from(o).where(y(o.sessionId,s)).orderBy(o.timestamp).all().map(X)}(this.db,e):[]}async getOperationsByMessage(e,s){return D(this.db,e,s)}async saveOperation(e,s){return function(e,s,t){const n=new Date,i={id:s.id,sessionId:s.sessionId,messageId:s.messageId,appId:t.appId||null,userId:t.userId||null,command:s.command,operationType:s.operationType,affectedFiles:s.affectedFiles,backupPath:s.backupPath,status:s.status||"pending",errorMessage:null,timestamp:n};return e.insert(o).values({id:i.id,sessionId:i.sessionId,messageId:i.messageId,appId:i.appId,userId:i.userId,command:i.command,operationType:i.operationType,affectedFiles:i.affectedFiles,backupPath:i.backupPath,status:i.status,errorMessage:i.errorMessage,timestamp:i.timestamp}).run(),i}(this.db,e,s)}async updateOperationStatus(e,s,t){!function(e,s,t,n){const i={status:t};void 0!==n&&(i.errorMessage=n),e.update(o).set(i).where(y(o.id,s)).run()}(this.db,e,s,t)}async getBackups(e){return function(e,s){return e.select().from(u).where(w(u.operationId,s)).all().map(x)}(this.db,e)}async saveBackup(e){return function(e,s){const t={...s,createdAt:new Date};return e.insert(u).values({id:t.id,operationId:t.operationId,originalPath:t.originalPath,backupPath:t.backupPath,fileSize:t.fileSize,fileHash:t.fileHash,createdAt:t.createdAt,expiresAt:t.expiresAt}).run(),t}(this.db,e)}async deleteExpiredBackups(){return function(e){const s=new Date;return e.delete(u).where(U(u.expiresAt,s)).run().changes}(this.db)}async getTrashItems(e){return function(e,s){const t=I(s);return e.select().from(l).where(t).orderBy(F(l.deletedAt)).all().map(C)}(this.db,e)}async moveToTrash(e,s){return function(e,s,t,n){const i=new Date,a=n.trashRetentionDays||30,d=new Date(i.getTime()+24*a*60*60*1e3),r={...s,appId:t.appId||null,userId:t.userId||null,deletedAt:i,autoDeleteAt:d};return e.insert(l).values({id:r.id,sessionId:r.sessionId,appId:r.appId,userId:r.userId,originalPath:r.originalPath,trashPath:r.trashPath,deletedAt:r.deletedAt,autoDeleteAt:r.autoDeleteAt}).run(),r}(this.db,e,s,this.config)}async restoreFromTrash(e,s){return function(e,s,t){const n=I(t),i=n?q(k(l.id,s),n):k(l.id,s),a=e.select().from(l).where(i).get();if(!a)throw new Error("回收站记录不存在");return e.delete(l).where(k(l.id,s)).run(),C(a)}(this.db,e,s)}async emptyExpiredTrash(){return function(e){const s=new Date;return e.delete(l).where(M(l.autoDeleteAt,s)).run().changes}(this.db)}async saveEmbedding(e,s,t,n,i){!function(e,s,t,n,i,a){const d=new Date;e.insert(p).values({id:s,sessionId:i.sessionId,messageId:i.messageId||null,appId:a.appId||null,userId:a.userId||null,content:t,contentType:i.contentType,embedding:JSON.stringify(n),metadata:JSON.stringify(i),createdAt:d}).run()}(this.db,e,s,t,n,i)}async searchSimilar(e,s,t){return B(this.db,e,s,t)}async getUserSetting(e,s){return function(e,s,t){const n=e.prepare("\n SELECT value FROM user_settings\n WHERE key = ? AND app_id IS ? AND user_id IS ?\n LIMIT 1\n ").get(s,t.appId||null,t.userId||null);return n?.value||null}(this.sqlite,e,s)}async setUserSetting(e,s,t){return function(e,s,t,n){const i=Date.now(),a=`${n.appId||"default"}_${n.userId||"default"}_${s}`,d=e.prepare("\n SELECT created_at FROM user_settings WHERE id = ?\n ").get(a),r=d?.created_at||i;e.prepare("\n INSERT OR REPLACE INTO user_settings \n (id, app_id, user_id, key, value, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ").run(a,n.appId||null,n.userId||null,s,t,r,i)}(this.sqlite,e,s,t)}async getUserSettings(e){return function(e,s){const t=e.prepare("\n SELECT key, value FROM user_settings\n WHERE app_id IS ? AND user_id IS ?\n ").all(s.appId||null,s.userId||null),n={};for(const e of t)n[e.key]=e.value;return n}(this.sqlite,e)}async deleteUserSetting(e,s){return function(e,s,t){e.prepare("\n DELETE FROM user_settings\n WHERE key = ? AND app_id IS ? AND user_id IS ?\n ").run(s,t.appId||null,t.userId||null)}(this.sqlite,e,s)}async close(){this.sqlite.close()}};export{d as sessions,r as messages,o as operations,u as backups,l as trash,p as embeddings,G as SqliteAdapter};
@@ -1 +0,0 @@
1
- import{PostgresAdapter as o}from"./chunk-EXGLTJH4.js";export{o as PostgresAdapter};
@@ -1 +0,0 @@
1
- import{SqliteAdapter as o}from"./chunk-V5E7YX6J.js";export{o as SqliteAdapter};