@mooncompany/uplink-chat 0.5.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.
Potentially problematic release.
This version of @mooncompany/uplink-chat might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/bin/uplink.js +279 -0
- package/middleware/error-handler.js +69 -0
- package/package.json +93 -0
- package/public/css/agents.36b98c0f.css +1469 -0
- package/public/css/agents.css +1469 -0
- package/public/css/app.a6a7f8f5.css +2731 -0
- package/public/css/app.css +2731 -0
- package/public/css/artifacts.css +444 -0
- package/public/css/commands.css +55 -0
- package/public/css/connection.css +131 -0
- package/public/css/dashboard.css +233 -0
- package/public/css/developer.css +328 -0
- package/public/css/files.css +123 -0
- package/public/css/markdown.css +156 -0
- package/public/css/message-actions.css +278 -0
- package/public/css/mobile.css +614 -0
- package/public/css/panels-unified.css +483 -0
- package/public/css/premium.css +415 -0
- package/public/css/realtime.css +189 -0
- package/public/css/satellites.css +401 -0
- package/public/css/shortcuts.css +185 -0
- package/public/css/split-view.4def0262.css +673 -0
- package/public/css/split-view.css +673 -0
- package/public/css/theme-generator.css +391 -0
- package/public/css/themes.css +387 -0
- package/public/css/timestamps.css +54 -0
- package/public/css/variables.css +78 -0
- package/public/dist/bundle.b55050c4.js +15757 -0
- package/public/favicon.svg +24 -0
- package/public/img/agents/ada.png +0 -0
- package/public/img/agents/clarice.png +0 -0
- package/public/img/agents/dennis-nedry.png +0 -0
- package/public/img/agents/elliot-alderson.png +0 -0
- package/public/img/agents/main.png +0 -0
- package/public/img/agents/scotty.png +0 -0
- package/public/img/agents/top-flight-security.png +0 -0
- package/public/index.html +1083 -0
- package/public/js/agents-data.js +234 -0
- package/public/js/agents-ui.js +72 -0
- package/public/js/agents.js +1525 -0
- package/public/js/app.js +79 -0
- package/public/js/appearance-settings.js +111 -0
- package/public/js/artifacts.js +432 -0
- package/public/js/audio-queue.js +168 -0
- package/public/js/bootstrap.js +54 -0
- package/public/js/chat.js +1211 -0
- package/public/js/commands.js +581 -0
- package/public/js/connection-api.js +121 -0
- package/public/js/connection.js +1231 -0
- package/public/js/context-tracker.js +271 -0
- package/public/js/core.js +172 -0
- package/public/js/dashboard.js +452 -0
- package/public/js/developer.js +432 -0
- package/public/js/encryption.js +124 -0
- package/public/js/errors.js +122 -0
- package/public/js/event-bus.js +77 -0
- package/public/js/fetch-utils.js +171 -0
- package/public/js/file-handler.js +229 -0
- package/public/js/files.js +352 -0
- package/public/js/gateway-chat.js +538 -0
- package/public/js/logger.js +112 -0
- package/public/js/markdown.js +190 -0
- package/public/js/message-actions.js +431 -0
- package/public/js/message-renderer.js +288 -0
- package/public/js/missed-messages.js +235 -0
- package/public/js/mobile-debug.js +95 -0
- package/public/js/notifications.js +367 -0
- package/public/js/offline-queue.js +178 -0
- package/public/js/onboarding.js +543 -0
- package/public/js/panels.js +156 -0
- package/public/js/premium.js +412 -0
- package/public/js/realtime-voice.js +844 -0
- package/public/js/satellite-sync.js +256 -0
- package/public/js/satellite-ui.js +175 -0
- package/public/js/satellites.js +1516 -0
- package/public/js/settings.js +1087 -0
- package/public/js/shortcuts.js +381 -0
- package/public/js/split-chat.js +1234 -0
- package/public/js/split-resize.js +211 -0
- package/public/js/splitview.js +340 -0
- package/public/js/storage.js +408 -0
- package/public/js/streaming-handler.js +324 -0
- package/public/js/stt-settings.js +316 -0
- package/public/js/theme-generator.js +661 -0
- package/public/js/themes.js +164 -0
- package/public/js/timestamps.js +198 -0
- package/public/js/tts-settings.js +575 -0
- package/public/js/ui.js +267 -0
- package/public/js/update-notifier.js +143 -0
- package/public/js/utils/constants.js +165 -0
- package/public/js/utils/sanitize.js +93 -0
- package/public/js/utils/sse-parser.js +195 -0
- package/public/js/voice.js +883 -0
- package/public/manifest.json +58 -0
- package/public/moon_texture.jpg +0 -0
- package/public/sw.js +221 -0
- package/public/three.min.js +6 -0
- package/server/channel.js +529 -0
- package/server/chat.js +270 -0
- package/server/config-store.js +362 -0
- package/server/config.js +159 -0
- package/server/context.js +131 -0
- package/server/gateway-commands.js +211 -0
- package/server/gateway-proxy.js +318 -0
- package/server/index.js +22 -0
- package/server/logger.js +89 -0
- package/server/middleware/auth.js +188 -0
- package/server/middleware.js +218 -0
- package/server/openclaw-discover.js +308 -0
- package/server/premium/index.js +156 -0
- package/server/premium/license.js +140 -0
- package/server/realtime/bridge.js +837 -0
- package/server/realtime/index.js +349 -0
- package/server/realtime/tts-stream.js +446 -0
- package/server/routes/agents.js +564 -0
- package/server/routes/artifacts.js +174 -0
- package/server/routes/chat.js +311 -0
- package/server/routes/config-settings.js +345 -0
- package/server/routes/config.js +603 -0
- package/server/routes/files.js +307 -0
- package/server/routes/index.js +18 -0
- package/server/routes/media.js +451 -0
- package/server/routes/missed-messages.js +107 -0
- package/server/routes/premium.js +75 -0
- package/server/routes/push.js +156 -0
- package/server/routes/satellite.js +406 -0
- package/server/routes/status.js +251 -0
- package/server/routes/stt.js +35 -0
- package/server/routes/voice.js +260 -0
- package/server/routes/webhooks.js +203 -0
- package/server/routes.js +206 -0
- package/server/runtime-config.js +336 -0
- package/server/share.js +305 -0
- package/server/stt/faster-whisper.js +72 -0
- package/server/stt/groq.js +51 -0
- package/server/stt/index.js +196 -0
- package/server/stt/openai.js +49 -0
- package/server/sync.js +244 -0
- package/server/tailscale-https.js +175 -0
- package/server/tts.js +646 -0
- package/server/update-checker.js +172 -0
- package/server/utils/filename.js +129 -0
- package/server/utils.js +147 -0
- package/server/watchdog.js +318 -0
- package/server/websocket/broadcast.js +359 -0
- package/server/websocket/connections.js +339 -0
- package/server/websocket/index.js +215 -0
- package/server/websocket/routing.js +277 -0
- package/server/websocket/sync.js +102 -0
- package/server.js +404 -0
- package/utils/detect-tool-usage.js +93 -0
- package/utils/errors.js +158 -0
- package/utils/html-escape.js +84 -0
- package/utils/id-sanitize.js +94 -0
- package/utils/response.js +130 -0
- package/utils/with-retry.js +105 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Routes - General file upload with text extraction
|
|
3
|
+
* Supports: PDF, DOCX, XLSX/CSV, plain text, code files
|
|
4
|
+
* Extracted text is saved alongside originals for agent access via `read` tool
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { randomUUID } from 'crypto';
|
|
10
|
+
import { fileTypeFromBuffer } from 'file-type';
|
|
11
|
+
import { badRequest, internalError, ErrorCodes } from '../../utils/errors.js';
|
|
12
|
+
|
|
13
|
+
// Lazy-load heavy parsers (only when needed)
|
|
14
|
+
let pdfParse = null;
|
|
15
|
+
let mammoth = null;
|
|
16
|
+
let ExcelJS = null;
|
|
17
|
+
|
|
18
|
+
async function loadPdfParse() {
|
|
19
|
+
if (!pdfParse) {
|
|
20
|
+
const mod = await import('pdf-parse');
|
|
21
|
+
pdfParse = mod.PDFParse || mod.default || mod;
|
|
22
|
+
}
|
|
23
|
+
return pdfParse;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function loadMammoth() {
|
|
27
|
+
if (!mammoth) {
|
|
28
|
+
const mod = await import('mammoth');
|
|
29
|
+
mammoth = mod.default || mod;
|
|
30
|
+
}
|
|
31
|
+
return mammoth;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function loadExcelJS() {
|
|
35
|
+
if (!ExcelJS) {
|
|
36
|
+
const mod = await import('exceljs');
|
|
37
|
+
ExcelJS = mod.default || mod;
|
|
38
|
+
}
|
|
39
|
+
return ExcelJS;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
import { MAX_FILE_EXTRACT_SIZE, FILE_EXTRACTION_TIMEOUT_MS, FILE_CLEANUP_DELAY_MS } from '../config.js';
|
|
43
|
+
|
|
44
|
+
// Max text extraction size (prevent memory bombs)
|
|
45
|
+
const MAX_EXTRACT_SIZE = MAX_FILE_EXTRACT_SIZE;
|
|
46
|
+
const EXTRACTION_TIMEOUT_MS = FILE_EXTRACTION_TIMEOUT_MS;
|
|
47
|
+
|
|
48
|
+
// File categories for routing
|
|
49
|
+
const TEXT_EXTENSIONS = new Set([
|
|
50
|
+
'.txt', '.md', '.json', '.js', '.ts', '.jsx', '.tsx', '.py', '.rb',
|
|
51
|
+
'.html', '.css', '.scss', '.less', '.xml', '.yaml', '.yml', '.toml',
|
|
52
|
+
'.sh', '.bat', '.ps1', '.sql', '.csv', '.env', '.gitignore', '.log',
|
|
53
|
+
'.ini', '.cfg', '.conf', '.dockerfile', '.makefile', '.rs', '.go',
|
|
54
|
+
'.java', '.kt', '.c', '.cpp', '.h', '.hpp', '.cs', '.swift', '.r',
|
|
55
|
+
'.lua', '.php', '.pl', '.ex', '.exs', '.erl', '.hs', '.ml',
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
const EXTRACTABLE_TYPES = {
|
|
59
|
+
'application/pdf': 'pdf',
|
|
60
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
|
61
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
|
62
|
+
'application/vnd.ms-excel': 'xls',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Run a function with a timeout
|
|
67
|
+
*/
|
|
68
|
+
function withTimeout(fn, ms) {
|
|
69
|
+
return Promise.race([
|
|
70
|
+
fn(),
|
|
71
|
+
new Promise((_, reject) =>
|
|
72
|
+
setTimeout(() => reject(new Error(`Extraction timed out after ${ms}ms`)), ms)
|
|
73
|
+
),
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extract text from a PDF buffer (pdf-parse v2 API)
|
|
79
|
+
*/
|
|
80
|
+
async function extractPdf(buffer) {
|
|
81
|
+
const PDFParse = await loadPdfParse();
|
|
82
|
+
const parser = new PDFParse({ data: buffer });
|
|
83
|
+
const result = await parser.getText();
|
|
84
|
+
const text = result?.text || '';
|
|
85
|
+
await parser.destroy();
|
|
86
|
+
return text.slice(0, MAX_EXTRACT_SIZE);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Extract text from a DOCX buffer
|
|
91
|
+
*/
|
|
92
|
+
async function extractDocx(buffer) {
|
|
93
|
+
const mam = await loadMammoth();
|
|
94
|
+
const result = await mam.extractRawText({ buffer });
|
|
95
|
+
return result.value?.slice(0, MAX_EXTRACT_SIZE) || '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Extract text from an XLSX/XLS buffer
|
|
100
|
+
*/
|
|
101
|
+
async function extractSpreadsheet(buffer) {
|
|
102
|
+
const EJ = await loadExcelJS();
|
|
103
|
+
const workbook = new EJ.Workbook();
|
|
104
|
+
await workbook.xlsx.load(buffer);
|
|
105
|
+
const sheets = [];
|
|
106
|
+
|
|
107
|
+
workbook.eachSheet((sheet) => {
|
|
108
|
+
const rows = [];
|
|
109
|
+
sheet.eachRow((row) => {
|
|
110
|
+
const values = [];
|
|
111
|
+
row.eachCell({ includeEmpty: true }, (cell) => {
|
|
112
|
+
const val = cell.text ?? cell.value ?? '';
|
|
113
|
+
values.push(String(val).replace(/,/g, ' '));
|
|
114
|
+
});
|
|
115
|
+
rows.push(values.join(','));
|
|
116
|
+
});
|
|
117
|
+
sheets.push(`## Sheet: ${sheet.name}\n${rows.join('\n')}`);
|
|
118
|
+
|
|
119
|
+
// Check total size
|
|
120
|
+
const totalSize = sheets.join('\n\n').length;
|
|
121
|
+
if (totalSize > MAX_EXTRACT_SIZE) return;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return sheets.join('\n\n').slice(0, MAX_EXTRACT_SIZE);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Determine if a file is plain text based on extension
|
|
129
|
+
*/
|
|
130
|
+
function isTextByExtension(filename) {
|
|
131
|
+
const ext = path.extname(filename).toLowerCase();
|
|
132
|
+
return TEXT_EXTENSIONS.has(ext);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Setup file routes
|
|
137
|
+
* @param {Express} app - Express app instance
|
|
138
|
+
* @param {Object} deps - Dependencies
|
|
139
|
+
*/
|
|
140
|
+
export function setupFileRoutes(app, context) {
|
|
141
|
+
const {
|
|
142
|
+
fileUpload,
|
|
143
|
+
fetch: fetchWithTimeout,
|
|
144
|
+
log,
|
|
145
|
+
config,
|
|
146
|
+
uploadsDir,
|
|
147
|
+
} = context;
|
|
148
|
+
|
|
149
|
+
const { GATEWAY_URL, GATEWAY_TOKEN, SESSION_USER, REQUEST_TIMEOUT } = config;
|
|
150
|
+
|
|
151
|
+
app.post('/api/file', (req, res) => {
|
|
152
|
+
fileUpload(req, res, async (err) => {
|
|
153
|
+
if (err) {
|
|
154
|
+
log('error', '[File] Upload error:', err);
|
|
155
|
+
const errorDetail = process.env.NODE_ENV === 'production'
|
|
156
|
+
? 'File upload failed'
|
|
157
|
+
: err.message;
|
|
158
|
+
return badRequest(res, 'Upload failed: ' + errorDetail, ErrorCodes.UPLOAD_FAILED);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
if (!req.file) {
|
|
163
|
+
return badRequest(res, 'No file provided', ErrorCodes.MISSING_FIELD);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const { originalname, path: tempPath, size } = req.file;
|
|
167
|
+
const caption = req.body?.caption?.slice(0, 500) || '';
|
|
168
|
+
const satelliteId = String(req.body?.satelliteId || 'main').replace(/[^a-zA-Z0-9_-]/g, '').substring(0, 32);
|
|
169
|
+
|
|
170
|
+
log('info', `[File] Received: ${originalname} (${(size / 1024).toFixed(1)} KB)`);
|
|
171
|
+
|
|
172
|
+
// Read the uploaded file
|
|
173
|
+
const fileBuffer = await fs.readFile(tempPath);
|
|
174
|
+
|
|
175
|
+
// Detect actual file type via magic bytes
|
|
176
|
+
const detectedType = await fileTypeFromBuffer(fileBuffer);
|
|
177
|
+
const mimeType = detectedType?.mime || 'application/octet-stream';
|
|
178
|
+
const ext = path.extname(originalname).toLowerCase() || (detectedType?.ext ? `.${detectedType.ext}` : '');
|
|
179
|
+
|
|
180
|
+
// Generate unique filename preserving original extension
|
|
181
|
+
const fileId = randomUUID();
|
|
182
|
+
const safeOrigName = originalname.replace(/[^a-zA-Z0-9._-]/g, '_').substring(0, 100);
|
|
183
|
+
const savedFilename = `file-${fileId}${ext}`;
|
|
184
|
+
const savedPath = path.join(uploadsDir, savedFilename);
|
|
185
|
+
|
|
186
|
+
// Save original file
|
|
187
|
+
await fs.mkdir(uploadsDir, { recursive: true });
|
|
188
|
+
await fs.writeFile(savedPath, fileBuffer);
|
|
189
|
+
|
|
190
|
+
// Clean up temp file
|
|
191
|
+
await fs.unlink(tempPath).catch(() => {});
|
|
192
|
+
|
|
193
|
+
// Attempt text extraction
|
|
194
|
+
let extractedText = null;
|
|
195
|
+
let extractedFilename = null;
|
|
196
|
+
let extractionMethod = 'none';
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
if (isTextByExtension(originalname)) {
|
|
200
|
+
// Plain text — read directly
|
|
201
|
+
extractedText = fileBuffer.toString('utf-8').slice(0, MAX_EXTRACT_SIZE);
|
|
202
|
+
extractionMethod = 'text';
|
|
203
|
+
} else if (EXTRACTABLE_TYPES[mimeType] === 'pdf') {
|
|
204
|
+
extractedText = await withTimeout(() => extractPdf(fileBuffer), EXTRACTION_TIMEOUT_MS);
|
|
205
|
+
extractionMethod = 'pdf-parse';
|
|
206
|
+
} else if (EXTRACTABLE_TYPES[mimeType] === 'docx') {
|
|
207
|
+
extractedText = await withTimeout(() => extractDocx(fileBuffer), EXTRACTION_TIMEOUT_MS);
|
|
208
|
+
extractionMethod = 'mammoth';
|
|
209
|
+
} else if (EXTRACTABLE_TYPES[mimeType] === 'xlsx' || EXTRACTABLE_TYPES[mimeType] === 'xls') {
|
|
210
|
+
extractedText = await withTimeout(() => extractSpreadsheet(fileBuffer), EXTRACTION_TIMEOUT_MS);
|
|
211
|
+
extractionMethod = 'exceljs';
|
|
212
|
+
}
|
|
213
|
+
} catch (extractErr) {
|
|
214
|
+
log('warn', `[File] Text extraction failed for ${originalname}: ${extractErr.message}`);
|
|
215
|
+
// Continue without extracted text — agent can still see the file exists
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Save extracted text alongside original
|
|
219
|
+
if (extractedText && extractedText.trim().length > 0) {
|
|
220
|
+
extractedFilename = `file-${fileId}.extracted.txt`;
|
|
221
|
+
const extractedPath = path.join(uploadsDir, extractedFilename);
|
|
222
|
+
const header = `# Extracted from: ${safeOrigName}\n# Type: ${mimeType}\n# Method: ${extractionMethod}\n# Size: ${(size / 1024).toFixed(1)} KB\n---\n\n`;
|
|
223
|
+
await fs.writeFile(extractedPath, header + extractedText, 'utf-8');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Build the message to send to the agent
|
|
227
|
+
const filePath = `uplink/uploads/${savedFilename}`;
|
|
228
|
+
const extractedPath = extractedFilename ? `uplink/uploads/${extractedFilename}` : null;
|
|
229
|
+
|
|
230
|
+
let prompt;
|
|
231
|
+
if (extractedPath) {
|
|
232
|
+
prompt = caption
|
|
233
|
+
? `[File uploaded: ${safeOrigName}] [Original at: ${filePath}] [Extracted text at: ${extractedPath} — read this file for the content] ${caption}`
|
|
234
|
+
: `[File uploaded: ${safeOrigName}] [Original at: ${filePath}] [Extracted text at: ${extractedPath} — read this file for the content] The user sent a file. Read the extracted text and summarize or respond to its contents.`;
|
|
235
|
+
} else {
|
|
236
|
+
prompt = caption
|
|
237
|
+
? `[File uploaded: ${safeOrigName}] [Saved at: ${filePath}] [Type: ${mimeType}, Size: ${(size / 1024).toFixed(1)} KB] ${caption}`
|
|
238
|
+
: `[File uploaded: ${safeOrigName}] [Saved at: ${filePath}] [Type: ${mimeType}, Size: ${(size / 1024).toFixed(1)} KB] The user sent a file. Acknowledge receipt and describe what you can do with it.`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// SSE response (same pattern as image upload)
|
|
242
|
+
res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
|
|
243
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
244
|
+
res.setHeader('Connection', 'keep-alive');
|
|
245
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
246
|
+
res.flushHeaders();
|
|
247
|
+
|
|
248
|
+
const keepalive = setInterval(() => {
|
|
249
|
+
res.write(': keepalive\n\n');
|
|
250
|
+
}, FILE_CLEANUP_DELAY_MS);
|
|
251
|
+
|
|
252
|
+
let reply = 'I received your file.';
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
// Derive session key
|
|
256
|
+
const sessionKey = satelliteId === 'main'
|
|
257
|
+
? 'agent:main:main'
|
|
258
|
+
: `agent:main:uplink:satellite:${satelliteId}`;
|
|
259
|
+
|
|
260
|
+
const response = await fetchWithTimeout(`${GATEWAY_URL}/v1/chat/completions`, {
|
|
261
|
+
method: 'POST',
|
|
262
|
+
headers: {
|
|
263
|
+
'Content-Type': 'application/json',
|
|
264
|
+
'Authorization': `Bearer ${GATEWAY_TOKEN}`,
|
|
265
|
+
'x-openclaw-session-key': sessionKey,
|
|
266
|
+
},
|
|
267
|
+
body: JSON.stringify({
|
|
268
|
+
model: 'openclaw',
|
|
269
|
+
user: SESSION_USER,
|
|
270
|
+
messages: [{ role: 'user', content: prompt }],
|
|
271
|
+
}),
|
|
272
|
+
}, REQUEST_TIMEOUT);
|
|
273
|
+
|
|
274
|
+
if (!response.ok) {
|
|
275
|
+
const text = await response.text();
|
|
276
|
+
throw new Error(`Chat API error: ${response.status} - ${text}`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const data = await response.json();
|
|
280
|
+
reply = data.choices?.[0]?.message?.content || reply;
|
|
281
|
+
} finally {
|
|
282
|
+
clearInterval(keepalive);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Send result
|
|
286
|
+
res.write(`data: ${JSON.stringify({
|
|
287
|
+
response: reply,
|
|
288
|
+
filename: safeOrigName,
|
|
289
|
+
filePath,
|
|
290
|
+
extractedPath,
|
|
291
|
+
extractionMethod,
|
|
292
|
+
})}\n\n`);
|
|
293
|
+
res.end();
|
|
294
|
+
|
|
295
|
+
log('info', `[File] Processed: ${safeOrigName} (extraction: ${extractionMethod})`);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
log('error', '[File] Error:', error);
|
|
298
|
+
if (res.headersSent) {
|
|
299
|
+
res.write(`data: ${JSON.stringify({ error: true, message: 'File processing failed' })}\n\n`);
|
|
300
|
+
res.end();
|
|
301
|
+
} else {
|
|
302
|
+
internalError(res, 'File processing failed', ErrorCodes.INTERNAL_ERROR);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routes Index - Export all route modules
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { setupVoiceRoutes } from './voice.js';
|
|
6
|
+
export { setupChatRoutes } from './chat.js';
|
|
7
|
+
export { setupMediaRoutes } from './media.js';
|
|
8
|
+
export { setupWebhookRoutes } from './webhooks.js';
|
|
9
|
+
export { setupConfigRoutes } from './config.js';
|
|
10
|
+
export { setupStatusRoutes } from './status.js';
|
|
11
|
+
export { setupSatelliteRoutes } from './satellite.js';
|
|
12
|
+
export { setupMissedMessagesRoutes, addMissedMessage } from './missed-messages.js';
|
|
13
|
+
export { setupPushRoutes, sendPushNotification } from './push.js';
|
|
14
|
+
export { setupSTTRoutes } from './stt.js';
|
|
15
|
+
export { setupFileRoutes } from './files.js';
|
|
16
|
+
export { setupAgentRoutes } from './agents.js';
|
|
17
|
+
export { setupPremiumRoutes } from './premium.js';
|
|
18
|
+
export { setupArtifactsRoutes } from './artifacts.js';
|