Merge pull request #3652 from SillyTavern/default-middleware Use default middleware for parsing request body

6024b29ea7543fb7de098951fceea6d9532dc6e8

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
44 files changed, +253 -298Showing whitespace changes
server.js+3 -3
@@ -113,6 +113,9 @@ app.use(helmet({
113113app.use(compression());
114114app.use(responseTime());
115115
116+app.use(bodyParser.json({ limit: '200mb' }));
117+app.use(bodyParser.urlencoded({ extended: true, limit: '200mb' }));
118+
116119// CORS Settings //
117120const CORS = cors({
118121 origin: 'null',
@@ -135,9 +138,6 @@ if (cliArgs.listen) {
135138}
136139
137140if (cliArgs.enableCorsProxy) {
138- app.use(bodyParser.json({
139- limit: '200mb',
140- }));
141141 app.use('/proxy/:url(*)', corsProxyMiddleware);
142142} else {
143143 app.use('/proxy/:url(*)', async (_, res) => {
src/endpoints/anthropic.js+1 -2
@@ -2,11 +2,10 @@ import fetch from 'node-fetch';
22import express from 'express';
33
44import { readSecret, SECRET_KEYS } from './secrets.js';
5-import { jsonParser } from '../express-common.js';
65
76export const router = express.Router();
87
98router.post('/caption-image', jsonParser, async (request, response) => {
109 try {
1110 const mimeType = request.body.image.split(';')[0].split(':')[1];
1211 const base64Data = request.body.image.split(',')[1];
src/endpoints/assets.js+4 -5
@@ -8,7 +8,6 @@ import sanitize from 'sanitize-filename';
88import fetch from 'node-fetch';
99
1010import { UNSAFE_EXTENSIONS } from '../constants.js';
11-import { jsonParser } from '../express-common.js';
1211import { clientRelativePath } from '../util.js';
1312
1413const VALID_CATEGORIES = ['bgm', 'ambient', 'blip', 'live2d', 'vrm', 'character', 'temp'];
@@ -105,7 +104,7 @@ export const router = express.Router();
105104 *
106105 * @returns {void}
107106 */
108107router.post('/get', jsonParser, async (request, response) => {
109108 const folderPath = path.join(request.user.directories.assets);
110109 let output = {};
111110
@@ -189,7 +188,7 @@ router.post('/get', jsonParser, async (request, response) => {
189188 *
190189 * @returns {void}
191190 */
192191router.post('/download', jsonParser, async (request, response) => {
193192 const url = request.body.url;
194193 const inputCategory = request.body.category;
195194
@@ -260,7 +259,7 @@ router.post('/download', jsonParser, async (request, response) => {
260259 *
261260 * @returns {void}
262261 */
263262router.post('/delete', jsonParser, async (request, response) => {
264263 const inputCategory = request.body.category;
265264
266265 // Check category
@@ -312,7 +311,7 @@ router.post('/delete', jsonParser, async (request, response) => {
312311 *
313312 * @returns {void}
314313 */
315314router.post('/character', jsonParser, async (request, response) => {
316315 if (request.query.name === undefined) return response.sendStatus(400);
317316
318317 // For backwards compatibility, don't reject invalid character names, just sanitize them
src/endpoints/avatars.js+3 -4
@@ -6,19 +6,18 @@ import sanitize from 'sanitize-filename';
66import jimp from 'jimp';
77import { sync as writeFileAtomicSync } from 'write-file-atomic';
88
9-import { jsonParser, urlencodedParser } from '../express-common.js';
109import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';
1110import { getImages, tryParse } from '../util.js';
1211import { getFileNameValidationFunction } from '../middleware/validateFileName.js';
1312
1413export const router = express.Router();
1514
1615router.post('/get', jsonParser, function (request, response) {
1716 var images = getImages(request.user.directories.avatars);
1817 response.send(JSON.stringify(images));
1918});
2019
2120router.post('/delete', jsonParser, getFileNameValidationFunction('avatar'), function (request, response) {
2221 if (!request.body) return response.sendStatus(400);
2322
2423 if (request.body.avatar !== sanitize(request.body.avatar)) {
@@ -36,7 +35,7 @@ router.post('/delete', jsonParser, getFileNameValidationFunction('avatar'), func
3635 return response.sendStatus(404);
3736});
3837
3938router.post('/upload', urlencodedParser, async (request, response) => {
4039 if (!request.file) return response.sendStatus(400);
4140
4241 try {
src/endpoints/azure.js+2 -3
@@ -2,11 +2,10 @@ import fetch from 'node-fetch';
22import { Router } from 'express';
33
44import { readSecret, SECRET_KEYS } from './secrets.js';
5-import { jsonParser } from '../express-common.js';
65
76export const router = Router();
87
98router.post('/list', jsonParser, async (req, res) => {
109 try {
1110 const key = readSecret(req.user.directories, SECRET_KEYS.AZURE_TTS);
1211
@@ -44,7 +43,7 @@ router.post('/list', jsonParser, async (req, res) => {
4443 }
4544});
4645
4746router.post('/generate', jsonParser, async (req, res) => {
4847 try {
4948 const key = readSecret(req.user.directories, SECRET_KEYS.AZURE_TTS);
5049
src/endpoints/backends/chat-completions.js+3 -4
@@ -2,7 +2,6 @@ import process from 'node:process';
22import express from 'express';
33import fetch from 'node-fetch';
44
5-import { jsonParser } from '../../express-common.js';
65import {
76 CHAT_COMPLETION_SOURCES,
87 GEMINI_SAFETY,
@@ -821,7 +820,7 @@ async function sendDeepSeekRequest(request, response) {
821820
822821export const router = express.Router();
823822
824823router.post('/status', jsonParser, async function (request, response_getstatus_openai) {
825824 if (!request.body) return response_getstatus_openai.sendStatus(400);
826825
827826 let api_url;
@@ -937,7 +936,7 @@ router.post('/status', jsonParser, async function (request, response_getstatus_o
937936 }
938937});
939938
940939router.post('/bias', jsonParser, async function (request, response) {
941940 if (!request.body || !Array.isArray(request.body))
942941 return response.sendStatus(400);
943942
@@ -1022,7 +1021,7 @@ router.post('/bias', jsonParser, async function (request, response) {
10221021});
10231022
10241023
10251024router.post('/generate', jsonParser, function (request, response) {
10261025 if (!request.body) return response.status(400).send({ error: true });
10271026
10281027 switch (request.body.chat_completion_source) {
src/endpoints/backends/kobold.js+3 -4
@@ -2,14 +2,13 @@ import fs from 'node:fs';
22import express from 'express';
33import fetch from 'node-fetch';
44
5-import { jsonParser, urlencodedParser } from '../../express-common.js';
65import { forwardFetchResponse, delay } from '../../util.js';
76import { getOverrideHeaders, setAdditionalHeaders, setAdditionalHeadersByType } from '../../additional-headers.js';
87import { TEXTGEN_TYPES } from '../../constants.js';
98
109export const router = express.Router();
1110
1211router.post('/generate', jsonParser, async function (request, response_generate) {
1312 if (!request.body) return response_generate.sendStatus(400);
1413
1514 if (request.body.api_server.indexOf('localhost') != -1) {
@@ -141,7 +140,7 @@ router.post('/generate', jsonParser, async function (request, response_generate)
141140 return response_generate.send({ error: true });
142141});
143142
144143router.post('/status', jsonParser, async function (request, response) {
145144 if (!request.body) return response.sendStatus(400);
146145 let api_server = request.body.api_server;
147146 if (api_server.indexOf('localhost') != -1) {
@@ -188,7 +187,7 @@ router.post('/status', jsonParser, async function (request, response) {
188187 response.send(result);
189188});
190189
191190router.post('/transcribe-audio', urlencodedParser, async function (request, response) {
192191 try {
193192 const server = request.body.server;
194193
src/endpoints/backends/scale-alt.js+1 -2
@@ -1,12 +1,11 @@
11import express from 'express';
22import fetch from 'node-fetch';
33
4-import { jsonParser } from '../../express-common.js';
54import { readSecret, SECRET_KEYS } from '../secrets.js';
65
76export const router = express.Router();
87
98router.post('/generate', jsonParser, async function (request, response) {
109 if (!request.body) return response.sendStatus(400);
1110
1211 try {
src/endpoints/backends/text-completions.js+9 -10
@@ -3,7 +3,6 @@ import fetch from 'node-fetch';
33import express from 'express';
44import _ from 'lodash';
55
6-import { jsonParser } from '../../express-common.js';
76import {
87 TEXTGEN_TYPES,
98 TOGETHERAI_KEYS,
@@ -93,7 +92,7 @@ async function abortKoboldCppRequest(url) {
9392}
9493
9594//************** Ooba/OpenAI text completions API
9695router.post('/status', jsonParser, async function (request, response) {
9796 if (!request.body) return response.sendStatus(400);
9897
9998 try {
@@ -227,7 +226,7 @@ router.post('/status', jsonParser, async function (request, response) {
227226 }
228227});
229228
230229router.post('/props', jsonParser, async function (request, response) {
231230 if (!request.body.api_server) return response.sendStatus(400);
232231
233232 try {
@@ -261,7 +260,7 @@ router.post('/props', jsonParser, async function (request, response) {
261260 }
262261});
263262
264263router.post('/generate', jsonParser, async function (request, response) {
265264 if (!request.body) return response.sendStatus(400);
266265
267266 try {
@@ -432,7 +431,7 @@ router.post('/generate', jsonParser, async function (request, response) {
432431
433432const ollama = express.Router();
434433
435434ollama.post('/download', jsonParser, async function (request, response) {
436435 try {
437436 if (!request.body.name || !request.body.api_server) return response.sendStatus(400);
438437
@@ -462,7 +461,7 @@ ollama.post('/download', jsonParser, async function (request, response) {
462461 }
463462});
464463
465464ollama.post('/caption-image', jsonParser, async function (request, response) {
466465 try {
467466 if (!request.body.server_url || !request.body.model) {
468467 return response.sendStatus(400);
@@ -507,7 +506,7 @@ ollama.post('/caption-image', jsonParser, async function (request, response) {
507506
508507const llamacpp = express.Router();
509508
510509llamacpp.post('/caption-image', jsonParser, async function (request, response) {
511510 try {
512511 if (!request.body.server_url) {
513512 return response.sendStatus(400);
@@ -552,7 +551,7 @@ llamacpp.post('/caption-image', jsonParser, async function (request, response) {
552551 }
553552});
554553
555554llamacpp.post('/props', jsonParser, async function (request, response) {
556555 try {
557556 if (!request.body.server_url) {
558557 return response.sendStatus(400);
@@ -581,7 +580,7 @@ llamacpp.post('/props', jsonParser, async function (request, response) {
581580 }
582581});
583582
584583llamacpp.post('/slots', jsonParser, async function (request, response) {
585584 try {
586585 if (!request.body.server_url) {
587586 return response.sendStatus(400);
@@ -633,7 +632,7 @@ llamacpp.post('/slots', jsonParser, async function (request, response) {
633632
634633const tabby = express.Router();
635634
636635tabby.post('/download', jsonParser, async function (request, response) {
637636 try {
638637 const baseUrl = String(request.body.api_server).replace(/\/$/, '');
639638
src/endpoints/backgrounds.js+4 -5
@@ -4,19 +4,18 @@ import path from 'node:path';
44import express from 'express';
55import sanitize from 'sanitize-filename';
66
7-import { jsonParser, urlencodedParser } from '../express-common.js';
87import { invalidateThumbnail } from './thumbnails.js';
98import { getImages } from '../util.js';
109import { getFileNameValidationFunction } from '../middleware/validateFileName.js';
1110
1211export const router = express.Router();
1312
1413router.post('/all', jsonParser, function (request, response) {
1514 var images = getImages(request.user.directories.backgrounds);
1615 response.send(JSON.stringify(images));
1716});
1817
1918router.post('/delete', jsonParser, getFileNameValidationFunction('bg'), function (request, response) {
2019 if (!request.body) return response.sendStatus(400);
2120
2221 if (request.body.bg !== sanitize(request.body.bg)) {
@@ -36,7 +35,7 @@ router.post('/delete', jsonParser, getFileNameValidationFunction('bg'), function
3635 return response.send('ok');
3736});
3837
3938router.post('/rename', jsonParser, function (request, response) {
4039 if (!request.body) return response.sendStatus(400);
4140
4241 const oldFileName = path.join(request.user.directories.backgrounds, sanitize(request.body.old_bg));
@@ -58,7 +57,7 @@ router.post('/rename', jsonParser, function (request, response) {
5857 return response.send('ok');
5958});
6059
6160router.post('/upload', urlencodedParser, function (request, response) {
6261 if (!request.body || !request.file) return response.sendStatus(400);
6362
6463 const img_path = path.join(request.file.destination, request.file.filename);
src/endpoints/caption.js+1 -2
@@ -1,12 +1,11 @@
11import express from 'express';
2-import { jsonParser } from '../express-common.js';
32import { getPipeline, getRawImage } from '../transformers.js';
43
54export const router = express.Router();
65
76const TASK = 'image-to-text';
87
98router.post('/', jsonParser, async (req, res) => {
109 try {
1110 const { image } = req.body;
1211
src/endpoints/characters.js+12 -13
@@ -13,7 +13,6 @@ import mime from 'mime-types';
1313import jimp from 'jimp';
1414
1515import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js';
16-import { jsonParser, urlencodedParser } from '../express-common.js';
1716import { default as validateAvatarUrlMiddleware, getFileNameValidationFunction } from '../middleware/validateFileName.js';
1817import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue } from '../util.js';
1918import { TavernCardValidator } from '../validator/TavernCardValidator.js';
@@ -768,7 +767,7 @@ async function importFromPng(uploadPath, { request }, preservedFileName) {
768767
769768export const router = express.Router();
770769
771770router.post('/create', urlencodedParser, async function (request, response) {
772771 try {
773772 if (!request.body) return response.sendStatus(400);
774773
@@ -797,7 +796,7 @@ router.post('/create', urlencodedParser, async function (request, response) {
797796 }
798797});
799798
800799router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
801800 if (!request.body.avatar_url || !request.body.new_name) {
802801 return response.sendStatus(400);
803802 }
@@ -844,7 +843,7 @@ router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (
844843 }
845844});
846845
847846router.post('/edit', urlencodedParser, validateAvatarUrlMiddleware, async function (request, response) {
848847 if (!request.body) {
849848 console.warn('Error: no response body detected');
850849 response.status(400).send('Error: no response body detected');
@@ -896,7 +895,7 @@ router.post('/edit', urlencodedParser, validateAvatarUrlMiddleware, async functi
896895 * @param {Object} response - The HTTP response object.
897896 * @returns {void}
898897 */
899898router.post('/edit-attribute', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
900899 console.debug(request.body);
901900 if (!request.body) {
902901 console.warn('Error: no response body detected');
@@ -942,7 +941,7 @@ router.post('/edit-attribute', jsonParser, validateAvatarUrlMiddleware, async fu
942941 *
943942 * @returns {void}
944943 * */
945944router.post('/merge-attributes', jsonParser, getFileNameValidationFunction('avatar'), async function (request, response) {
946945 try {
947946 const update = request.body;
948947 const avatarPath = path.join(request.user.directories.characters, update.avatar);
@@ -973,7 +972,7 @@ router.post('/merge-attributes', jsonParser, getFileNameValidationFunction('avat
973972 }
974973});
975974
976975router.post('/delete', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
977976 if (!request.body || !request.body.avatar_url) {
978977 return response.sendStatus(400);
979978 }
@@ -1023,7 +1022,7 @@ router.post('/delete', jsonParser, validateAvatarUrlMiddleware, async function (
10231022 * @param {import("express").Response} response The HTTP response object.
10241023 * @return {void}
10251024 */
10261025router.post('/all', jsonParser, async function (request, response) {
10271026 try {
10281027 const files = fs.readdirSync(request.user.directories.characters);
10291028 const pngFiles = files.filter(file => file.endsWith('.png'));
@@ -1036,7 +1035,7 @@ router.post('/all', jsonParser, async function (request, response) {
10361035 }
10371036});
10381037
10391038router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
10401039 try {
10411040 if (!request.body) return response.sendStatus(400);
10421041 const item = request.body.avatar_url;
@@ -1055,7 +1054,7 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, async function (req
10551054 }
10561055});
10571056
10581057router.post('/chats', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
10591058 try {
10601059 if (!request.body) return response.sendStatus(400);
10611060
@@ -1164,7 +1163,7 @@ function getPreservedName(request) {
11641163 : undefined;
11651164}
11661165
11671166router.post('/import', urlencodedParser, async function (request, response) {
11681167 if (!request.body || !request.file) return response.sendStatus(400);
11691168
11701169 const uploadPath = path.join(request.file.destination, request.file.filename);
@@ -1204,7 +1203,7 @@ router.post('/import', urlencodedParser, async function (request, response) {
12041203 }
12051204});
12061205
12071206router.post('/duplicate', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
12081207 try {
12091208 if (!request.body.avatar_url) {
12101209 console.warn('avatar URL not found in request body');
@@ -1250,7 +1249,7 @@ router.post('/duplicate', jsonParser, validateAvatarUrlMiddleware, async functio
12501249 }
12511250});
12521251
12531252router.post('/export', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
12541253 try {
12551254 if (!request.body.format || !request.body.avatar_url) {
12561255 return response.sendStatus(400);
src/endpoints/chats.js+11 -13
@@ -8,7 +8,6 @@ import sanitize from 'sanitize-filename';
88import { sync as writeFileAtomicSync } from 'write-file-atomic';
99import _ from 'lodash';
1010
11-import { jsonParser, urlencodedParser } from '../express-common.js';
1211import validateAvatarUrlMiddleware from '../middleware/validateFileName.js';
1312import {
1413 getConfigValue,
@@ -295,7 +294,7 @@ function importRisuChat(userName, characterName, jsonData) {
295294
296295export const router = express.Router();
297296
298297router.post('/save', jsonParser, validateAvatarUrlMiddleware, function (request, response) {
299298 try {
300299 const directoryName = String(request.body.avatar_url).replace('.png', '');
301300 const chatData = request.body.chat;
@@ -311,7 +310,7 @@ router.post('/save', jsonParser, validateAvatarUrlMiddleware, function (request,
311310 }
312311});
313312
314313router.post('/get', jsonParser, validateAvatarUrlMiddleware, function (request, response) {
315314 try {
316315 const dirName = String(request.body.avatar_url).replace('.png', '');
317316 const directoryPath = path.join(request.user.directories.chats, dirName);
@@ -347,8 +346,7 @@ router.post('/get', jsonParser, validateAvatarUrlMiddleware, function (request,
347346 }
348347});
349348
350-
349+router.post('/rename', validateAvatarUrlMiddleware, async function (request, response) {
351-router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
352350 if (!request.body || !request.body.original_file || !request.body.renamed_file) {
353351 return response.sendStatus(400);
354352 }
@@ -373,7 +371,7 @@ router.post('/rename', jsonParser, validateAvatarUrlMiddleware, async function (
373371 return response.send({ ok: true, sanitizedFileName });
374372});
375373
376374router.post('/delete', jsonParser, validateAvatarUrlMiddleware, function (request, response) {
377375 const dirName = String(request.body.avatar_url).replace('.png', '');
378376 const fileName = String(request.body.chatfile);
379377 const filePath = path.join(request.user.directories.chats, dirName, sanitize(fileName));
@@ -389,7 +387,7 @@ router.post('/delete', jsonParser, validateAvatarUrlMiddleware, function (reques
389387 return response.send('ok');
390388});
391389
392390router.post('/export', jsonParser, validateAvatarUrlMiddleware, async function (request, response) {
393391 if (!request.body.file || (!request.body.avatar_url && request.body.is_group === false)) {
394392 return response.sendStatus(400);
395393 }
@@ -458,7 +456,7 @@ router.post('/export', jsonParser, validateAvatarUrlMiddleware, async function (
458456 }
459457});
460458
461459router.post('/group/import', urlencodedParser, function (request, response) {
462460 try {
463461 const filedata = request.file;
464462
@@ -478,7 +476,7 @@ router.post('/group/import', urlencodedParser, function (request, response) {
478476 }
479477});
480478
481479router.post('/import', urlencodedParser, validateAvatarUrlMiddleware, function (request, response) {
482480 if (!request.body) return response.sendStatus(400);
483481
484482 const format = request.body.file_type;
@@ -571,7 +569,7 @@ router.post('/import', urlencodedParser, validateAvatarUrlMiddleware, function (
571569 }
572570});
573571
574572router.post('/group/get', jsonParser, (request, response) => {
575573 if (!request.body || !request.body.id) {
576574 return response.sendStatus(400);
577575 }
@@ -591,7 +589,7 @@ router.post('/group/get', jsonParser, (request, response) => {
591589 }
592590});
593591
594592router.post('/group/delete', jsonParser, (request, response) => {
595593 if (!request.body || !request.body.id) {
596594 return response.sendStatus(400);
597595 }
@@ -607,7 +605,7 @@ router.post('/group/delete', jsonParser, (request, response) => {
607605 return response.send({ error: true });
608606});
609607
610608router.post('/group/save', jsonParser, (request, response) => {
611609 if (!request.body || !request.body.id) {
612610 return response.sendStatus(400);
613611 }
@@ -626,7 +624,7 @@ router.post('/group/save', jsonParser, (request, response) => {
626624 return response.send({ ok: true });
627625});
628626
629627router.post('/search', jsonParser, validateAvatarUrlMiddleware, function (request, response) {
630628 try {
631629 const { query, avatar_url, group_id } = request.body;
632630 let chatFiles = [];
src/endpoints/classify.js+2 -3
@@ -1,7 +1,6 @@
11import express from 'express';
22
33import { getPipeline } from '../transformers.js';
4-import { jsonParser } from '../express-common.js';
54
65const TASK = 'text-classification';
76
@@ -12,7 +11,7 @@ export const router = express.Router();
1211 */
1312const cacheObject = new Map();
1413
1514router.post('/labels', jsonParser, async (req, res) => {
1615 try {
1716 const pipe = await getPipeline(TASK);
1817 const result = Object.keys(pipe.model.config.label2id);
@@ -23,7 +22,7 @@ router.post('/labels', jsonParser, async (req, res) => {
2322 }
2423});
2524
2625router.post('/', jsonParser, async (req, res) => {
2726 try {
2827 const { text } = req.body;
2928
src/endpoints/content-manager.js+2 -3
@@ -9,7 +9,6 @@ import sanitize from 'sanitize-filename';
99import { sync as writeFileAtomicSync } from 'write-file-atomic';
1010
1111import { getConfigValue, color } from '../util.js';
12-import { jsonParser } from '../express-common.js';
1312import { write } from '../character-card-parser.js';
1413
1514const contentDirectory = path.join(process.cwd(), 'default/content');
@@ -627,7 +626,7 @@ function isHostWhitelisted(host) {
627626
628627export const router = express.Router();
629628
630629router.post('/importURL', jsonParser, async (request, response) => {
631630 if (!request.body.url) {
632631 return response.sendStatus(400);
633632 }
@@ -713,7 +712,7 @@ router.post('/importURL', jsonParser, async (request, response) => {
713712 }
714713});
715714
716715router.post('/importUUID', jsonParser, async (request, response) => {
717716 if (!request.body.url) {
718717 return response.sendStatus(400);
719718 }
src/endpoints/extensions.js+6 -7
@@ -6,7 +6,6 @@ import sanitize from 'sanitize-filename';
66import { default as simpleGit } from 'simple-git';
77
88import { PUBLIC_DIRECTORIES } from '../constants.js';
9-import { jsonParser } from '../express-common.js';
109
1110/**
1211 * This function extracts the extension information from the manifest file.
@@ -60,7 +59,7 @@ export const router = express.Router();
6059 *
6160 * @returns {void}
6261 */
6362router.post('/install', jsonParser, async (request, response) => {
6463 if (!request.body.url) {
6564 return response.status(400).send('Bad Request: URL is required in the request body.');
6665 }
@@ -114,7 +113,7 @@ router.post('/install', jsonParser, async (request, response) => {
114113 *
115114 * @returns {void}
116115 */
117116router.post('/update', jsonParser, async (request, response) => {
118117 const git = simpleGit();
119118 if (!request.body.extensionName) {
120119 return response.status(400).send('Bad Request: extensionName is required in the request body.');
@@ -155,7 +154,7 @@ router.post('/update', jsonParser, async (request, response) => {
155154 }
156155});
157156
158157router.post('/move', jsonParser, async (request, response) => {
159158 try {
160159 const { extensionName, source, destination } = request.body;
161160
@@ -209,7 +208,7 @@ router.post('/move', jsonParser, async (request, response) => {
209208 *
210209 * @returns {void}
211210 */
212211router.post('/version', jsonParser, async (request, response) => {
213212 const git = simpleGit();
214213 if (!request.body.extensionName) {
215214 return response.status(400).send('Bad Request: extensionName is required in the request body.');
@@ -256,7 +255,7 @@ router.post('/version', jsonParser, async (request, response) => {
256255 *
257256 * @returns {void}
258257 */
259258router.post('/delete', jsonParser, async (request, response) => {
260259 if (!request.body.extensionName) {
261260 return response.status(400).send('Bad Request: extensionName is required in the request body.');
262261 }
@@ -291,7 +290,7 @@ router.post('/delete', jsonParser, async (request, response) => {
291290 * Discover the extension folders
292291 * If the folder is called third-party, search for subfolders instead
293292 */
294293router.get('/discover', jsonParser, function (request, response) {
295294 if (!fs.existsSync(path.join(request.user.directories.extensions))) {
296295 fs.mkdirSync(path.join(request.user.directories.extensions));
297296 }
src/endpoints/files.js+4 -5
@@ -6,12 +6,11 @@ import sanitize from 'sanitize-filename';
66import { sync as writeFileSyncAtomic } from 'write-file-atomic';
77
88import { validateAssetFileName } from './assets.js';
9-import { jsonParser } from '../express-common.js';
109import { clientRelativePath } from '../util.js';
1110
1211export const router = express.Router();
1312
1413router.post('/sanitize-filename', jsonParser, async (request, response) => {
1514 try {
1615 const fileName = String(request.body.fileName);
1716 if (!fileName) {
@@ -26,7 +25,7 @@ router.post('/sanitize-filename', jsonParser, async (request, response) => {
2625 }
2726});
2827
2928router.post('/upload', jsonParser, async (request, response) => {
3029 try {
3130 if (!request.body.name) {
3231 return response.status(400).send('No upload name specified');
@@ -52,7 +51,7 @@ router.post('/upload', jsonParser, async (request, response) => {
5251 }
5352});
5453
5554router.post('/delete', jsonParser, async (request, response) => {
5655 try {
5756 if (!request.body.path) {
5857 return response.status(400).send('No path specified');
@@ -76,7 +75,7 @@ router.post('/delete', jsonParser, async (request, response) => {
7675 }
7776});
7877
7978router.post('/verify', jsonParser, async (request, response) => {
8079 try {
8180 if (!Array.isArray(request.body.urls)) {
8281 return response.status(400).send('No URLs specified');
src/endpoints/google.js+2 -3
@@ -4,14 +4,13 @@ import express from 'express';
44import { speak, languages } from 'google-translate-api-x';
55
66import { readSecret, SECRET_KEYS } from './secrets.js';
7-import { jsonParser } from '../express-common.js';
87import { GEMINI_SAFETY } from '../constants.js';
98
109const API_MAKERSUITE = 'https://generativelanguage.googleapis.com';
1110
1211export const router = express.Router();
1312
1413router.post('/caption-image', jsonParser, async (request, response) => {
1514 try {
1615 const mimeType = request.body.image.split(';')[0].split(':')[1];
1716 const base64Data = request.body.image.split(',')[1];
@@ -75,7 +74,7 @@ router.post('/list-voices', (_, response) => {
7574 return response.json(languages);
7675});
7776
7877router.post('/generate-voice', jsonParser, async (request, response) => {
7978 try {
8079 const text = request.body.text;
8180 const voice = request.body.voice ?? 'en';
src/endpoints/groups.js+4 -5
@@ -5,12 +5,11 @@ import express from 'express';
55import sanitize from 'sanitize-filename';
66import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8-import { jsonParser } from '../express-common.js';
98import { humanizedISO8601DateTime } from '../util.js';
109
1110export const router = express.Router();
1211
1312router.post('/all', jsonParser, (request, response) => {
1413 const groups = [];
1514
1615 if (!fs.existsSync(request.user.directories.groups)) {
@@ -54,7 +53,7 @@ router.post('/all', jsonParser, (request, response) => {
5453 return response.send(groups);
5554});
5655
5756router.post('/create', jsonParser, (request, response) => {
5857 if (!request.body) {
5958 return response.sendStatus(400);
6059 }
@@ -88,7 +87,7 @@ router.post('/create', jsonParser, (request, response) => {
8887 return response.send(groupMetadata);
8988});
9089
9190router.post('/edit', jsonParser, (request, response) => {
9291 if (!request.body || !request.body.id) {
9392 return response.sendStatus(400);
9493 }
@@ -100,7 +99,7 @@ router.post('/edit', jsonParser, (request, response) => {
10099 return response.send({ ok: true });
101100});
102101
103102router.post('/delete', jsonParser, async (request, response) => {
104103 if (!request.body || !request.body.id) {
105104 return response.sendStatus(400);
106105 }
src/endpoints/horde.js+11 -12
@@ -3,7 +3,6 @@ import express from 'express';
33import { AIHorde, ModelGenerationInputStableSamplers, ModelInterrogationFormTypes, HordeAsyncRequestStates } from '@zeldafan0225/ai_horde';
44import { getVersion, delay, Cache } from '../util.js';
55import { readSecret, SECRET_KEYS } from './secrets.js';
6-import { jsonParser } from '../express-common.js';
76
87const ANONYMOUS_KEY = '0000000000';
98const HORDE_TEXT_MODEL_METADATA_URL = 'https://raw.githubusercontent.com/db0/AI-Horde-text-model-reference/main/db.json';
@@ -56,7 +55,7 @@ function sanitizeHordeImagePrompt(prompt) {
5655 return prompt;
5756}
5857
5958router.post('/text-workers', jsonParser, async (request, response) => {
6059 try {
6160 const cachedWorkers = cache.get('workers');
6261
@@ -94,7 +93,7 @@ async function mergeModelsAndMetadata(models, metadata) {
9493 });
9594}
9695
9796router.post('/text-models', jsonParser, async (request, response) => {
9897 try {
9998 const cachedModels = cache.get('models');
10099 if (cachedModels && !request.body.force) {
@@ -127,7 +126,7 @@ router.post('/text-models', jsonParser, async (request, response) => {
127126 }
128127});
129128
130129router.post('/status', jsonParser, async (_, response) => {
131130 try {
132131 const agent = await getClientAgent();
133132 const fetchResult = await fetch('https://aihorde.net/api/v2/status/heartbeat', {
@@ -143,7 +142,7 @@ router.post('/status', jsonParser, async (_, response) => {
143142 }
144143});
145144
146145router.post('/cancel-task', jsonParser, async (request, response) => {
147146 try {
148147 const taskId = request.body.taskId;
149148 const agent = await getClientAgent();
@@ -163,7 +162,7 @@ router.post('/cancel-task', jsonParser, async (request, response) => {
163162 }
164163});
165164
166165router.post('/task-status', jsonParser, async (request, response) => {
167166 try {
168167 const taskId = request.body.taskId;
169168 const agent = await getClientAgent();
@@ -182,7 +181,7 @@ router.post('/task-status', jsonParser, async (request, response) => {
182181 }
183182});
184183
185184router.post('/generate-text', jsonParser, async (request, response) => {
186185 const apiKey = readSecret(request.user.directories, SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
187186 const url = 'https://aihorde.net/api/v2/generate/text/async';
188187 const agent = await getClientAgent();
@@ -213,7 +212,7 @@ router.post('/generate-text', jsonParser, async (request, response) => {
213212 }
214213});
215214
216215router.post('/sd-samplers', jsonParser, async (_, response) => {
217216 try {
218217 const samplers = Object.values(ModelGenerationInputStableSamplers);
219218 response.send(samplers);
@@ -223,7 +222,7 @@ router.post('/sd-samplers', jsonParser, async (_, response) => {
223222 }
224223});
225224
226225router.post('/sd-models', jsonParser, async (_, response) => {
227226 try {
228227 const ai_horde = await getHordeClient();
229228 const models = await ai_horde.getModels();
@@ -234,7 +233,7 @@ router.post('/sd-models', jsonParser, async (_, response) => {
234233 }
235234});
236235
237236router.post('/caption-image', jsonParser, async (request, response) => {
238237 try {
239238 const api_key_horde = readSecret(request.user.directories, SECRET_KEYS.HORDE) || ANONYMOUS_KEY;
240239 const ai_horde = await getHordeClient();
@@ -286,7 +285,7 @@ router.post('/caption-image', jsonParser, async (request, response) => {
286285 }
287286});
288287
289288router.post('/user-info', jsonParser, async (request, response) => {
290289 const api_key_horde = readSecret(request.user.directories, SECRET_KEYS.HORDE);
291290
292291 if (!api_key_horde) {
@@ -303,7 +302,7 @@ router.post('/user-info', jsonParser, async (request, response) => {
303302 }
304303});
305304
306305router.post('/generate-image', jsonParser, async (request, response) => {
307306 if (!request.body.prompt) {
308307 return response.sendStatus(400);
309308 }
src/endpoints/images.js+2 -3
@@ -5,7 +5,6 @@ import { Buffer } from 'node:buffer';
55import express from 'express';
66import sanitize from 'sanitize-filename';
77
8-import { jsonParser } from '../express-common.js';
98import { clientRelativePath, removeFileExtension, getImages } from '../util.js';
109
1110/**
@@ -36,7 +35,7 @@ export const router = express.Router();
3635 * @param {string} [request.body.ch_name] - Optional character name to determine the sub-directory.
3736 * @returns {Object} response - The response object containing the path where the image was saved.
3837 */
3938router.post('/upload', jsonParser, async (request, response) => {
4039 // Check for image data
4140 if (!request.body || !request.body.image) {
4241 return response.status(400).send({ error: 'No image data provided' });
@@ -76,7 +75,7 @@ router.post('/upload', jsonParser, async (request, response) => {
7675 }
7776});
7877
7978router.post('/list/:folder?', jsonParser, (request, response) => {
8079 try {
8180 if (request.params.folder) {
8281 if (request.body.folder) {
src/endpoints/moving-ui.js+1 -3
@@ -3,11 +3,9 @@ import express from 'express';
33import sanitize from 'sanitize-filename';
44import { sync as writeFileAtomicSync } from 'write-file-atomic';
55
6-import { jsonParser } from '../express-common.js';
7-
86export const router = express.Router();
97
108router.post('/save', jsonParser, (request, response) => {
119 if (!request.body || !request.body.name) {
1210 return response.sendStatus(400);
1311 }
src/endpoints/novelai.js+4 -5
@@ -6,7 +6,6 @@ import express from 'express';
66
77import { readSecret, SECRET_KEYS } from './secrets.js';
88import { readAllChunks, extractFileFromZipBuffer, forwardFetchResponse } from '../util.js';
9-import { jsonParser } from '../express-common.js';
109
1110const API_NOVELAI = 'https://api.novelai.net';
1211const TEXT_NOVELAI = 'https://text.novelai.net';
@@ -115,7 +114,7 @@ function getRepPenaltyWhitelist(model) {
115114
116115export const router = express.Router();
117116
118117router.post('/status', jsonParser, async function (req, res) {
119118 if (!req.body) return res.sendStatus(400);
120119 const api_key_novel = readSecret(req.user.directories, SECRET_KEYS.NOVEL);
121120
@@ -150,7 +149,7 @@ router.post('/status', jsonParser, async function (req, res) {
150149 }
151150});
152151
153152router.post('/generate', jsonParser, async function (req, res) {
154153 if (!req.body) return res.sendStatus(400);
155154
156155 const api_key_novel = readSecret(req.user.directories, SECRET_KEYS.NOVEL);
@@ -284,7 +283,7 @@ router.post('/generate', jsonParser, async function (req, res) {
284283 }
285284});
286285
287286router.post('/generate-image', jsonParser, async (request, response) => {
288287 if (!request.body) {
289288 return response.sendStatus(400);
290289 }
@@ -418,7 +417,7 @@ router.post('/generate-image', jsonParser, async (request, response) => {
418417 }
419418});
420419
421420router.post('/generate-voice', jsonParser, async (request, response) => {
422421 const token = readSecret(request.user.directories, SECRET_KEYS.NOVEL);
423422
424423 if (!token) {
src/endpoints/openai.js+5 -6
@@ -5,7 +5,6 @@ import fetch from 'node-fetch';
55import FormData from 'form-data';
66import express from 'express';
77
8-import { jsonParser, urlencodedParser } from '../express-common.js';
98import { getConfigValue, mergeObjectWithYaml, excludeKeysByYaml, trimV1 } from '../util.js';
109import { setAdditionalHeaders } from '../additional-headers.js';
1110import { readSecret, SECRET_KEYS } from './secrets.js';
@@ -13,7 +12,7 @@ import { OPENROUTER_HEADERS } from '../constants.js';
1312
1413export const router = express.Router();
1514
1615router.post('/caption-image', jsonParser, async (request, response) => {
1716 try {
1817 let key = '';
1918 let headers = {};
@@ -189,7 +188,7 @@ router.post('/caption-image', jsonParser, async (request, response) => {
189188 }
190189});
191190
192191router.post('/transcribe-audio', urlencodedParser, async (request, response) => {
193192 try {
194193 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);
195194
@@ -237,7 +236,7 @@ router.post('/transcribe-audio', urlencodedParser, async (request, response) =>
237236 }
238237});
239238
240239router.post('/generate-voice', jsonParser, async (request, response) => {
241240 try {
242241 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);
243242
@@ -276,7 +275,7 @@ router.post('/generate-voice', jsonParser, async (request, response) => {
276275 }
277276});
278277
279278router.post('/generate-image', jsonParser, async (request, response) => {
280279 try {
281280 const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);
282281
@@ -312,7 +311,7 @@ router.post('/generate-image', jsonParser, async (request, response) => {
312311
313312const custom = express.Router();
314313
315314custom.post('/generate-voice', jsonParser, async (request, response) => {
316315 try {
317316 const key = readSecret(request.user.directories, SECRET_KEYS.CUSTOM_OPENAI_TTS);
318317 const { input, provider_endpoint, response_format, voice, speed, model } = request.body;
src/endpoints/openrouter.js+2 -3
@@ -1,10 +1,9 @@
11import express from 'express';
2-import { jsonParser } from '../express-common.js';
32
43export const router = express.Router();
54const API_OPENROUTER = 'https://openrouter.ai/api/v1';
65
76router.post('/models/providers', jsonParser, async (req, res) => {
87 try {
98 const { model } = req.body;
109 const response = await fetch(`${API_OPENROUTER}/models/${model}/endpoints`, {
@@ -29,7 +28,7 @@ router.post('/models/providers', jsonParser, async (req, res) => {
2928 }
3029});
3130
3231router.post('/models/multimodal', jsonParser, async (_req, res) => {
3332 try {
3433 // The endpoint is available without authentication
3534 const response = await fetch(`${API_OPENROUTER}/models`, {
src/endpoints/presets.js+5 -6
@@ -6,7 +6,6 @@ import sanitize from 'sanitize-filename';
66import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
88import { getDefaultPresetFile, getDefaultPresets } from './content-manager.js';
9-import { jsonParser } from '../express-common.js';
109
1110/**
1211 * Gets the folder and extension for the preset settings based on the API source ID.
@@ -38,7 +37,7 @@ function getPresetSettingsByAPI(apiId, directories) {
3837
3938export const router = express.Router();
4039
4140router.post('/save', jsonParser, function (request, response) {
4241 const name = sanitize(request.body.name);
4342 if (!request.body.preset || !name) {
4443 return response.sendStatus(400);
@@ -56,7 +55,7 @@ router.post('/save', jsonParser, function (request, response) {
5655 return response.send({ name });
5756});
5857
5958router.post('/delete', jsonParser, function (request, response) {
6059 const name = sanitize(request.body.name);
6160 if (!name) {
6261 return response.sendStatus(400);
@@ -79,7 +78,7 @@ router.post('/delete', jsonParser, function (request, response) {
7978 }
8079});
8180
8281router.post('/restore', jsonParser, function (request, response) {
8382 try {
8483 const settings = getPresetSettingsByAPI(request.body.apiId, request.user.directories);
8584 const name = sanitize(request.body.name);
@@ -102,7 +101,7 @@ router.post('/restore', jsonParser, function (request, response) {
102101});
103102
104103// TODO: Merge with /api/presets/save
105104router.post('/save-openai', jsonParser, function (request, response) {
106105 if (!request.body || typeof request.query.name !== 'string') return response.sendStatus(400);
107106 const name = sanitize(request.query.name);
108107 if (!name) return response.sendStatus(400);
@@ -114,7 +113,7 @@ router.post('/save-openai', jsonParser, function (request, response) {
114113});
115114
116115// TODO: Merge with /api/presets/delete
117116router.post('/delete-openai', jsonParser, function (request, response) {
118117 if (!request.body || !request.body.name) {
119118 return response.sendStatus(400);
120119 }
src/endpoints/quick-replies.js+2 -4
@@ -5,11 +5,9 @@ import express from 'express';
55import sanitize from 'sanitize-filename';
66import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8-import { jsonParser } from '../express-common.js';
9-
108export const router = express.Router();
119
1210router.post('/save', jsonParser, (request, response) => {
1311 if (!request.body || !request.body.name) {
1412 return response.sendStatus(400);
1513 }
@@ -20,7 +18,7 @@ router.post('/save', jsonParser, (request, response) => {
2018 return response.sendStatus(200);
2119});
2220
2321router.post('/delete', jsonParser, (request, response) => {
2422 if (!request.body || !request.body.name) {
2523 return response.sendStatus(400);
2624 }
src/endpoints/search.js+7 -8
@@ -3,7 +3,6 @@ import express from 'express';
33
44import { decode } from 'html-entities';
55import { readSecret, SECRET_KEYS } from './secrets.js';
6-import { jsonParser } from '../express-common.js';
76import { trimV1 } from '../util.js';
87import { setAdditionalHeaders } from '../additional-headers.js';
98
@@ -91,7 +90,7 @@ async function extractTranscript(videoPageBody, lang) {
9190 return transcriptText;
9291}
9392
9493router.post('/serpapi', jsonParser, async (request, response) => {
9594 try {
9695 const key = readSecret(request.user.directories, SECRET_KEYS.SERPAPI);
9796
@@ -124,7 +123,7 @@ router.post('/serpapi', jsonParser, async (request, response) => {
124123 * Get the transcript of a YouTube video
125124 * @copyright https://github.com/Kakulukian/youtube-transcript (MIT License)
126125 */
127126router.post('/transcript', jsonParser, async (request, response) => {
128127 try {
129128 const id = request.body.id;
130129 const lang = request.body.lang;
@@ -161,7 +160,7 @@ router.post('/transcript', jsonParser, async (request, response) => {
161160 }
162161});
163162
164163router.post('/searxng', jsonParser, async (request, response) => {
165164 try {
166165 const { baseUrl, query, preferences, categories } = request.body;
167166
@@ -215,7 +214,7 @@ router.post('/searxng', jsonParser, async (request, response) => {
215214 }
216215});
217216
218217router.post('/tavily', jsonParser, async (request, response) => {
219218 try {
220219 const apiKey = readSecret(request.user.directories, SECRET_KEYS.TAVILY);
221220
@@ -264,7 +263,7 @@ router.post('/tavily', jsonParser, async (request, response) => {
264263 }
265264});
266265
267266router.post('/koboldcpp', jsonParser, async (request, response) => {
268267 try {
269268 const { query, url } = request.body;
270269
@@ -300,7 +299,7 @@ router.post('/koboldcpp', jsonParser, async (request, response) => {
300299 }
301300});
302301
303302router.post('/serper', jsonParser, async (request, response) => {
304303 try {
305304 const key = readSecret(request.user.directories, SECRET_KEYS.SERPER);
306305
@@ -342,7 +341,7 @@ router.post('/serper', jsonParser, async (request, response) => {
342341 }
343342});
344343
345344router.post('/visit', jsonParser, async (request, response) => {
346345 try {
347346 const url = request.body.url;
348347 const html = Boolean(request.body.html ?? true);
src/endpoints/secrets.js+4 -5
@@ -4,7 +4,6 @@ import path from 'node:path';
44import express from 'express';
55import { sync as writeFileAtomicSync } from 'write-file-atomic';
66import { getConfigValue } from '../util.js';
7-import { jsonParser } from '../express-common.js';
87
98export const SECRETS_FILE = 'secrets.json';
109export const SECRET_KEYS = {
@@ -164,7 +163,7 @@ export function getAllSecrets(directories) {
164163
165164export const router = express.Router();
166165
167166router.post('/write', jsonParser, (request, response) => {
168167 const key = request.body.key;
169168 const value = request.body.value;
170169
@@ -172,7 +171,7 @@ router.post('/write', jsonParser, (request, response) => {
172171 return response.send('ok');
173172});
174173
175174router.post('/read', jsonParser, (request, response) => {
176175 try {
177176 const state = readSecretState(request.user.directories);
178177 return response.send(state);
@@ -182,7 +181,7 @@ router.post('/read', jsonParser, (request, response) => {
182181 }
183182});
184183
185184router.post('/view', jsonParser, async (request, response) => {
186185 const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean');
187186
188187 if (!allowKeysExposure) {
@@ -204,7 +203,7 @@ router.post('/view', jsonParser, async (request, response) => {
204203 }
205204});
206205
207206router.post('/find', jsonParser, (request, response) => {
208207 const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean');
209208 const key = request.body.key;
210209
src/endpoints/settings.js+6 -7
@@ -7,7 +7,6 @@ import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
88import { SETTINGS_FILE } from '../constants.js';
99import { getConfigValue, generateTimestamp, removeOldBackups } from '../util.js';
10-import { jsonParser } from '../express-common.js';
1110import { getAllUserHandles, getUserDirectories } from '../users.js';
1211import { getFileNameValidationFunction } from '../middleware/validateFileName.js';
1312
@@ -195,7 +194,7 @@ function getLatestBackup(handle) {
195194
196195export const router = express.Router();
197196
198197router.post('/save', jsonParser, function (request, response) {
199198 try {
200199 const pathToSettings = path.join(request.user.directories.root, SETTINGS_FILE);
201200 writeFileAtomicSync(pathToSettings, JSON.stringify(request.body, null, 4), 'utf8');
@@ -208,7 +207,7 @@ router.post('/save', jsonParser, function (request, response) {
208207});
209208
210209// Wintermute's code
211210router.post('/get', jsonParser, (request, response) => {
212211 let settings;
213212 try {
214213 const pathToSettings = path.join(request.user.directories.root, SETTINGS_FILE);
@@ -279,7 +278,7 @@ router.post('/get', jsonParser, (request, response) => {
279278 });
280279});
281280
282281router.post('/get-snapshots', jsonParser, async (request, response) => {
283282 try {
284283 const snapshots = fs.readdirSync(request.user.directories.backups);
285284 const userFilesPattern = getFilePrefix(request.user.profile.handle);
@@ -297,7 +296,7 @@ router.post('/get-snapshots', jsonParser, async (request, response) => {
297296 }
298297});
299298
300299router.post('/load-snapshot', jsonParser, getFileNameValidationFunction('name'), async (request, response) => {
301300 try {
302301 const userFilesPattern = getFilePrefix(request.user.profile.handle);
303302
@@ -321,7 +320,7 @@ router.post('/load-snapshot', jsonParser, getFileNameValidationFunction('name'),
321320 }
322321});
323322
324323router.post('/make-snapshot', jsonParser, async (request, response) => {
325324 try {
326325 backupUserSettings(request.user.profile.handle, false);
327326 response.sendStatus(204);
@@ -331,7 +330,7 @@ router.post('/make-snapshot', jsonParser, async (request, response) => {
331330 }
332331});
333332
334333router.post('/restore-snapshot', jsonParser, getFileNameValidationFunction('name'), async (request, response) => {
335334 try {
336335 const userFilesPattern = getFilePrefix(request.user.profile.handle);
337336
src/endpoints/speech.js+2 -3
@@ -1,7 +1,6 @@
11import { Buffer } from 'node:buffer';
22import express from 'express';
33import wavefile from 'wavefile';
4-import { jsonParser } from '../express-common.js';
54import { getPipeline } from '../transformers.js';
65
76export const router = express.Router();
@@ -34,7 +33,7 @@ function getWaveFile(audio) {
3433 return audioData;
3534}
3635
3736router.post('/recognize', jsonParser, async (req, res) => {
3837 try {
3938 const TASK = 'automatic-speech-recognition';
4039 const { model, audio, lang } = req.body;
@@ -53,7 +52,7 @@ router.post('/recognize', jsonParser, async (req, res) => {
5352 }
5453});
5554
5655router.post('/synthesize', jsonParser, async (req, res) => {
5756 try {
5857 const TASK = 'text-to-speech';
5958 const { text, model, speaker } = req.body;
src/endpoints/sprites.js+4 -5
@@ -7,7 +7,6 @@ import sanitize from 'sanitize-filename';
77import { sync as writeFileAtomicSync } from 'write-file-atomic';
88
99import { getImageBuffers } from '../util.js';
10-import { jsonParser, urlencodedParser } from '../express-common.js';
1110
1211/**
1312 * Gets the path to the sprites folder for the provided character name
@@ -109,7 +108,7 @@ export function importRisuSprites(directories, data) {
109108
110109export const router = express.Router();
111110
112111router.get('/get', jsonParser, function (request, response) {
113112 const name = String(request.query.name);
114113 const isSubfolder = name.includes('/');
115114 const spritesPath = getSpritesPath(request.user.directories, name, isSubfolder);
@@ -144,7 +143,7 @@ router.get('/get', jsonParser, function (request, response) {
144143 return response.send(sprites);
145144});
146145
147146router.post('/delete', jsonParser, async (request, response) => {
148147 const label = request.body.label;
149148 const name = request.body.name;
150149 const spriteName = request.body.spriteName || label;
@@ -177,7 +176,7 @@ router.post('/delete', jsonParser, async (request, response) => {
177176 }
178177});
179178
180179router.post('/upload-zip', urlencodedParser, async (request, response) => {
181180 const file = request.file;
182181 const name = request.body.name;
183182
@@ -224,7 +223,7 @@ router.post('/upload-zip', urlencodedParser, async (request, response) => {
224223 }
225224});
226225
227226router.post('/upload', urlencodedParser, async (request, response) => {
228227 const file = request.file;
229228 const label = request.body.label;
230229 const name = request.body.name;
src/endpoints/stable-diffusion.js+38 -39
@@ -10,7 +10,6 @@ import urlJoin from 'url-join';
1010import _ from 'lodash';
1111
1212import { delay, getBasicAuthHeader, tryParse } from '../util.js';
13-import { jsonParser } from '../express-common.js';
1413import { readSecret, SECRET_KEYS } from './secrets.js';
1514
1615/**
@@ -27,7 +26,7 @@ function getComfyWorkflows(directories) {
2726
2827export const router = express.Router();
2928
3029router.post('/ping', jsonParser, async (request, response) => {
3130 try {
3231 const url = new URL(request.body.url);
3332 url.pathname = '/sdapi/v1/options';
@@ -50,7 +49,7 @@ router.post('/ping', jsonParser, async (request, response) => {
5049 }
5150});
5251
5352router.post('/upscalers', jsonParser, async (request, response) => {
5453 try {
5554 async function getUpscalerModels() {
5655 const url = new URL(request.body.url);
@@ -104,7 +103,7 @@ router.post('/upscalers', jsonParser, async (request, response) => {
104103 }
105104});
106105
107106router.post('/vaes', jsonParser, async (request, response) => {
108107 try {
109108 const autoUrl = new URL(request.body.url);
110109 autoUrl.pathname = '/sdapi/v1/sd-vae';
@@ -136,7 +135,7 @@ router.post('/vaes', jsonParser, async (request, response) => {
136135 }
137136});
138137
139138router.post('/samplers', jsonParser, async (request, response) => {
140139 try {
141140 const url = new URL(request.body.url);
142141 url.pathname = '/sdapi/v1/samplers';
@@ -163,7 +162,7 @@ router.post('/samplers', jsonParser, async (request, response) => {
163162 }
164163});
165164
166165router.post('/schedulers', jsonParser, async (request, response) => {
167166 try {
168167 const url = new URL(request.body.url);
169168 url.pathname = '/sdapi/v1/schedulers';
@@ -189,7 +188,7 @@ router.post('/schedulers', jsonParser, async (request, response) => {
189188 }
190189});
191190
192191router.post('/models', jsonParser, async (request, response) => {
193192 try {
194193 const url = new URL(request.body.url);
195194 url.pathname = '/sdapi/v1/sd-models';
@@ -215,7 +214,7 @@ router.post('/models', jsonParser, async (request, response) => {
215214 }
216215});
217216
218217router.post('/get-model', jsonParser, async (request, response) => {
219218 try {
220219 const url = new URL(request.body.url);
221220 url.pathname = '/sdapi/v1/options';
@@ -235,7 +234,7 @@ router.post('/get-model', jsonParser, async (request, response) => {
235234 }
236235});
237236
238237router.post('/set-model', jsonParser, async (request, response) => {
239238 try {
240239 async function getProgress() {
241240 const url = new URL(request.body.url);
@@ -294,7 +293,7 @@ router.post('/set-model', jsonParser, async (request, response) => {
294293 }
295294});
296295
297296router.post('/generate', jsonParser, async (request, response) => {
298297 try {
299298 try {
300299 const optionsUrl = new URL(request.body.url);
@@ -349,7 +348,7 @@ router.post('/generate', jsonParser, async (request, response) => {
349348 }
350349});
351350
352351router.post('/sd-next/upscalers', jsonParser, async (request, response) => {
353352 try {
354353 const url = new URL(request.body.url);
355354 url.pathname = '/sdapi/v1/upscalers';
@@ -384,7 +383,7 @@ router.post('/sd-next/upscalers', jsonParser, async (request, response) => {
384383
385384const comfy = express.Router();
386385
387386comfy.post('/ping', jsonParser, async (request, response) => {
388387 try {
389388 const url = new URL(urlJoin(request.body.url, '/system_stats'));
390389
@@ -400,7 +399,7 @@ comfy.post('/ping', jsonParser, async (request, response) => {
400399 }
401400});
402401
403402comfy.post('/samplers', jsonParser, async (request, response) => {
404403 try {
405404 const url = new URL(urlJoin(request.body.url, '/object_info'));
406405
@@ -418,7 +417,7 @@ comfy.post('/samplers', jsonParser, async (request, response) => {
418417 }
419418});
420419
421420comfy.post('/models', jsonParser, async (request, response) => {
422421 try {
423422 const url = new URL(urlJoin(request.body.url, '/object_info'));
424423
@@ -446,7 +445,7 @@ comfy.post('/models', jsonParser, async (request, response) => {
446445 }
447446});
448447
449448comfy.post('/schedulers', jsonParser, async (request, response) => {
450449 try {
451450 const url = new URL(urlJoin(request.body.url, '/object_info'));
452451
@@ -464,7 +463,7 @@ comfy.post('/schedulers', jsonParser, async (request, response) => {
464463 }
465464});
466465
467466comfy.post('/vaes', jsonParser, async (request, response) => {
468467 try {
469468 const url = new URL(urlJoin(request.body.url, '/object_info'));
470469
@@ -482,7 +481,7 @@ comfy.post('/vaes', jsonParser, async (request, response) => {
482481 }
483482});
484483
485484comfy.post('/workflows', jsonParser, async (request, response) => {
486485 try {
487486 const data = getComfyWorkflows(request.user.directories);
488487 return response.send(data);
@@ -492,7 +491,7 @@ comfy.post('/workflows', jsonParser, async (request, response) => {
492491 }
493492});
494493
495494comfy.post('/workflow', jsonParser, async (request, response) => {
496495 try {
497496 let filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));
498497 if (!fs.existsSync(filePath)) {
@@ -506,7 +505,7 @@ comfy.post('/workflow', jsonParser, async (request, response) => {
506505 }
507506});
508507
509508comfy.post('/save-workflow', jsonParser, async (request, response) => {
510509 try {
511510 const filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));
512511 writeFileAtomicSync(filePath, request.body.workflow, 'utf8');
@@ -518,7 +517,7 @@ comfy.post('/save-workflow', jsonParser, async (request, response) => {
518517 }
519518});
520519
521520comfy.post('/delete-workflow', jsonParser, async (request, response) => {
522521 try {
523522 const filePath = path.join(request.user.directories.comfyWorkflows, sanitize(String(request.body.file_name)));
524523 if (fs.existsSync(filePath)) {
@@ -531,7 +530,7 @@ comfy.post('/delete-workflow', jsonParser, async (request, response) => {
531530 }
532531});
533532
534533comfy.post('/generate', jsonParser, async (request, response) => {
535534 try {
536535 let item;
537536 const url = new URL(urlJoin(request.body.url, '/prompt'));
@@ -599,7 +598,7 @@ comfy.post('/generate', jsonParser, async (request, response) => {
599598
600599const together = express.Router();
601600
602601together.post('/models', jsonParser, async (request, response) => {
603602 try {
604603 const key = readSecret(request.user.directories, SECRET_KEYS.TOGETHERAI);
605604
@@ -638,7 +637,7 @@ together.post('/models', jsonParser, async (request, response) => {
638637 }
639638});
640639
641640together.post('/generate', jsonParser, async (request, response) => {
642641 try {
643642 const key = readSecret(request.user.directories, SECRET_KEYS.TOGETHERAI);
644643
@@ -694,7 +693,7 @@ together.post('/generate', jsonParser, async (request, response) => {
694693
695694const drawthings = express.Router();
696695
697696drawthings.post('/ping', jsonParser, async (request, response) => {
698697 try {
699698 const url = new URL(request.body.url);
700699 url.pathname = '/';
@@ -714,7 +713,7 @@ drawthings.post('/ping', jsonParser, async (request, response) => {
714713 }
715714});
716715
717716drawthings.post('/get-model', jsonParser, async (request, response) => {
718717 try {
719718 const url = new URL(request.body.url);
720719 url.pathname = '/';
@@ -733,7 +732,7 @@ drawthings.post('/get-model', jsonParser, async (request, response) => {
733732 }
734733});
735734
736735drawthings.post('/get-upscaler', jsonParser, async (request, response) => {
737736 try {
738737 const url = new URL(request.body.url);
739738 url.pathname = '/';
@@ -752,7 +751,7 @@ drawthings.post('/get-upscaler', jsonParser, async (request, response) => {
752751 }
753752});
754753
755754drawthings.post('/generate', jsonParser, async (request, response) => {
756755 try {
757756 console.debug('SD DrawThings API request:', request.body);
758757
@@ -788,7 +787,7 @@ drawthings.post('/generate', jsonParser, async (request, response) => {
788787
789788const pollinations = express.Router();
790789
791790pollinations.post('/models', jsonParser, async (_request, response) => {
792791 try {
793792 const modelsUrl = new URL('https://image.pollinations.ai/models');
794793 const result = await fetch(modelsUrl);
@@ -813,7 +812,7 @@ pollinations.post('/models', jsonParser, async (_request, response) => {
813812 }
814813});
815814
816815pollinations.post('/generate', jsonParser, async (request, response) => {
817816 try {
818817 const promptUrl = new URL(`https://image.pollinations.ai/prompt/${encodeURIComponent(request.body.prompt)}`);
819818 const params = new URLSearchParams({
@@ -850,7 +849,7 @@ pollinations.post('/generate', jsonParser, async (request, response) => {
850849
851850const stability = express.Router();
852851
853852stability.post('/generate', jsonParser, async (request, response) => {
854853 try {
855854 const key = readSecret(request.user.directories, SECRET_KEYS.STABILITY);
856855
@@ -910,7 +909,7 @@ stability.post('/generate', jsonParser, async (request, response) => {
910909
911910const blockentropy = express.Router();
912911
913912blockentropy.post('/models', jsonParser, async (request, response) => {
914913 try {
915914 const key = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);
916915
@@ -946,7 +945,7 @@ blockentropy.post('/models', jsonParser, async (request, response) => {
946945 }
947946});
948947
949948blockentropy.post('/generate', jsonParser, async (request, response) => {
950949 try {
951950 const key = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);
952951
@@ -993,7 +992,7 @@ blockentropy.post('/generate', jsonParser, async (request, response) => {
993992
994993const huggingface = express.Router();
995994
996995huggingface.post('/generate', jsonParser, async (request, response) => {
997996 try {
998997 const key = readSecret(request.user.directories, SECRET_KEYS.HUGGINGFACE);
999998
@@ -1032,7 +1031,7 @@ huggingface.post('/generate', jsonParser, async (request, response) => {
10321031
10331032const nanogpt = express.Router();
10341033
10351034nanogpt.post('/models', jsonParser, async (request, response) => {
10361035 try {
10371036 const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
10381037
@@ -1072,7 +1071,7 @@ nanogpt.post('/models', jsonParser, async (request, response) => {
10721071 }
10731072});
10741073
10751074nanogpt.post('/generate', jsonParser, async (request, response) => {
10761075 try {
10771076 const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
10781077
@@ -1116,7 +1115,7 @@ nanogpt.post('/generate', jsonParser, async (request, response) => {
11161115
11171116const bfl = express.Router();
11181117
11191118bfl.post('/generate', jsonParser, async (request, response) => {
11201119 try {
11211120 const key = readSecret(request.user.directories, SECRET_KEYS.BFL);
11221121
@@ -1230,7 +1229,7 @@ bfl.post('/generate', jsonParser, async (request, response) => {
12301229
12311230const falai = express.Router();
12321231
12331232falai.post('/models', jsonParser, async (_request, response) => {
12341233 try {
12351234 const modelsUrl = new URL('https://fal.ai/api/models?categories=text-to-image');
12361235 const result = await fetch(modelsUrl);
@@ -1260,7 +1259,7 @@ falai.post('/models', jsonParser, async (_request, response) => {
12601259 }
12611260});
12621261
12631262falai.post('/generate', jsonParser, async (request, response) => {
12641263 try {
12651264 const key = readSecret(request.user.directories, SECRET_KEYS.FALAI);
12661265
@@ -1276,7 +1275,7 @@ falai.post('/generate', jsonParser, async (request, response) => {
12761275 seed: request.body.seed ?? null,
12771276 guidance_scale: request.body.guidance,
12781277 enable_safety_checker: false, // Disable general safety checks
12791278 safety_tolerance: 6, // Make Flux the least strict
12801279 };
12811280
12821281 console.debug('FAL.AI request:', requestBody);
src/endpoints/stats.js+3 -4
@@ -8,7 +8,6 @@ import writeFileAtomic from 'write-file-atomic';
88const readFile = fs.promises.readFile;
99const readdir = fs.promises.readdir;
1010
11-import { jsonParser } from '../express-common.js';
1211import { getAllUserHandles, getUserDirectories } from '../users.js';
1312
1413const STATS_FILE = 'stats.json';
@@ -440,7 +439,7 @@ export const router = express.Router();
440439/**
441440 * Handle a POST request to get the stats object
442441 */
443442router.post('/get', jsonParser, function (request, response) {
444443 const stats = STATS.get(request.user.profile.handle) || {};
445444 response.send(stats);
446445});
@@ -448,7 +447,7 @@ router.post('/get', jsonParser, function (request, response) {
448447/**
449448 * Triggers the recreation of statistics from chat files.
450449 */
451450router.post('/recreate', jsonParser, async function (request, response) {
452451 try {
453452 await recreateStats(request.user.profile.handle, request.user.directories.chats, request.user.directories.characters);
454453 return response.sendStatus(200);
@@ -461,7 +460,7 @@ router.post('/recreate', jsonParser, async function (request, response) {
461460/**
462461 * Handle a POST request to update the stats object
463462*/
464463router.post('/update', jsonParser, function (request, response) {
465464 if (!request.body) return response.sendStatus(400);
466465 setCharStats(request.user.profile.handle, request.body);
467466 return response.sendStatus(200);
src/endpoints/themes.js+2 -4
@@ -5,11 +5,9 @@ import express from 'express';
55import sanitize from 'sanitize-filename';
66import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8-import { jsonParser } from '../express-common.js';
9-
108export const router = express.Router();
119
1210router.post('/save', jsonParser, (request, response) => {
1311 if (!request.body || !request.body.name) {
1412 return response.sendStatus(400);
1513 }
@@ -20,7 +18,7 @@ router.post('/save', jsonParser, (request, response) => {
2018 return response.sendStatus(200);
2119});
2220
2321router.post('/delete', jsonParser, function (request, response) {
2422 if (!request.body || !request.body.name) {
2523 return response.sendStatus(400);
2624 }
src/endpoints/thumbnails.js+1 -2
@@ -10,7 +10,6 @@ import { sync as writeFileAtomicSync } from 'write-file-atomic';
1010
1111import { getAllUserHandles, getUserDirectories } from '../users.js';
1212import { getConfigValue } from '../util.js';
13-import { jsonParser } from '../express-common.js';
1413
1514const thumbnailsEnabled = !!getConfigValue('thumbnails.enabled', true, 'boolean');
1615const quality = Math.min(100, Math.max(1, parseInt(getConfigValue('thumbnails.quality', 95, 'number'))));
@@ -176,7 +175,7 @@ export async function ensureThumbnailCache() {
176175export const router = express.Router();
177176
178177// Important: This route must be mounted as '/thumbnail'. It is used in the client code and saved to chat files.
179178router.get('/', jsonParser, async function (request, response) {
180179 try{
181180 if (typeof request.query.file !== 'string' || typeof request.query.type !== 'string') {
182181 return response.sendStatus(400);
src/endpoints/tokenizers.js+34 -35
@@ -11,7 +11,6 @@ import tiktoken from 'tiktoken';
1111
1212import { convertClaudePrompt } from '../prompt-converters.js';
1313import { TEXTGEN_TYPES } from '../constants.js';
14-import { jsonParser } from '../express-common.js';
1514import { setAdditionalHeaders } from '../additional-headers.js';
1615import { getConfigValue, isValidUrl } from '../util.js';
1716
@@ -689,36 +688,36 @@ function createWebTokenizerDecodingHandler(tokenizer) {
689688
690689export const router = express.Router();
691690
692691router.post('/llama/encode', jsonParser, createSentencepieceEncodingHandler(spp_llama));
693692router.post('/nerdstash/encode', jsonParser, createSentencepieceEncodingHandler(spp_nerd));
694693router.post('/nerdstash_v2/encode', jsonParser, createSentencepieceEncodingHandler(spp_nerd_v2));
695694router.post('/mistral/encode', jsonParser, createSentencepieceEncodingHandler(spp_mistral));
696695router.post('/yi/encode', jsonParser, createSentencepieceEncodingHandler(spp_yi));
697696router.post('/gemma/encode', jsonParser, createSentencepieceEncodingHandler(spp_gemma));
698697router.post('/jamba/encode', jsonParser, createSentencepieceEncodingHandler(spp_jamba));
699698router.post('/gpt2/encode', jsonParser, createTiktokenEncodingHandler('gpt2'));
700699router.post('/claude/encode', jsonParser, createWebTokenizerEncodingHandler(claude_tokenizer));
701700router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer));
702701router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer));
703702router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer));
704703router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer));
705704router.post('/deepseek/encode', jsonParser, createWebTokenizerEncodingHandler(deepseekTokenizer));
706705router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama));
707706router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd));
708707router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2));
709708router.post('/mistral/decode', jsonParser, createSentencepieceDecodingHandler(spp_mistral));
710709router.post('/yi/decode', jsonParser, createSentencepieceDecodingHandler(spp_yi));
711710router.post('/gemma/decode', jsonParser, createSentencepieceDecodingHandler(spp_gemma));
712711router.post('/jamba/decode', jsonParser, createSentencepieceDecodingHandler(spp_jamba));
713712router.post('/gpt2/decode', jsonParser, createTiktokenDecodingHandler('gpt2'));
714713router.post('/claude/decode', jsonParser, createWebTokenizerDecodingHandler(claude_tokenizer));
715714router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer));
716715router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer));
717716router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer));
718717router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer));
719718router.post('/deepseek/decode', jsonParser, createWebTokenizerDecodingHandler(deepseekTokenizer));
720719
721720router.post('/openai/encode', jsonParser, async function (req, res) {
722721 try {
723722 const queryModel = String(req.query.model || '');
724723
@@ -786,7 +785,7 @@ router.post('/openai/encode', jsonParser, async function (req, res) {
786785 }
787786});
788787
789788router.post('/openai/decode', jsonParser, async function (req, res) {
790789 try {
791790 const queryModel = String(req.query.model || '');
792791
@@ -854,7 +853,7 @@ router.post('/openai/decode', jsonParser, async function (req, res) {
854853 }
855854});
856855
857856router.post('/openai/count', jsonParser, async function (req, res) {
858857 try {
859858 if (!req.body) return res.sendStatus(400);
860859
@@ -968,7 +967,7 @@ router.post('/openai/count', jsonParser, async function (req, res) {
968967 }
969968});
970969
971970router.post('/remote/kobold/count', jsonParser, async function (request, response) {
972971 if (!request.body) {
973972 return response.sendStatus(400);
974973 }
@@ -1002,7 +1001,7 @@ router.post('/remote/kobold/count', jsonParser, async function (request, respons
10021001 }
10031002});
10041003
10051004router.post('/remote/textgenerationwebui/encode', jsonParser, async function (request, response) {
10061005 if (!request.body) {
10071006 return response.sendStatus(400);
10081007 }
src/endpoints/translate.js+8 -9
@@ -8,7 +8,6 @@ import urlJoin from 'url-join';
88
99import { readSecret, SECRET_KEYS } from './secrets.js';
1010import { getConfigValue, uuidv4 } from '../util.js';
11-import { jsonParser } from '../express-common.js';
1211
1312const DEEPLX_URL_DEFAULT = 'http://127.0.0.1:1188/translate';
1413const ONERING_URL_DEFAULT = 'http://127.0.0.1:4990/translate';
@@ -40,7 +39,7 @@ function decodeBuffer(buffer) {
4039 }
4140}
4241
4342router.post('/libre', jsonParser, async (request, response) => {
4443 try {
4544 const key = readSecret(request.user.directories, SECRET_KEYS.LIBRE);
4645 const url = readSecret(request.user.directories, SECRET_KEYS.LIBRE_URL);
@@ -100,7 +99,7 @@ router.post('/libre', jsonParser, async (request, response) => {
10099 }
101100});
102101
103102router.post('/google', jsonParser, async (request, response) => {
104103 try {
105104 const text = request.body.text;
106105 const lang = request.body.lang;
@@ -133,7 +132,7 @@ router.post('/google', jsonParser, async (request, response) => {
133132 }
134133});
135134
136135router.post('/yandex', jsonParser, async (request, response) => {
137136 try {
138137 if (request.body.lang === 'pt-PT') {
139138 request.body.lang = 'pt';
@@ -189,7 +188,7 @@ router.post('/yandex', jsonParser, async (request, response) => {
189188 }
190189});
191190
192191router.post('/lingva', jsonParser, async (request, response) => {
193192 try {
194193 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.LINGVA_URL);
195194 const baseUrl = secretUrl || LINGVA_DEFAULT;
@@ -233,7 +232,7 @@ router.post('/lingva', jsonParser, async (request, response) => {
233232 }
234233});
235234
236235router.post('/deepl', jsonParser, async (request, response) => {
237236 try {
238237 const key = readSecret(request.user.directories, SECRET_KEYS.DEEPL);
239238
@@ -295,7 +294,7 @@ router.post('/deepl', jsonParser, async (request, response) => {
295294 }
296295});
297296
298297router.post('/onering', jsonParser, async (request, response) => {
299298 try {
300299 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.ONERING_URL);
301300 const url = secretUrl || ONERING_URL_DEFAULT;
@@ -352,7 +351,7 @@ router.post('/onering', jsonParser, async (request, response) => {
352351 }
353352});
354353
355354router.post('/deeplx', jsonParser, async (request, response) => {
356355 try {
357356 const secretUrl = readSecret(request.user.directories, SECRET_KEYS.DEEPLX_URL);
358357 const url = secretUrl || DEEPLX_URL_DEFAULT;
@@ -408,7 +407,7 @@ router.post('/deeplx', jsonParser, async (request, response) => {
408407 }
409408});
410409
411410router.post('/bing', jsonParser, async (request, response) => {
412411 try {
413412 const text = request.body.text;
414413 let lang = request.body.lang;
src/endpoints/users-admin.js+8 -9
@@ -3,7 +3,6 @@ import { promises as fsPromises } from 'node:fs';
33import storage from 'node-persist';
44import express from 'express';
55import lodash from 'lodash';
6-import { jsonParser } from '../express-common.js';
76import { checkForNewContent, CONTENT_TYPES } from './content-manager.js';
87import {
98 KEY_PREFIX,
@@ -20,7 +19,7 @@ import { DEFAULT_USER } from '../constants.js';
2019
2120export const router = express.Router();
2221
2322router.post('/get', requireAdminMiddleware, jsonParser, async (_request, response) => {
2423 try {
2524 /** @type {import('../users.js').User[]} */
2625 const users = await storage.values(x => x.key.startsWith(KEY_PREFIX));
@@ -50,7 +49,7 @@ router.post('/get', requireAdminMiddleware, jsonParser, async (_request, respons
5049 }
5150});
5251
5352router.post('/disable', requireAdminMiddleware, jsonParser, async (request, response) => {
5453 try {
5554 if (!request.body.handle) {
5655 console.warn('Disable user failed: Missing required fields');
@@ -79,7 +78,7 @@ router.post('/disable', requireAdminMiddleware, jsonParser, async (request, resp
7978 }
8079});
8180
8281router.post('/enable', requireAdminMiddleware, jsonParser, async (request, response) => {
8382 try {
8483 if (!request.body.handle) {
8584 console.warn('Enable user failed: Missing required fields');
@@ -103,7 +102,7 @@ router.post('/enable', requireAdminMiddleware, jsonParser, async (request, respo
103102 }
104103});
105104
106105router.post('/promote', requireAdminMiddleware, jsonParser, async (request, response) => {
107106 try {
108107 if (!request.body.handle) {
109108 console.warn('Promote user failed: Missing required fields');
@@ -127,7 +126,7 @@ router.post('/promote', requireAdminMiddleware, jsonParser, async (request, resp
127126 }
128127});
129128
130129router.post('/demote', requireAdminMiddleware, jsonParser, async (request, response) => {
131130 try {
132131 if (!request.body.handle) {
133132 console.warn('Demote user failed: Missing required fields');
@@ -156,7 +155,7 @@ router.post('/demote', requireAdminMiddleware, jsonParser, async (request, respo
156155 }
157156});
158157
159158router.post('/create', requireAdminMiddleware, jsonParser, async (request, response) => {
160159 try {
161160 if (!request.body.handle || !request.body.name) {
162161 console.warn('Create user failed: Missing required fields');
@@ -203,7 +202,7 @@ router.post('/create', requireAdminMiddleware, jsonParser, async (request, respo
203202 }
204203});
205204
206205router.post('/delete', requireAdminMiddleware, jsonParser, async (request, response) => {
207206 try {
208207 if (!request.body.handle) {
209208 console.warn('Delete user failed: Missing required fields');
@@ -235,7 +234,7 @@ router.post('/delete', requireAdminMiddleware, jsonParser, async (request, respo
235234 }
236235});
237236
238237router.post('/slugify', requireAdminMiddleware, jsonParser, async (request, response) => {
239238 try {
240239 if (!request.body.text) {
241240 console.warn('Slugify failed: Missing required fields');
src/endpoints/users-private.js+7 -8
@@ -5,7 +5,6 @@ import crypto from 'node:crypto';
55import storage from 'node-persist';
66import express from 'express';
77
8-import { jsonParser } from '../express-common.js';
98import { getUserAvatar, toKey, getPasswordHash, getPasswordSalt, createBackupArchive, ensurePublicDirectoriesExist, toAvatarKey } from '../users.js';
109import { SETTINGS_FILE } from '../constants.js';
1110import { checkForNewContent, CONTENT_TYPES } from './content-manager.js';
@@ -55,7 +54,7 @@ router.get('/me', async (request, response) => {
5554 }
5655});
5756
5857router.post('/change-avatar', jsonParser, async (request, response) => {
5958 try {
6059 if (!request.body.handle) {
6160 console.warn('Change avatar failed: Missing required fields');
@@ -90,7 +89,7 @@ router.post('/change-avatar', jsonParser, async (request, response) => {
9089 }
9190});
9291
9392router.post('/change-password', jsonParser, async (request, response) => {
9493 try {
9594 if (!request.body.handle) {
9695 console.warn('Change password failed: Missing required fields');
@@ -137,7 +136,7 @@ router.post('/change-password', jsonParser, async (request, response) => {
137136 }
138137});
139138
140139router.post('/backup', jsonParser, async (request, response) => {
141140 try {
142141 const handle = request.body.handle;
143142
@@ -158,7 +157,7 @@ router.post('/backup', jsonParser, async (request, response) => {
158157 }
159158});
160159
161160router.post('/reset-settings', jsonParser, async (request, response) => {
162161 try {
163162 const password = request.body.password;
164163
@@ -178,7 +177,7 @@ router.post('/reset-settings', jsonParser, async (request, response) => {
178177 }
179178});
180179
181180router.post('/change-name', jsonParser, async (request, response) => {
182181 try {
183182 if (!request.body.name || !request.body.handle) {
184183 console.warn('Change name failed: Missing required fields');
@@ -208,7 +207,7 @@ router.post('/change-name', jsonParser, async (request, response) => {
208207 }
209208});
210209
211210router.post('/reset-step1', jsonParser, async (request, response) => {
212211 try {
213212 const resetCode = String(crypto.randomInt(1000, 9999));
214213 console.log();
@@ -222,7 +221,7 @@ router.post('/reset-step1', jsonParser, async (request, response) => {
222221 }
223222});
224223
225224router.post('/reset-step2', jsonParser, async (request, response) => {
226225 try {
227226 if (!request.body.code) {
228227 console.warn('Recover step 2 failed: Missing required fields');
src/endpoints/users-public.js+4 -4
@@ -3,7 +3,7 @@ import crypto from 'node:crypto';
33import storage from 'node-persist';
44import express from 'express';
55import { RateLimiterMemory, RateLimiterRes } from 'rate-limiter-flexible';
66import { jsonParser, getIpFromRequest, getRealIpFromHeader } from '../express-common.js';
77import { color, Cache, getConfigValue } from '../util.js';
88import { KEY_PREFIX, getUserAvatar, toKey, getPasswordHash, getPasswordSalt } from '../users.js';
99
@@ -56,7 +56,7 @@ router.post('/list', async (_request, response) => {
5656 }
5757});
5858
5959router.post('/login', jsonParser, async (request, response) => {
6060 try {
6161 if (!request.body.handle) {
6262 console.warn('Login failed: Missing required fields');
@@ -104,7 +104,7 @@ router.post('/login', jsonParser, async (request, response) => {
104104 }
105105});
106106
107107router.post('/recover-step1', jsonParser, async (request, response) => {
108108 try {
109109 if (!request.body.handle) {
110110 console.warn('Recover step 1 failed: Missing required fields');
@@ -144,7 +144,7 @@ router.post('/recover-step1', jsonParser, async (request, response) => {
144144 }
145145});
146146
147147router.post('/recover-step2', jsonParser, async (request, response) => {
148148 try {
149149 if (!request.body.handle || !request.body.code) {
150150 console.warn('Recover step 2 failed: Missing required fields');
src/endpoints/vectors.js+7 -8
@@ -5,7 +5,6 @@ import vectra from 'vectra';
55import express from 'express';
66import sanitize from 'sanitize-filename';
77
8-import { jsonParser } from '../express-common.js';
98import { getConfigValue } from '../util.js';
109
1110import { getNomicAIBatchVector, getNomicAIVector } from '../vectors/nomicai-vectors.js';
@@ -384,7 +383,7 @@ async function regenerateCorruptedIndexErrorHandler(req, res, error) {
384383
385384export const router = express.Router();
386385
387386router.post('/query', jsonParser, async (req, res) => {
388387 try {
389388 if (!req.body.collectionId || !req.body.searchText) {
390389 return res.sendStatus(400);
@@ -404,7 +403,7 @@ router.post('/query', jsonParser, async (req, res) => {
404403 }
405404});
406405
407406router.post('/query-multi', jsonParser, async (req, res) => {
408407 try {
409408 if (!Array.isArray(req.body.collectionIds) || !req.body.searchText) {
410409 return res.sendStatus(400);
@@ -424,7 +423,7 @@ router.post('/query-multi', jsonParser, async (req, res) => {
424423 }
425424});
426425
427426router.post('/insert', jsonParser, async (req, res) => {
428427 try {
429428 if (!Array.isArray(req.body.items) || !req.body.collectionId) {
430429 return res.sendStatus(400);
@@ -442,7 +441,7 @@ router.post('/insert', jsonParser, async (req, res) => {
442441 }
443442});
444443
445444router.post('/list', jsonParser, async (req, res) => {
446445 try {
447446 if (!req.body.collectionId) {
448447 return res.sendStatus(400);
@@ -459,7 +458,7 @@ router.post('/list', jsonParser, async (req, res) => {
459458 }
460459});
461460
462461router.post('/delete', jsonParser, async (req, res) => {
463462 try {
464463 if (!Array.isArray(req.body.hashes) || !req.body.collectionId) {
465464 return res.sendStatus(400);
@@ -477,7 +476,7 @@ router.post('/delete', jsonParser, async (req, res) => {
477476 }
478477});
479478
480479router.post('/purge-all', jsonParser, async (req, res) => {
481480 try {
482481 for (const source of SOURCES) {
483482 const sourcePath = path.join(req.user.directories.vectors, sanitize(source));
@@ -495,7 +494,7 @@ router.post('/purge-all', jsonParser, async (req, res) => {
495494 }
496495});
497496
498497router.post('/purge', jsonParser, async (req, res) => {
499498 try {
500499 if (!req.body.collectionId) {
501500 return res.sendStatus(400);
src/endpoints/worldinfo.js+4 -6
@@ -5,8 +5,6 @@ import express from 'express';
55import sanitize from 'sanitize-filename';
66import { sync as writeFileAtomicSync } from 'write-file-atomic';
77
8-import { jsonParser, urlencodedParser } from '../express-common.js';
9-
108/**
119 * Reads a World Info file and returns its contents
1210 * @param {import('../users.js').UserDirectoryList} directories User directories
@@ -36,7 +34,7 @@ export function readWorldInfoFile(directories, worldInfoName, allowDummy) {
3634
3735export const router = express.Router();
3836
3937router.post('/get', jsonParser, (request, response) => {
4038 if (!request.body?.name) {
4139 return response.sendStatus(400);
4240 }
@@ -46,7 +44,7 @@ router.post('/get', jsonParser, (request, response) => {
4644 return response.send(file);
4745});
4846
4947router.post('/delete', jsonParser, (request, response) => {
5048 if (!request.body?.name) {
5149 return response.sendStatus(400);
5250 }
@@ -64,7 +62,7 @@ router.post('/delete', jsonParser, (request, response) => {
6462 return response.sendStatus(200);
6563});
6664
6765router.post('/import', urlencodedParser, (request, response) => {
6866 if (!request.file) return response.sendStatus(400);
6967
7068 const filename = `${path.parse(sanitize(request.file.originalname)).name}.json`;
@@ -99,7 +97,7 @@ router.post('/import', urlencodedParser, (request, response) => {
9997 return response.send({ name: worldName });
10098});
10199
102100router.post('/edit', jsonParser, (request, response) => {
103101 if (!request.body) {
104102 return response.sendStatus(400);
105103 }
src/express-common.js+5 -4
@@ -1,9 +1,10 @@
1-import express from 'express';
21import ipaddr from 'ipaddr.js';
32
4-// Instantiate parser middleware here with application-level size limits
3+const noopMiddleware = (_req, _res, next) => next();
5-export const jsonParser = express.json({ limit: '200mb' });
4+/** @deprecated Do not use. A global middleware is provided at the application level. */
6-export const urlencodedParser = express.urlencoded({ extended: true, limit: '200mb' });
5+export const jsonParser = noopMiddleware;
6+/** @deprecated Do not use. A global middleware is provided at the application level. */
7+export const urlencodedParser = noopMiddleware;
78
89/**
910 * Gets the IP address of the client from the request object.