@coffer-org/server 2.2.1 → 2.3.0
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.
- package/dist/entity-schema.js +1 -0
- package/dist/migrations.js +1 -1
- package/dist/thread-store.d.ts +8 -0
- package/dist/thread-store.js +23 -1
- package/dist/uploads.d.ts +10 -0
- package/dist/uploads.js +24 -1
- package/package.json +3 -3
package/dist/entity-schema.js
CHANGED
|
@@ -161,6 +161,7 @@ export const ThreadMessageSchema = new EntitySchema({
|
|
|
161
161
|
role: { type: 'text' },
|
|
162
162
|
sender: { type: 'text', nullable: true },
|
|
163
163
|
text: { type: 'text' },
|
|
164
|
+
attachments: { type: 'text', nullable: true },
|
|
164
165
|
ts: { type: 'integer' },
|
|
165
166
|
reply_to_id: { type: 'text', nullable: true },
|
|
166
167
|
},
|
package/dist/migrations.js
CHANGED
|
@@ -145,7 +145,7 @@ export function makeTable(em, table) {
|
|
|
145
145
|
const sources = new Set(c.from);
|
|
146
146
|
for (const t of c.to) {
|
|
147
147
|
if (info.columns.has(t.name) && !sources.has(t.name)) {
|
|
148
|
-
throw new Error(`[migrations] ${table}.${t.name}:
|
|
148
|
+
throw new Error(`[migrations] ${table}.${t.name}: convert target column already exists and is not a source — use changeType/renameColumn`);
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
const sqlite = dialectOf(em) === 'sqlite';
|
package/dist/thread-store.d.ts
CHANGED
|
@@ -3,9 +3,16 @@ export interface StoredMsg {
|
|
|
3
3
|
role: 'user' | 'assistant' | 'reasoning';
|
|
4
4
|
sender: string | null;
|
|
5
5
|
text: string;
|
|
6
|
+
attachments?: StoredAttachment[];
|
|
6
7
|
ts: number;
|
|
7
8
|
replyToId: string | null;
|
|
8
9
|
}
|
|
10
|
+
export interface StoredAttachment {
|
|
11
|
+
name: string;
|
|
12
|
+
mime?: string;
|
|
13
|
+
size?: number;
|
|
14
|
+
label?: string;
|
|
15
|
+
}
|
|
9
16
|
export interface ThreadChat {
|
|
10
17
|
chatId: string;
|
|
11
18
|
lastTs: number;
|
|
@@ -19,6 +26,7 @@ export declare function putThreadMessage(m: {
|
|
|
19
26
|
msgId: string;
|
|
20
27
|
role: 'user' | 'assistant' | 'reasoning';
|
|
21
28
|
sender?: string | null;
|
|
29
|
+
attachments?: StoredAttachment[];
|
|
22
30
|
text: string;
|
|
23
31
|
ts: number;
|
|
24
32
|
replyToId: string | null;
|
package/dist/thread-store.js
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
import { getEm } from "./db.js";
|
|
2
2
|
function toStored(r) {
|
|
3
|
-
|
|
3
|
+
let attachments;
|
|
4
|
+
if (r.attachments) {
|
|
5
|
+
try {
|
|
6
|
+
const parsed = JSON.parse(r.attachments);
|
|
7
|
+
if (Array.isArray(parsed)) {
|
|
8
|
+
const valid = parsed.filter((v) => typeof v === 'object' && v !== null && typeof v.name === 'string');
|
|
9
|
+
if (valid.length)
|
|
10
|
+
attachments = valid;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
msgId: r.msg_id,
|
|
18
|
+
role: r.role,
|
|
19
|
+
sender: r.sender,
|
|
20
|
+
text: r.text,
|
|
21
|
+
...(attachments ? { attachments } : {}),
|
|
22
|
+
ts: r.ts,
|
|
23
|
+
replyToId: r.reply_to_id,
|
|
24
|
+
};
|
|
4
25
|
}
|
|
5
26
|
export async function getThreadMessage(connector, chatId, msgId) {
|
|
6
27
|
const em = getEm().fork();
|
|
@@ -15,6 +36,7 @@ export async function putThreadMessage(m) {
|
|
|
15
36
|
msg_id: m.msgId,
|
|
16
37
|
role: m.role,
|
|
17
38
|
sender: m.sender ?? null,
|
|
39
|
+
attachments: m.attachments?.length ? JSON.stringify(m.attachments) : null,
|
|
18
40
|
text: m.text,
|
|
19
41
|
ts: m.ts,
|
|
20
42
|
reply_to_id: m.replyToId,
|
package/dist/uploads.d.ts
CHANGED
|
@@ -2,4 +2,14 @@ export declare function uploadsDir(): string;
|
|
|
2
2
|
export declare function seedAsset(absPath: string): {
|
|
3
3
|
name: string;
|
|
4
4
|
};
|
|
5
|
+
export interface StoredUpload {
|
|
6
|
+
name: string;
|
|
7
|
+
mime?: string;
|
|
8
|
+
size: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function saveUploadBytes(bytes: Uint8Array, opts?: {
|
|
11
|
+
originalName?: string;
|
|
12
|
+
mime?: string;
|
|
13
|
+
maxBytes?: number;
|
|
14
|
+
}): Promise<StoredUpload>;
|
|
5
15
|
export declare function seedAssetPath(metaUrl: string): (rel: string) => string;
|
package/dist/uploads.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync } from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { writeFile } from 'node:fs/promises';
|
|
3
|
+
import { basename, extname, join } from 'node:path';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
3
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
const MIME_EXT = {
|
|
7
|
+
'image/jpeg': '.jpg',
|
|
8
|
+
'image/png': '.png',
|
|
9
|
+
'image/gif': '.gif',
|
|
10
|
+
'image/webp': '.webp',
|
|
11
|
+
'application/pdf': '.pdf',
|
|
12
|
+
'text/plain': '.txt',
|
|
13
|
+
'text/csv': '.csv',
|
|
14
|
+
'application/json': '.json',
|
|
15
|
+
};
|
|
4
16
|
export function uploadsDir() {
|
|
5
17
|
const dir = process.env.UPLOADS ?? join(process.cwd(), 'data', 'uploads');
|
|
6
18
|
mkdirSync(dir, { recursive: true });
|
|
@@ -11,6 +23,17 @@ export function seedAsset(absPath) {
|
|
|
11
23
|
copyFileSync(absPath, join(uploadsDir(), name));
|
|
12
24
|
return { name };
|
|
13
25
|
}
|
|
26
|
+
export async function saveUploadBytes(bytes, opts = {}) {
|
|
27
|
+
const maxBytes = opts.maxBytes ?? 25 * 1024 * 1024;
|
|
28
|
+
if (bytes.byteLength > maxBytes)
|
|
29
|
+
throw new Error(`upload exceeds ${maxBytes} bytes`);
|
|
30
|
+
const originalExt = opts.originalName ? extname(basename(opts.originalName)).toLowerCase() : '';
|
|
31
|
+
const ext = originalExt && /^[.][a-z0-9]{1,10}$/.test(originalExt) ? originalExt : MIME_EXT[opts.mime ?? ''] ?? '';
|
|
32
|
+
const name = `${randomUUID()}${ext}`;
|
|
33
|
+
await writeFile(join(uploadsDir(), name), bytes);
|
|
34
|
+
const mime = opts.mime === 'application/octet-stream' ? undefined : opts.mime;
|
|
35
|
+
return { name, ...(mime ? { mime } : {}), size: bytes.byteLength };
|
|
36
|
+
}
|
|
14
37
|
export function seedAssetPath(metaUrl) {
|
|
15
38
|
return (rel) => fileURLToPath(new URL(`../../seed/assets/${rel}`, metaUrl));
|
|
16
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffer-org/server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24"
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"postpack": "node ../../scripts/swap-exports.mjs src"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@coffer-org/core": "^2.1.
|
|
28
|
-
"@coffer-org/sdk": "^2.1.
|
|
27
|
+
"@coffer-org/core": "^2.1.2",
|
|
28
|
+
"@coffer-org/sdk": "^2.1.1",
|
|
29
29
|
"@extractus/oembed-extractor": "^4.1.0",
|
|
30
30
|
"@fastify/cors": "^11.2.0",
|
|
31
31
|
"@fastify/multipart": "^10.0.0",
|