mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-30 19:19:03 +01:00 
			
		
		
		
	Merge pull request #48 from TriliumNext/feature/typescript_backend_11
Convert backend to TypeScript (89% -> 92%, final)
This commit is contained in:
		
						commit
						a68b75f069
					
				| @ -4,7 +4,7 @@ cloc HEAD \ | |||||||
|     --git --md \ |     --git --md \ | ||||||
|     --include-lang=javascript,typescript \ |     --include-lang=javascript,typescript \ | ||||||
|     --found=filelist.txt \ |     --found=filelist.txt \ | ||||||
|     --exclude-dir=public,libraries |     --exclude-dir=public,libraries,views,docs | ||||||
| 
 | 
 | ||||||
| grep -R \.js$ filelist.txt | grep -R \.js$ filelist.txt | ||||||
| rm filelist.txt | rm filelist.txt | ||||||
							
								
								
									
										70
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										70
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -91,6 +91,8 @@ | |||||||
|         "@types/archiver": "^6.0.2", |         "@types/archiver": "^6.0.2", | ||||||
|         "@types/better-sqlite3": "^7.6.9", |         "@types/better-sqlite3": "^7.6.9", | ||||||
|         "@types/cls-hooked": "^4.3.8", |         "@types/cls-hooked": "^4.3.8", | ||||||
|  |         "@types/compression": "^1.7.5", | ||||||
|  |         "@types/cookie-parser": "^1.4.7", | ||||||
|         "@types/csurf": "^1.11.5", |         "@types/csurf": "^1.11.5", | ||||||
|         "@types/ejs": "^3.1.5", |         "@types/ejs": "^3.1.5", | ||||||
|         "@types/escape-html": "^1.0.4", |         "@types/escape-html": "^1.0.4", | ||||||
| @ -105,6 +107,8 @@ | |||||||
|         "@types/safe-compare": "^1.1.2", |         "@types/safe-compare": "^1.1.2", | ||||||
|         "@types/sanitize-html": "^2.11.0", |         "@types/sanitize-html": "^2.11.0", | ||||||
|         "@types/sax": "^1.2.7", |         "@types/sax": "^1.2.7", | ||||||
|  |         "@types/semver": "^7.5.8", | ||||||
|  |         "@types/serve-favicon": "^2.5.7", | ||||||
|         "@types/stream-throttle": "^0.1.4", |         "@types/stream-throttle": "^0.1.4", | ||||||
|         "@types/tmp": "^0.2.6", |         "@types/tmp": "^0.2.6", | ||||||
|         "@types/turndown": "^5.0.4", |         "@types/turndown": "^5.0.4", | ||||||
| @ -1229,6 +1233,15 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/compression": { | ||||||
|  |       "version": "1.7.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", | ||||||
|  |       "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", | ||||||
|  |       "dev": true, | ||||||
|  |       "dependencies": { | ||||||
|  |         "@types/express": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@types/connect": { |     "node_modules/@types/connect": { | ||||||
|       "version": "3.4.38", |       "version": "3.4.38", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", |       "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", | ||||||
| @ -1238,6 +1251,15 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/cookie-parser": { | ||||||
|  |       "version": "1.4.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.7.tgz", | ||||||
|  |       "integrity": "sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==", | ||||||
|  |       "dev": true, | ||||||
|  |       "dependencies": { | ||||||
|  |         "@types/express": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@types/csurf": { |     "node_modules/@types/csurf": { | ||||||
|       "version": "1.11.5", |       "version": "1.11.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/csurf/-/csurf-1.11.5.tgz", |       "resolved": "https://registry.npmjs.org/@types/csurf/-/csurf-1.11.5.tgz", | ||||||
| @ -1643,6 +1665,12 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/semver": { | ||||||
|  |       "version": "7.5.8", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", | ||||||
|  |       "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", | ||||||
|  |       "dev": true | ||||||
|  |     }, | ||||||
|     "node_modules/@types/send": { |     "node_modules/@types/send": { | ||||||
|       "version": "0.17.4", |       "version": "0.17.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", |       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", | ||||||
| @ -1653,6 +1681,15 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/serve-favicon": { | ||||||
|  |       "version": "2.5.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/serve-favicon/-/serve-favicon-2.5.7.tgz", | ||||||
|  |       "integrity": "sha512-z9TNUQXdQ+W/OJMP1e3KOYUZ99qJS4+ZfFOIrPGImcayqKoyifbJSEFkVq1MCKBbqjMZpjPj3B5ilrQAR2+TOw==", | ||||||
|  |       "dev": true, | ||||||
|  |       "dependencies": { | ||||||
|  |         "@types/express": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@types/serve-static": { |     "node_modules/@types/serve-static": { | ||||||
|       "version": "1.15.5", |       "version": "1.15.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", |       "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", | ||||||
| @ -14246,6 +14283,15 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@types/compression": { | ||||||
|  |       "version": "1.7.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", | ||||||
|  |       "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", | ||||||
|  |       "dev": true, | ||||||
|  |       "requires": { | ||||||
|  |         "@types/express": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "@types/connect": { |     "@types/connect": { | ||||||
|       "version": "3.4.38", |       "version": "3.4.38", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", |       "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", | ||||||
| @ -14255,6 +14301,15 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@types/cookie-parser": { | ||||||
|  |       "version": "1.4.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.7.tgz", | ||||||
|  |       "integrity": "sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==", | ||||||
|  |       "dev": true, | ||||||
|  |       "requires": { | ||||||
|  |         "@types/express": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "@types/csurf": { |     "@types/csurf": { | ||||||
|       "version": "1.11.5", |       "version": "1.11.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/csurf/-/csurf-1.11.5.tgz", |       "resolved": "https://registry.npmjs.org/@types/csurf/-/csurf-1.11.5.tgz", | ||||||
| @ -14630,6 +14685,12 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@types/semver": { | ||||||
|  |       "version": "7.5.8", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", | ||||||
|  |       "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", | ||||||
|  |       "dev": true | ||||||
|  |     }, | ||||||
|     "@types/send": { |     "@types/send": { | ||||||
|       "version": "0.17.4", |       "version": "0.17.4", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", |       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", | ||||||
| @ -14640,6 +14701,15 @@ | |||||||
|         "@types/node": "*" |         "@types/node": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "@types/serve-favicon": { | ||||||
|  |       "version": "2.5.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/serve-favicon/-/serve-favicon-2.5.7.tgz", | ||||||
|  |       "integrity": "sha512-z9TNUQXdQ+W/OJMP1e3KOYUZ99qJS4+ZfFOIrPGImcayqKoyifbJSEFkVq1MCKBbqjMZpjPj3B5ilrQAR2+TOw==", | ||||||
|  |       "dev": true, | ||||||
|  |       "requires": { | ||||||
|  |         "@types/express": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "@types/serve-static": { |     "@types/serve-static": { | ||||||
|       "version": "1.15.5", |       "version": "1.15.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", |       "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| @ -13,9 +13,9 @@ | |||||||
|     "url": "https://github.com/zadam/trilium.git" |     "url": "https://github.com/zadam/trilium.git" | ||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "start-server": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/www.js", |     "start-server": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/www.ts", | ||||||
|     "start-server-no-dir": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/www.js", |     "start-server-no-dir": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/www.ts", | ||||||
|     "qstart-server": "npm run qswitch-server && TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/www.js", |     "qstart-server": "npm run qswitch-server && TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon src/www.ts", | ||||||
|     "start-electron": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .", |     "start-electron": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .", | ||||||
|     "start-electron-no-dir": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 electron --inspect=5858 .", |     "start-electron-no-dir": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 electron --inspect=5858 .", | ||||||
|     "qstart-electron": "npm run qswitch-electron && TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .", |     "qstart-electron": "npm run qswitch-electron && TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .", | ||||||
| @ -112,6 +112,8 @@ | |||||||
|     "@types/archiver": "^6.0.2", |     "@types/archiver": "^6.0.2", | ||||||
|     "@types/better-sqlite3": "^7.6.9", |     "@types/better-sqlite3": "^7.6.9", | ||||||
|     "@types/cls-hooked": "^4.3.8", |     "@types/cls-hooked": "^4.3.8", | ||||||
|  |     "@types/compression": "^1.7.5", | ||||||
|  |     "@types/cookie-parser": "^1.4.7", | ||||||
|     "@types/csurf": "^1.11.5", |     "@types/csurf": "^1.11.5", | ||||||
|     "@types/ejs": "^3.1.5", |     "@types/ejs": "^3.1.5", | ||||||
|     "@types/escape-html": "^1.0.4", |     "@types/escape-html": "^1.0.4", | ||||||
| @ -126,6 +128,8 @@ | |||||||
|     "@types/safe-compare": "^1.1.2", |     "@types/safe-compare": "^1.1.2", | ||||||
|     "@types/sanitize-html": "^2.11.0", |     "@types/sanitize-html": "^2.11.0", | ||||||
|     "@types/sax": "^1.2.7", |     "@types/sax": "^1.2.7", | ||||||
|  |     "@types/semver": "^7.5.8", | ||||||
|  |     "@types/serve-favicon": "^2.5.7", | ||||||
|     "@types/stream-throttle": "^0.1.4", |     "@types/stream-throttle": "^0.1.4", | ||||||
|     "@types/tmp": "^0.2.6", |     "@types/tmp": "^0.2.6", | ||||||
|     "@types/turndown": "^5.0.4", |     "@types/turndown": "^5.0.4", | ||||||
| @ -151,4 +155,4 @@ | |||||||
|   "optionalDependencies": { |   "optionalDependencies": { | ||||||
|     "electron-installer-debian": "3.2.0" |     "electron-installer-debian": "3.2.0" | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -1,11 +1,11 @@ | |||||||
| const express = require('express'); | import express = require('express'); | ||||||
| const path = require('path'); | import path = require('path'); | ||||||
| const favicon = require('serve-favicon'); | import favicon = require('serve-favicon'); | ||||||
| const cookieParser = require('cookie-parser'); | import cookieParser = require('cookie-parser'); | ||||||
| const helmet = require('helmet'); | import helmet = require('helmet'); | ||||||
| const compression = require('compression'); | import compression = require('compression'); | ||||||
| const sessionParser = require('./routes/session_parser'); | import sessionParser = require('./routes/session_parser'); | ||||||
| const utils = require('./services/utils'); | import utils = require('./services/utils'); | ||||||
| 
 | 
 | ||||||
| require('./services/handlers'); | require('./services/handlers'); | ||||||
| require('./becca/becca_loader'); | require('./becca/becca_loader'); | ||||||
| @ -20,7 +20,7 @@ if (!utils.isElectron()) { | |||||||
|     app.use(compression()); // HTTP compression
 |     app.use(compression()); // HTTP compression
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| app.use(helmet({ | app.use(helmet.default({ | ||||||
|     hidePoweredBy: false, // errors out in electron
 |     hidePoweredBy: false, // errors out in electron
 | ||||||
|     contentSecurityPolicy: false, |     contentSecurityPolicy: false, | ||||||
|     crossOriginEmbedderPolicy: false |     crossOriginEmbedderPolicy: false | ||||||
| @ -38,7 +38,7 @@ app.use(sessionParser); | |||||||
| app.use(favicon(`${__dirname}/../images/app-icons/win/icon.ico`)); | app.use(favicon(`${__dirname}/../images/app-icons/win/icon.ico`)); | ||||||
| 
 | 
 | ||||||
| require('./routes/assets').register(app); | require('./routes/assets').register(app); | ||||||
| require('./routes/routes.js').register(app); | require('./routes/routes').register(app); | ||||||
| require('./routes/custom').register(app); | require('./routes/custom').register(app); | ||||||
| require('./routes/error_handlers').register(app); | require('./routes/error_handlers').register(app); | ||||||
| 
 | 
 | ||||||
| @ -57,4 +57,4 @@ if (utils.isElectron()) { | |||||||
|     require('@electron/remote/main').initialize(); |     require('@electron/remote/main').initialize(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = app; | export = app; | ||||||
| @ -103,6 +103,6 @@ function register(router: Router) { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | export = { | ||||||
|     register |     register | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -229,7 +229,7 @@ function findNotesByUrl(req: Request){ | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | export = { | ||||||
|     createNote, |     createNote, | ||||||
|     addClipping, |     addClipping, | ||||||
|     openNote, |     openNote, | ||||||
|  | |||||||
| @ -55,6 +55,6 @@ function exportBranch(req: Request, res: Response) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | export = { | ||||||
|     exportBranch |     exportBranch | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -124,7 +124,7 @@ function attachmentContentProvider(req: Request) { | |||||||
|     return streamContent(attachment.getContent(), attachment.getFileName(), attachment.mime); |     return streamContent(attachment.getContent(), attachment.getFileName(), attachment.mime); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function streamContent(content: string | Buffer, fileName: string, mimeType: string) { | async function streamContent(content: string | Buffer, fileName: string, mimeType: string) { | ||||||
|     if (typeof content === "string") { |     if (typeof content === "string") { | ||||||
|         content = Buffer.from(content, 'utf8'); |         content = Buffer.from(content, 'utf8'); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,87 +1,94 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| const utils = require('../services/utils'); | import utils = require('../services/utils'); | ||||||
| const multer = require('multer'); | import multer = require('multer'); | ||||||
| const log = require('../services/log'); | import log = require('../services/log'); | ||||||
| const express = require('express'); | import express = require('express'); | ||||||
| const router = express.Router(); | const router = express.Router(); | ||||||
| const auth = require('../services/auth'); | import auth = require('../services/auth'); | ||||||
| const cls = require('../services/cls'); | import cls = require('../services/cls'); | ||||||
| const sql = require('../services/sql'); | import sql = require('../services/sql'); | ||||||
| const entityChangesService = require('../services/entity_changes'); | import entityChangesService = require('../services/entity_changes'); | ||||||
| const csurf = require('csurf'); | import csurf = require('csurf'); | ||||||
| const { createPartialContentHandler } = require("express-partial-content"); | import { createPartialContentHandler } from "express-partial-content"; | ||||||
| const rateLimit = require("express-rate-limit"); | import rateLimit = require("express-rate-limit"); | ||||||
| const AbstractBeccaEntity = require('../becca/entities/abstract_becca_entity'); | import AbstractBeccaEntity = require('../becca/entities/abstract_becca_entity'); | ||||||
| const NotFoundError = require('../errors/not_found_error'); | import NotFoundError = require('../errors/not_found_error'); | ||||||
| const ValidationError = require('../errors/validation_error'); | import ValidationError = require('../errors/validation_error'); | ||||||
| 
 | 
 | ||||||
| // page routes
 | // page routes
 | ||||||
| const setupRoute = require('./setup'); | import setupRoute = require('./setup'); | ||||||
| const loginRoute = require('./login'); | import loginRoute = require('./login'); | ||||||
| const indexRoute = require('./index'); | import indexRoute = require('./index'); | ||||||
| 
 | 
 | ||||||
| // API routes
 | // API routes
 | ||||||
| const treeApiRoute = require('./api/tree'); | import treeApiRoute = require('./api/tree'); | ||||||
| const notesApiRoute = require('./api/notes'); | import notesApiRoute = require('./api/notes'); | ||||||
| const branchesApiRoute = require('./api/branches'); | import branchesApiRoute = require('./api/branches'); | ||||||
| const attachmentsApiRoute = require('./api/attachments'); | import attachmentsApiRoute = require('./api/attachments'); | ||||||
| const autocompleteApiRoute = require('./api/autocomplete'); | import autocompleteApiRoute = require('./api/autocomplete'); | ||||||
| const cloningApiRoute = require('./api/cloning'); | import cloningApiRoute = require('./api/cloning'); | ||||||
| const revisionsApiRoute = require('./api/revisions'); | import revisionsApiRoute = require('./api/revisions'); | ||||||
| const recentChangesApiRoute = require('./api/recent_changes'); | import recentChangesApiRoute = require('./api/recent_changes'); | ||||||
| const optionsApiRoute = require('./api/options'); | import optionsApiRoute = require('./api/options'); | ||||||
| const passwordApiRoute = require('./api/password'); | import passwordApiRoute = require('./api/password'); | ||||||
| const syncApiRoute = require('./api/sync'); | import syncApiRoute = require('./api/sync'); | ||||||
| const loginApiRoute = require('./api/login'); | import loginApiRoute = require('./api/login'); | ||||||
| const recentNotesRoute = require('./api/recent_notes'); | import recentNotesRoute = require('./api/recent_notes'); | ||||||
| const appInfoRoute = require('./api/app_info'); | import appInfoRoute = require('./api/app_info'); | ||||||
| const exportRoute = require('./api/export'); | import exportRoute = require('./api/export'); | ||||||
| const importRoute = require('./api/import'); | import importRoute = require('./api/import'); | ||||||
| const setupApiRoute = require('./api/setup'); | import setupApiRoute = require('./api/setup'); | ||||||
| const sqlRoute = require('./api/sql'); | import sqlRoute = require('./api/sql'); | ||||||
| const databaseRoute = require('./api/database'); | import databaseRoute = require('./api/database'); | ||||||
| const imageRoute = require('./api/image'); | import imageRoute = require('./api/image'); | ||||||
| const attributesRoute = require('./api/attributes'); | import attributesRoute = require('./api/attributes'); | ||||||
| const scriptRoute = require('./api/script'); | import scriptRoute = require('./api/script'); | ||||||
| const senderRoute = require('./api/sender'); | import senderRoute = require('./api/sender'); | ||||||
| const filesRoute = require('./api/files'); | import filesRoute = require('./api/files'); | ||||||
| const searchRoute = require('./api/search'); | import searchRoute = require('./api/search'); | ||||||
| const bulkActionRoute = require('./api/bulk_action'); | import bulkActionRoute = require('./api/bulk_action'); | ||||||
| const specialNotesRoute = require('./api/special_notes'); | import specialNotesRoute = require('./api/special_notes'); | ||||||
| const noteMapRoute = require('./api/note_map'); | import noteMapRoute = require('./api/note_map'); | ||||||
| const clipperRoute = require('./api/clipper'); | import clipperRoute = require('./api/clipper'); | ||||||
| const similarNotesRoute = require('./api/similar_notes'); | import similarNotesRoute = require('./api/similar_notes'); | ||||||
| const keysRoute = require('./api/keys'); | import keysRoute = require('./api/keys'); | ||||||
| const backendLogRoute = require('./api/backend_log'); | import backendLogRoute = require('./api/backend_log'); | ||||||
| const statsRoute = require('./api/stats'); | import statsRoute = require('./api/stats'); | ||||||
| const fontsRoute = require('./api/fonts'); | import fontsRoute = require('./api/fonts'); | ||||||
| const etapiTokensApiRoutes = require('./api/etapi_tokens'); | import etapiTokensApiRoutes = require('./api/etapi_tokens'); | ||||||
| const relationMapApiRoute = require('./api/relation-map'); | import relationMapApiRoute = require('./api/relation-map'); | ||||||
| const otherRoute = require('./api/other'); | import otherRoute = require('./api/other'); | ||||||
| const shareRoutes = require('../share/routes'); | import shareRoutes = require('../share/routes'); | ||||||
| 
 | 
 | ||||||
| const etapiAuthRoutes = require('../etapi/auth'); | import etapiAuthRoutes = require('../etapi/auth'); | ||||||
| const etapiAppInfoRoutes = require('../etapi/app_info'); | import etapiAppInfoRoutes = require('../etapi/app_info'); | ||||||
| const etapiAttachmentRoutes = require('../etapi/attachments'); | import etapiAttachmentRoutes = require('../etapi/attachments'); | ||||||
| const etapiAttributeRoutes = require('../etapi/attributes'); | import etapiAttributeRoutes = require('../etapi/attributes'); | ||||||
| const etapiBranchRoutes = require('../etapi/branches'); | import etapiBranchRoutes = require('../etapi/branches'); | ||||||
| const etapiNoteRoutes = require('../etapi/notes'); | import etapiNoteRoutes = require('../etapi/notes'); | ||||||
| const etapiSpecialNoteRoutes = require('../etapi/special_notes'); | import etapiSpecialNoteRoutes = require('../etapi/special_notes'); | ||||||
| const etapiSpecRoute = require('../etapi/spec'); | import etapiSpecRoute = require('../etapi/spec'); | ||||||
| const etapiBackupRoute = require('../etapi/backup'); | import etapiBackupRoute = require('../etapi/backup'); | ||||||
|  | import { AppRequest, AppRequestHandler } from './route-interface'; | ||||||
| 
 | 
 | ||||||
| const csrfMiddleware = csurf({ | const csrfMiddleware = csurf({ | ||||||
|     cookie: true, |     cookie: { | ||||||
|     path: '' // empty, so cookie is valid only for the current path
 |         path: ""       // empty, so cookie is valid only for the current path
 | ||||||
|  |     } | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const MAX_ALLOWED_FILE_SIZE_MB = 250; | const MAX_ALLOWED_FILE_SIZE_MB = 250; | ||||||
| const GET = 'get', PST = 'post', PUT = 'put', PATCH = 'patch', DEL = 'delete'; | const GET = 'get', PST = 'post', PUT = 'put', PATCH = 'patch', DEL = 'delete'; | ||||||
| 
 | 
 | ||||||
|  | type ApiResultHandler = (req: express.Request, res: express.Response, result: unknown) => number; | ||||||
|  | 
 | ||||||
|  | // TODO: Deduplicate with etapi_utils.ts afterwards.
 | ||||||
|  | type HttpMethod = "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head"; | ||||||
|  | 
 | ||||||
| const uploadMiddleware = createUploadMiddleware(); | const uploadMiddleware = createUploadMiddleware(); | ||||||
| 
 | 
 | ||||||
| const uploadMiddlewareWithErrorHandling = function (req, res, next) { | const uploadMiddlewareWithErrorHandling = function (req: express.Request, res: express.Response, next: express.NextFunction) { | ||||||
|     uploadMiddleware(req, res, function (err) { |     uploadMiddleware(req, res, function (err) { | ||||||
|         if (err?.code === 'LIMIT_FILE_SIZE') { |         if (err?.code === 'LIMIT_FILE_SIZE') { | ||||||
|             res.setHeader("Content-Type", "text/plain") |             res.setHeader("Content-Type", "text/plain") | ||||||
| @ -94,12 +101,12 @@ const uploadMiddlewareWithErrorHandling = function (req, res, next) { | |||||||
|     }); |     }); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function register(app) { | function register(app: express.Application) { | ||||||
|     route(GET, '/', [auth.checkAuth, csrfMiddleware], indexRoute.index); |     route(GET, '/', [auth.checkAuth, csrfMiddleware], indexRoute.index); | ||||||
|     route(GET, '/login', [auth.checkAppInitialized, auth.checkPasswordSet], loginRoute.loginPage); |     route(GET, '/login', [auth.checkAppInitialized, auth.checkPasswordSet], loginRoute.loginPage); | ||||||
|     route(GET, '/set-password', [auth.checkAppInitialized, auth.checkPasswordNotSet], loginRoute.setPasswordPage); |     route(GET, '/set-password', [auth.checkAppInitialized, auth.checkPasswordNotSet], loginRoute.setPasswordPage); | ||||||
| 
 | 
 | ||||||
|     const loginRateLimiter = rateLimit({ |     const loginRateLimiter = rateLimit.rateLimit({ | ||||||
|         windowMs: 15 * 60 * 1000, // 15 minutes
 |         windowMs: 15 * 60 * 1000, // 15 minutes
 | ||||||
|         max: 10, // limit each IP to 10 requests per windowMs
 |         max: 10, // limit each IP to 10 requests per windowMs
 | ||||||
|         skipSuccessfulRequests: true // successful auth to rate-limited ETAPI routes isn't counted. However, successful auth to /login is still counted!
 |         skipSuccessfulRequests: true // successful auth to rate-limited ETAPI routes isn't counted. However, successful auth to /login is still counted!
 | ||||||
| @ -353,7 +360,7 @@ function register(app) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Handling common patterns. If entity is not caught, serialization to JSON will fail */ | /** Handling common patterns. If entity is not caught, serialization to JSON will fail */ | ||||||
| function convertEntitiesToPojo(result) { | function convertEntitiesToPojo(result: unknown) { | ||||||
|     if (result instanceof AbstractBeccaEntity) { |     if (result instanceof AbstractBeccaEntity) { | ||||||
|         result = result.getPojo(); |         result = result.getPojo(); | ||||||
|     } |     } | ||||||
| @ -364,24 +371,24 @@ function convertEntitiesToPojo(result) { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     else { |     else if (result && typeof result === "object") { | ||||||
|         if (result && result.note instanceof AbstractBeccaEntity) { |         if ("note" in result && result.note instanceof AbstractBeccaEntity) { | ||||||
|             result.note = result.note.getPojo(); |             result.note = result.note.getPojo(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (result && result.branch instanceof AbstractBeccaEntity) { |         if ("branch" in result && result.branch instanceof AbstractBeccaEntity) { | ||||||
|             result.branch = result.branch.getPojo(); |             result.branch = result.branch.getPojo(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (result && result.executionResult) { // from runOnBackend()
 |     if (result && typeof result === "object" && "executionResult" in result) { // from runOnBackend()
 | ||||||
|         result.executionResult = convertEntitiesToPojo(result.executionResult); |         result.executionResult = convertEntitiesToPojo(result.executionResult); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function apiResultHandler(req, res, result) { | function apiResultHandler(req: express.Request, res: express.Response, result: unknown) { | ||||||
|     res.setHeader('trilium-max-entity-change-id', entityChangesService.getMaxEntityChangeId()); |     res.setHeader('trilium-max-entity-change-id', entityChangesService.getMaxEntityChangeId()); | ||||||
| 
 | 
 | ||||||
|     result = convertEntitiesToPojo(result); |     result = convertEntitiesToPojo(result); | ||||||
| @ -404,7 +411,7 @@ function apiResultHandler(req, res, result) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function send(res, statusCode, response) { | function send(res: express.Response, statusCode: number, response: unknown) { | ||||||
|     if (typeof response === 'string') { |     if (typeof response === 'string') { | ||||||
|         if (statusCode >= 400) { |         if (statusCode >= 400) { | ||||||
|             res.setHeader("Content-Type", "text/plain"); |             res.setHeader("Content-Type", "text/plain"); | ||||||
| @ -424,12 +431,12 @@ function send(res, statusCode, response) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function apiRoute(method, path, routeHandler) { | function apiRoute(method: HttpMethod, path: string, routeHandler: express.Handler) { | ||||||
|     route(method, path, [auth.checkApiAuth, csrfMiddleware], routeHandler, apiResultHandler); |     route(method, path, [auth.checkApiAuth, csrfMiddleware], routeHandler, apiResultHandler); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function route(method, path, middleware, routeHandler, resultHandler = null, transactional = true) { | function route(method: HttpMethod, path: string, middleware: (express.Handler | AppRequestHandler)[], routeHandler: AppRequestHandler, resultHandler: ApiResultHandler | null = null, transactional = true) { | ||||||
|     router[method](path, ...middleware, (req, res, next) => { |     router[method](path, ...(middleware as express.Handler[]), (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||||||
|         const start = Date.now(); |         const start = Date.now(); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| @ -441,7 +448,7 @@ function route(method, path, middleware, routeHandler, resultHandler = null, tra | |||||||
|                 cls.set('localNowDateTime', req.headers['trilium-local-now-datetime']); |                 cls.set('localNowDateTime', req.headers['trilium-local-now-datetime']); | ||||||
|                 cls.set('hoistedNoteId', req.headers['trilium-hoisted-note-id'] || 'root'); |                 cls.set('hoistedNoteId', req.headers['trilium-hoisted-note-id'] || 'root'); | ||||||
| 
 | 
 | ||||||
|                 const cb = () => routeHandler(req, res, next); |                 const cb = () => routeHandler(req as AppRequest, res, next); | ||||||
| 
 | 
 | ||||||
|                 return transactional ? sql.transactional(cb) : cb(); |                 return transactional ? sql.transactional(cb) : cb(); | ||||||
|             }); |             }); | ||||||
| @ -452,8 +459,8 @@ function route(method, path, middleware, routeHandler, resultHandler = null, tra | |||||||
| 
 | 
 | ||||||
|             if (result?.then) { // promise
 |             if (result?.then) { // promise
 | ||||||
|                 result |                 result | ||||||
|                     .then(promiseResult => handleResponse(resultHandler, req, res, promiseResult, start)) |                     .then((promiseResult: unknown) => handleResponse(resultHandler, req, res, promiseResult, start)) | ||||||
|                     .catch(e => handleException(e, method, path, res)); |                     .catch((e: any) => handleException(e, method, path, res)); | ||||||
|             } else { |             } else { | ||||||
|                 handleResponse(resultHandler, req, res, result, start) |                 handleResponse(resultHandler, req, res, result, start) | ||||||
|             } |             } | ||||||
| @ -464,13 +471,13 @@ function route(method, path, middleware, routeHandler, resultHandler = null, tra | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function handleResponse(resultHandler, req, res, result, start) { | function handleResponse(resultHandler: ApiResultHandler, req: express.Request, res: express.Response, result: unknown, start: number) { | ||||||
|     const responseLength = resultHandler(req, res, result); |     const responseLength = resultHandler(req, res, result); | ||||||
| 
 | 
 | ||||||
|     log.request(req, res, Date.now() - start, responseLength); |     log.request(req, res, Date.now() - start, responseLength); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function handleException(e, method, path, res) { | function handleException(e: any, method: HttpMethod, path: string, res: express.Response) { | ||||||
|     log.error(`${method} ${path} threw exception: '${e.message}', stack: ${e.stack}`); |     log.error(`${method} ${path} threw exception: '${e.message}', stack: ${e.stack}`); | ||||||
| 
 | 
 | ||||||
|     if (e instanceof ValidationError) { |     if (e instanceof ValidationError) { | ||||||
| @ -492,8 +499,8 @@ function handleException(e, method, path, res) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function createUploadMiddleware() { | function createUploadMiddleware() { | ||||||
|     const multerOptions = { |     const multerOptions: multer.Options = { | ||||||
|         fileFilter: (req, file, cb) => { |         fileFilter: (req: express.Request, file, cb) => { | ||||||
|             // UTF-8 file names are not well decoded by multer/busboy, so we handle the conversion on our side.
 |             // UTF-8 file names are not well decoded by multer/busboy, so we handle the conversion on our side.
 | ||||||
|             // See https://github.com/expressjs/multer/pull/1102.
 |             // See https://github.com/expressjs/multer/pull/1102.
 | ||||||
|             file.originalname = Buffer.from(file.originalname, "latin1").toString("utf-8"); |             file.originalname = Buffer.from(file.originalname, "latin1").toString("utf-8"); | ||||||
| @ -510,6 +517,6 @@ function createUploadMiddleware() { | |||||||
|     return multer(multerOptions).single('upload'); |     return multer(multerOptions).single('upload'); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = { | export = { | ||||||
|     register |     register | ||||||
| }; | }; | ||||||
| @ -76,7 +76,7 @@ function error(message: string) { | |||||||
| 
 | 
 | ||||||
| const requestBlacklist = [ "/libraries", "/app", "/images", "/stylesheets", "/api/recent-notes" ]; | const requestBlacklist = [ "/libraries", "/app", "/images", "/stylesheets", "/api/recent-notes" ]; | ||||||
| 
 | 
 | ||||||
| function request(req: Request, res: Response, timeMs: number, responseLength = "?") { | function request(req: Request, res: Response, timeMs: number, responseLength: number | string = "?") { | ||||||
|     for (const bl of requestBlacklist) { |     for (const bl of requestBlacklist) { | ||||||
|         if (req.url.startsWith(bl)) { |         if (req.url.startsWith(bl)) { | ||||||
|             return; |             return; | ||||||
|  | |||||||
| @ -81,7 +81,7 @@ async function createMainWindow(app: App) { | |||||||
| 
 | 
 | ||||||
|     app.on('second-instance', () => { |     app.on('second-instance', () => { | ||||||
|         // Someone tried to run a second instance, we should focus our window.
 |         // Someone tried to run a second instance, we should focus our window.
 | ||||||
|         // see www.js "requestSingleInstanceLock" for the rest of this logic with explanation
 |         // see www.ts "requestSingleInstanceLock" for the rest of this logic with explanation
 | ||||||
|         if (mainWindow) { |         if (mainWindow) { | ||||||
|             if (mainWindow.isMinimized()) { |             if (mainWindow.isMinimized()) { | ||||||
|                 mainWindow.restore(); |                 mainWindow.restore(); | ||||||
|  | |||||||
| @ -18,19 +18,19 @@ function exit() { | |||||||
| process.on('SIGINT', exit); | process.on('SIGINT', exit); | ||||||
| process.on('SIGTERM', exit); | process.on('SIGTERM', exit); | ||||||
| 
 | 
 | ||||||
| const app = require('./app'); | import app = require('./app'); | ||||||
| const sessionParser = require('./routes/session_parser'); | import sessionParser = require('./routes/session_parser'); | ||||||
| const fs = require('fs'); | import fs = require('fs'); | ||||||
| const http = require('http'); | import http = require('http'); | ||||||
| const https = require('https'); | import https = require('https'); | ||||||
| const config = require('./services/config'); | import config = require('./services/config'); | ||||||
| const log = require('./services/log'); | import log = require('./services/log'); | ||||||
| const appInfo = require('./services/app_info'); | import appInfo = require('./services/app_info'); | ||||||
| const ws = require('./services/ws'); | import ws = require('./services/ws'); | ||||||
| const utils = require('./services/utils'); | import utils = require('./services/utils'); | ||||||
| const port = require('./services/port'); | import port = require('./services/port'); | ||||||
| const host = require('./services/host'); | import host = require('./services/host'); | ||||||
| const semver = require('semver'); | import semver = require('semver'); | ||||||
| 
 | 
 | ||||||
| if (!semver.satisfies(process.version, ">=10.5.0")) { | if (!semver.satisfies(process.version, ">=10.5.0")) { | ||||||
|     console.error("Trilium only supports node.js 10.5 and later"); |     console.error("Trilium only supports node.js 10.5 and later"); | ||||||
| @ -66,7 +66,7 @@ function startTrilium() { | |||||||
| 
 | 
 | ||||||
|     const httpServer = startHttpServer(); |     const httpServer = startHttpServer(); | ||||||
| 
 | 
 | ||||||
|     ws.init(httpServer, sessionParser); |     ws.init(httpServer, sessionParser as any); // TODO: Not sure why session parser is incompatible.
 | ||||||
| 
 | 
 | ||||||
|     if (utils.isElectron()) { |     if (utils.isElectron()) { | ||||||
|         const electronRouting = require('./routes/electron'); |         const electronRouting = require('./routes/electron'); | ||||||
| @ -126,25 +126,23 @@ function startHttpServer() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     httpServer.on('error', error => { |     httpServer.on('error', error => { | ||||||
|         if (!listenOnTcp || error.syscall !== 'listen') { |         if (!listenOnTcp || ("syscall" in error && error.syscall !== 'listen')) { | ||||||
|             throw error; |             throw error; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // handle specific listen errors with friendly messages
 |         // handle specific listen errors with friendly messages
 | ||||||
|         switch (error.code) { |         if ("code" in error) { | ||||||
|             case 'EACCES': |             switch (error.code) { | ||||||
|                 console.error(`Port ${port} requires elevated privileges. It's recommended to use port above 1024.`); |                 case 'EACCES': | ||||||
|                 process.exit(1); |                     console.error(`Port ${port} requires elevated privileges. It's recommended to use port above 1024.`); | ||||||
|                 break; |                     process.exit(1); | ||||||
| 
 |                 case 'EADDRINUSE': | ||||||
|             case 'EADDRINUSE': |                     console.error(`Port ${port} is already in use. Most likely, another Trilium process is already running. You might try to find it, kill it, and try again.`); | ||||||
|                 console.error(`Port ${port} is already in use. Most likely, another Trilium process is already running. You might try to find it, kill it, and try again.`); |                     process.exit(1); | ||||||
|                 process.exit(1); |             } | ||||||
|                 break; |  | ||||||
| 
 |  | ||||||
|             default: |  | ||||||
|                 throw error; |  | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         throw error; | ||||||
|     } |     } | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran