mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 03:29:02 +01:00 
			
		
		
		
	Merge pull request #18 from TriliumNext/feature/typescript_backend_2
Convert backend to TypeScript (19% -> 35%)
This commit is contained in:
		
						commit
						a7ae16bb39
					
				| @ -1,6 +1,6 @@ | ||||
| #!/usr/bin/env node
 | ||||
| 
 | ||||
| const anonymizationService = require('../src/services/anonymization.js'); | ||||
| const anonymizationService = require('../src/services/anonymization'); | ||||
| const fs = require('fs'); | ||||
| const path = require('path'); | ||||
| 
 | ||||
|  | ||||
| @ -26,9 +26,9 @@ jq '.version = "'$VERSION'"' package.json|sponge package.json | ||||
| 
 | ||||
| git add package.json | ||||
| 
 | ||||
| echo 'module.exports = { buildDate:"'`date --iso-8601=seconds`'", buildRevision: "'`git log -1 --format="%H"`'" };' > src/services/build.js | ||||
| echo 'export = { buildDate:"'`date --iso-8601=seconds`'", buildRevision: "'`git log -1 --format="%H"`'" };' > src/services/build.ts | ||||
| 
 | ||||
| git add src/services/build.js | ||||
| git add src/services/build.ts | ||||
| 
 | ||||
| TAG=v$VERSION | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| module.exports = () => { | ||||
|     const beccaLoader = require('../../src/becca/becca_loader.js'); | ||||
|     const beccaLoader = require('../../src/becca/becca_loader'); | ||||
|     const becca = require('../../src/becca/becca'); | ||||
|     const cls = require('../../src/services/cls'); | ||||
|     const log = require('../../src/services/log'); | ||||
|  | ||||
| @ -10,7 +10,7 @@ if (config.Network.https) { | ||||
|     process.exit(0); | ||||
| } | ||||
| 
 | ||||
| const port = require('./src/services/port.js'); | ||||
| const port = require('./src/services/port.ts'); | ||||
| const host = require('./src/services/host.js'); | ||||
| 
 | ||||
| const options = { timeout: 2000 }; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| const {app, globalShortcut, BrowserWindow} = require('electron'); | ||||
| const sqlInit = require('./src/services/sql_init.js'); | ||||
| const sqlInit = require('./src/services/sql_init'); | ||||
| const appIconService = require('./src/services/app_icon.js'); | ||||
| const windowService = require('./src/services/window.js'); | ||||
| const tray = require('./src/services/tray.js'); | ||||
|  | ||||
							
								
								
									
										220
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										220
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -93,8 +93,10 @@ | ||||
|         "@types/escape-html": "^1.0.4", | ||||
|         "@types/express": "^4.17.21", | ||||
|         "@types/ini": "^4.1.0", | ||||
|         "@types/jsdom": "^21.1.6", | ||||
|         "@types/mime-types": "^2.1.4", | ||||
|         "@types/node": "^20.11.19", | ||||
|         "@types/sanitize-html": "^2.11.0", | ||||
|         "@types/ws": "^8.5.10", | ||||
|         "cross-env": "7.0.3", | ||||
|         "electron": "25.9.8", | ||||
| @ -1333,6 +1335,41 @@ | ||||
|       "integrity": "sha512-mTehMtc+xtnWBBvqizcqYCktKDBH2WChvx1GU3Sfe4PysFDXiNe+1YwtpVX1MDtCa4NQrSPw2+3HmvXHY3gt1w==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/@types/jsdom": { | ||||
|       "version": "21.1.6", | ||||
|       "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz", | ||||
|       "integrity": "sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@types/node": "*", | ||||
|         "@types/tough-cookie": "*", | ||||
|         "parse5": "^7.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/jsdom/node_modules/entities": { | ||||
|       "version": "4.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", | ||||
|       "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", | ||||
|       "dev": true, | ||||
|       "engines": { | ||||
|         "node": ">=0.12" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/fb55/entities?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/jsdom/node_modules/parse5": { | ||||
|       "version": "7.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", | ||||
|       "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "entities": "^4.4.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/inikulin/parse5?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/json-schema": { | ||||
|       "version": "7.0.9", | ||||
|       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", | ||||
| @ -1439,6 +1476,89 @@ | ||||
|         "@types/node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/sanitize-html": { | ||||
|       "version": "2.11.0", | ||||
|       "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz", | ||||
|       "integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "htmlparser2": "^8.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/sanitize-html/node_modules/dom-serializer": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", | ||||
|       "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "domelementtype": "^2.3.0", | ||||
|         "domhandler": "^5.0.2", | ||||
|         "entities": "^4.2.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/sanitize-html/node_modules/domhandler": { | ||||
|       "version": "5.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", | ||||
|       "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "domelementtype": "^2.3.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 4" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/fb55/domhandler?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/sanitize-html/node_modules/domutils": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", | ||||
|       "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "dom-serializer": "^2.0.0", | ||||
|         "domelementtype": "^2.3.0", | ||||
|         "domhandler": "^5.0.3" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/fb55/domutils?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/sanitize-html/node_modules/entities": { | ||||
|       "version": "4.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", | ||||
|       "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", | ||||
|       "dev": true, | ||||
|       "engines": { | ||||
|         "node": ">=0.12" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/fb55/entities?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/sanitize-html/node_modules/htmlparser2": { | ||||
|       "version": "8.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", | ||||
|       "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", | ||||
|       "dev": true, | ||||
|       "funding": [ | ||||
|         "https://github.com/fb55/htmlparser2?sponsor=1", | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/fb55" | ||||
|         } | ||||
|       ], | ||||
|       "dependencies": { | ||||
|         "domelementtype": "^2.3.0", | ||||
|         "domhandler": "^5.0.3", | ||||
|         "domutils": "^3.0.1", | ||||
|         "entities": "^4.4.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/send": { | ||||
|       "version": "0.17.4", | ||||
|       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", | ||||
| @ -1460,6 +1580,12 @@ | ||||
|         "@types/node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/tough-cookie": { | ||||
|       "version": "4.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", | ||||
|       "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/@types/unist": { | ||||
|       "version": "2.0.10", | ||||
|       "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", | ||||
| @ -14124,6 +14250,34 @@ | ||||
|       "integrity": "sha512-mTehMtc+xtnWBBvqizcqYCktKDBH2WChvx1GU3Sfe4PysFDXiNe+1YwtpVX1MDtCa4NQrSPw2+3HmvXHY3gt1w==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "@types/jsdom": { | ||||
|       "version": "21.1.6", | ||||
|       "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz", | ||||
|       "integrity": "sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@types/node": "*", | ||||
|         "@types/tough-cookie": "*", | ||||
|         "parse5": "^7.0.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "entities": { | ||||
|           "version": "4.5.0", | ||||
|           "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", | ||||
|           "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "parse5": { | ||||
|           "version": "7.1.2", | ||||
|           "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", | ||||
|           "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "entities": "^4.4.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "@types/json-schema": { | ||||
|       "version": "7.0.9", | ||||
|       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", | ||||
| @ -14230,6 +14384,66 @@ | ||||
|         "@types/node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "@types/sanitize-html": { | ||||
|       "version": "2.11.0", | ||||
|       "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz", | ||||
|       "integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "htmlparser2": "^8.0.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "dom-serializer": { | ||||
|           "version": "2.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", | ||||
|           "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "domelementtype": "^2.3.0", | ||||
|             "domhandler": "^5.0.2", | ||||
|             "entities": "^4.2.0" | ||||
|           } | ||||
|         }, | ||||
|         "domhandler": { | ||||
|           "version": "5.0.3", | ||||
|           "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", | ||||
|           "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "domelementtype": "^2.3.0" | ||||
|           } | ||||
|         }, | ||||
|         "domutils": { | ||||
|           "version": "3.1.0", | ||||
|           "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", | ||||
|           "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "dom-serializer": "^2.0.0", | ||||
|             "domelementtype": "^2.3.0", | ||||
|             "domhandler": "^5.0.3" | ||||
|           } | ||||
|         }, | ||||
|         "entities": { | ||||
|           "version": "4.5.0", | ||||
|           "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", | ||||
|           "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "htmlparser2": { | ||||
|           "version": "8.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", | ||||
|           "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "domelementtype": "^2.3.0", | ||||
|             "domhandler": "^5.0.3", | ||||
|             "domutils": "^3.0.1", | ||||
|             "entities": "^4.4.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "@types/send": { | ||||
|       "version": "0.17.4", | ||||
|       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", | ||||
| @ -14251,6 +14465,12 @@ | ||||
|         "@types/node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "@types/tough-cookie": { | ||||
|       "version": "4.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", | ||||
|       "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "@types/unist": { | ||||
|       "version": "2.0.10", | ||||
|       "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", | ||||
|  | ||||
| @ -114,8 +114,10 @@ | ||||
|     "@types/escape-html": "^1.0.4", | ||||
|     "@types/express": "^4.17.21", | ||||
|     "@types/ini": "^4.1.0", | ||||
|     "@types/jsdom": "^21.1.6", | ||||
|     "@types/mime-types": "^2.1.4", | ||||
|     "@types/node": "^20.11.19", | ||||
|     "@types/sanitize-html": "^2.11.0", | ||||
|     "@types/ws": "^8.5.10", | ||||
|     "cross-env": "7.0.3", | ||||
|     "electron": "25.9.8", | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| const anonymizationService = require('./services/anonymization.js'); | ||||
| const sqlInit = require('./services/sql_init.js'); | ||||
| require('./becca/entity_constructor.js'); | ||||
| const anonymizationService = require('./services/anonymization'); | ||||
| const sqlInit = require('./services/sql_init'); | ||||
| require('./becca/entity_constructor'); | ||||
| 
 | ||||
| sqlInit.dbReady.then(async () => { | ||||
|     try { | ||||
|  | ||||
| @ -8,7 +8,7 @@ const sessionParser = require('./routes/session_parser.js'); | ||||
| const utils = require('./services/utils'); | ||||
| 
 | ||||
| require('./services/handlers.js'); | ||||
| require('./becca/becca_loader.js'); | ||||
| require('./becca/becca_loader'); | ||||
| 
 | ||||
| const app = express(); | ||||
| 
 | ||||
| @ -46,7 +46,7 @@ require('./routes/error_handlers.js').register(app); | ||||
| require('./services/sync.js'); | ||||
| 
 | ||||
| // triggers backup timer
 | ||||
| require('./services/backup.js'); | ||||
| require('./services/backup'); | ||||
| 
 | ||||
| // trigger consistency checks timer
 | ||||
| require('./services/consistency_checks.js'); | ||||
|  | ||||
| @ -21,7 +21,7 @@ interface AttachmentOpts { | ||||
|  * Becca is a backend cache of all notes, branches, and attributes. | ||||
|  * There's a similar frontend cache Froca, and share cache Shaca. | ||||
|  */ | ||||
| class Becca { | ||||
| export default class Becca { | ||||
|     loaded!: boolean; | ||||
| 
 | ||||
|     notes!: Record<string, BNote>; | ||||
| @ -280,4 +280,12 @@ class Becca { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export = Becca; | ||||
| /** | ||||
|  * This interface contains the data that is shared across all the objects of a given derived class of {@link AbstractBeccaEntity}. | ||||
|  * For example, all BAttributes will share their content, but all BBranches will have another set of this data.  | ||||
|  */ | ||||
| export interface ConstructorData<T extends AbstractBeccaEntity<T>> { | ||||
|     primaryKeyName: string; | ||||
|     entityName: string; | ||||
|     hashedProperties: (keyof T)[]; | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| import Becca = require("./becca-interface"); | ||||
| import Becca from "./becca-interface"; | ||||
| 
 | ||||
| const becca = new Becca(); | ||||
| 
 | ||||
|  | ||||
| @ -1,19 +1,21 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const sql = require('../services/sql'); | ||||
| const eventService = require('../services/events'); | ||||
| const becca = require('./becca'); | ||||
| const sqlInit = require('../services/sql_init'); | ||||
| const log = require('../services/log'); | ||||
| const BNote = require('./entities/bnote'); | ||||
| const BBranch = require('./entities/bbranch'); | ||||
| const BAttribute = require('./entities/battribute'); | ||||
| const BOption = require('./entities/boption'); | ||||
| const BEtapiToken = require('./entities/betapi_token'); | ||||
| const cls = require('../services/cls'); | ||||
| const entityConstructor = require('../becca/entity_constructor'); | ||||
| import sql = require('../services/sql'); | ||||
| import eventService = require('../services/events'); | ||||
| import becca = require('./becca'); | ||||
| import sqlInit = require('../services/sql_init'); | ||||
| import log = require('../services/log'); | ||||
| import BNote = require('./entities/bnote'); | ||||
| import BBranch = require('./entities/bbranch'); | ||||
| import BAttribute = require('./entities/battribute'); | ||||
| import BOption = require('./entities/boption'); | ||||
| import BEtapiToken = require('./entities/betapi_token'); | ||||
| import cls = require('../services/cls'); | ||||
| import entityConstructor = require('../becca/entity_constructor'); | ||||
| import { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from './entities/rows'; | ||||
| import AbstractBeccaEntity = require('./entities/abstract_becca_entity'); | ||||
| 
 | ||||
| const beccaLoaded = new Promise((res, rej) => { | ||||
| const beccaLoaded = new Promise<void>((res, rej) => { | ||||
|     sqlInit.dbReady.then(() => { | ||||
|         cls.init(() => { | ||||
|             load(); | ||||
| @ -38,23 +40,23 @@ function load() { | ||||
|             new BNote().update(row).init(); | ||||
|         } | ||||
| 
 | ||||
|         const branchRows = sql.getRawRows(`SELECT branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified FROM branches WHERE isDeleted = 0`); | ||||
|         const branchRows = sql.getRawRows<BranchRow>(`SELECT branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified FROM branches WHERE isDeleted = 0`); | ||||
|         // in-memory sort is faster than in the DB
 | ||||
|         branchRows.sort((a, b) => a.notePosition - b.notePosition); | ||||
|         branchRows.sort((a, b) => (a.notePosition || 0) - (b.notePosition || 0)); | ||||
| 
 | ||||
|         for (const row of branchRows) { | ||||
|             new BBranch().update(row).init(); | ||||
|         } | ||||
| 
 | ||||
|         for (const row of sql.getRawRows(`SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified FROM attributes WHERE isDeleted = 0`)) { | ||||
|         for (const row of sql.getRawRows<AttributeRow>(`SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified FROM attributes WHERE isDeleted = 0`)) { | ||||
|             new BAttribute().update(row).init(); | ||||
|         } | ||||
| 
 | ||||
|         for (const row of sql.getRows(`SELECT name, value, isSynced, utcDateModified FROM options`)) { | ||||
|         for (const row of sql.getRows<OptionRow>(`SELECT name, value, isSynced, utcDateModified FROM options`)) { | ||||
|             new BOption(row); | ||||
|         } | ||||
| 
 | ||||
|         for (const row of sql.getRows(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) { | ||||
|         for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) { | ||||
|             new BEtapiToken(row); | ||||
|         } | ||||
|     }); | ||||
| @ -68,7 +70,7 @@ function load() { | ||||
|     log.info(`Becca (note cache) load took ${Date.now() - start}ms`); | ||||
| } | ||||
| 
 | ||||
| function reload(reason) { | ||||
| function reload(reason: string) { | ||||
|     load(); | ||||
| 
 | ||||
|     require('../services/ws').reloadFrontend(reason || "becca reloaded"); | ||||
| @ -88,7 +90,7 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({ entity | ||||
|         if (beccaEntity) { | ||||
|             beccaEntity.updateFromRow(entityRow); | ||||
|         } else { | ||||
|             beccaEntity = new EntityClass(); | ||||
|             beccaEntity = new EntityClass() as AbstractBeccaEntity<AbstractBeccaEntity<any>>; | ||||
|             beccaEntity.updateFromRow(entityRow); | ||||
|             beccaEntity.init(); | ||||
|         } | ||||
| @ -112,7 +114,7 @@ eventService.subscribeBeccaLoader(eventService.ENTITY_CHANGED, ({ entityName, en | ||||
|  * @param entityRow - can be a becca entity (change comes from this trilium instance) or just a row (from sync). | ||||
|  *                    It should be therefore treated as a row. | ||||
|  */ | ||||
| function postProcessEntityUpdate(entityName, entityRow) { | ||||
| function postProcessEntityUpdate(entityName: string, entityRow: any) { | ||||
|     if (entityName === 'notes') { | ||||
|         noteUpdated(entityRow); | ||||
|     } else if (entityName === 'branches') { | ||||
| @ -140,13 +142,13 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENT | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| function noteDeleted(noteId) { | ||||
| function noteDeleted(noteId: string) { | ||||
|     delete becca.notes[noteId]; | ||||
| 
 | ||||
|     becca.dirtyNoteSetCache(); | ||||
| } | ||||
| 
 | ||||
| function branchDeleted(branchId) { | ||||
| function branchDeleted(branchId: string) { | ||||
|     const branch = becca.branches[branchId]; | ||||
| 
 | ||||
|     if (!branch) { | ||||
| @ -173,23 +175,26 @@ function branchDeleted(branchId) { | ||||
|     } | ||||
| 
 | ||||
|     delete becca.childParentToBranch[`${branch.noteId}-${branch.parentNoteId}`]; | ||||
|     if (branch.branchId) { | ||||
|         delete becca.branches[branch.branchId]; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function noteUpdated(entityRow) { | ||||
| function noteUpdated(entityRow: NoteRow) { | ||||
|     const note = becca.notes[entityRow.noteId]; | ||||
| 
 | ||||
|     if (note) { | ||||
|         // TODO, this wouldn't have worked in the original implementation since the variable was named __flatTextCache.
 | ||||
|         // type / mime could have been changed, and they are present in flatTextCache
 | ||||
|         note.flatTextCache = null; | ||||
|         note.__flatTextCache = null; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function branchUpdated(branchRow) { | ||||
| function branchUpdated(branchRow: BranchRow) { | ||||
|     const childNote = becca.notes[branchRow.noteId]; | ||||
| 
 | ||||
|     if (childNote) { | ||||
|         childNote.flatTextCache = null; | ||||
|         childNote.__flatTextCache = null; | ||||
|         childNote.sortParents(); | ||||
| 
 | ||||
|         // notes in the subtree can get new inherited attributes
 | ||||
| @ -204,7 +209,7 @@ function branchUpdated(branchRow) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function attributeDeleted(attributeId) { | ||||
| function attributeDeleted(attributeId: string) { | ||||
|     const attribute = becca.attributes[attributeId]; | ||||
| 
 | ||||
|     if (!attribute) { | ||||
| @ -239,8 +244,7 @@ function attributeDeleted(attributeId) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** @param {BAttribute} attributeRow */ | ||||
| function attributeUpdated(attributeRow) { | ||||
| function attributeUpdated(attributeRow: BAttribute) { | ||||
|     const attribute = becca.attributes[attributeRow.attributeId]; | ||||
|     const note = becca.notes[attributeRow.noteId]; | ||||
| 
 | ||||
| @ -253,7 +257,7 @@ function attributeUpdated(attributeRow) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function noteReorderingUpdated(branchIdList) { | ||||
| function noteReorderingUpdated(branchIdList: number[]) { | ||||
|     const parentNoteIds = new Set(); | ||||
| 
 | ||||
|     for (const branchId in branchIdList) { | ||||
| @ -267,7 +271,7 @@ function noteReorderingUpdated(branchIdList) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function etapiTokenDeleted(etapiTokenId) { | ||||
| function etapiTokenDeleted(etapiTokenId: string) { | ||||
|     delete becca.etapiTokens[etapiTokenId]; | ||||
| } | ||||
| 
 | ||||
| @ -275,14 +279,14 @@ eventService.subscribeBeccaLoader(eventService.ENTER_PROTECTED_SESSION, () => { | ||||
|     try { | ||||
|         becca.decryptProtectedNotes(); | ||||
|     } | ||||
|     catch (e) { | ||||
|     catch (e: any) { | ||||
|         log.error(`Could not decrypt protected notes: ${e.message} ${e.stack}`); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| eventService.subscribeBeccaLoader(eventService.LEAVE_PROTECTED_SESSION, load); | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     load, | ||||
|     reload, | ||||
|     beccaLoaded | ||||
| @ -1,10 +1,10 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const becca = require('./becca'); | ||||
| const cls = require('../services/cls'); | ||||
| const log = require('../services/log'); | ||||
| import becca = require('./becca'); | ||||
| import cls = require('../services/cls'); | ||||
| import log = require('../services/log'); | ||||
| 
 | ||||
| function isNotePathArchived(notePath) { | ||||
| function isNotePathArchived(notePath: string[]) { | ||||
|     const noteId = notePath[notePath.length - 1]; | ||||
|     const note = becca.notes[noteId]; | ||||
| 
 | ||||
| @ -24,9 +24,9 @@ function isNotePathArchived(notePath) { | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| function getNoteTitle(childNoteId, parentNoteId) { | ||||
| function getNoteTitle(childNoteId: string, parentNoteId?: string) { | ||||
|     const childNote = becca.notes[childNoteId]; | ||||
|     const parentNote = becca.notes[parentNoteId]; | ||||
|     const parentNote = parentNoteId ? becca.notes[parentNoteId] : null; | ||||
| 
 | ||||
|     if (!childNote) { | ||||
|         log.info(`Cannot find note '${childNoteId}'`); | ||||
| @ -40,7 +40,7 @@ function getNoteTitle(childNoteId, parentNoteId) { | ||||
|     return `${(branch && branch.prefix) ? `${branch.prefix} - ` : ''}${title}`; | ||||
| } | ||||
| 
 | ||||
| function getNoteTitleArrayForPath(notePathArray) { | ||||
| function getNoteTitleArrayForPath(notePathArray: string[]) { | ||||
|     if (!notePathArray || !Array.isArray(notePathArray)) { | ||||
|         throw new Error(`${notePathArray} is not an array.`); | ||||
|     } | ||||
| @ -76,13 +76,13 @@ function getNoteTitleArrayForPath(notePathArray) { | ||||
|     return titles; | ||||
| } | ||||
| 
 | ||||
| function getNoteTitleForPath(notePathArray) { | ||||
| function getNoteTitleForPath(notePathArray: string[]) { | ||||
|     const titles = getNoteTitleArrayForPath(notePathArray); | ||||
| 
 | ||||
|     return titles.join(' / '); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     getNoteTitle, | ||||
|     getNoteTitleForPath, | ||||
|     isNotePathArchived | ||||
| @ -9,25 +9,15 @@ import cls = require('../../services/cls'); | ||||
| import log = require('../../services/log'); | ||||
| import protectedSessionService = require('../../services/protected_session'); | ||||
| import blobService = require('../../services/blob'); | ||||
| import Becca = require('../becca-interface'); | ||||
| import Becca, { ConstructorData } from '../becca-interface'; | ||||
| 
 | ||||
| let becca: Becca | null = null; | ||||
| let becca: Becca; | ||||
| 
 | ||||
| interface ContentOpts { | ||||
|     forceSave?: boolean; | ||||
|     forceFrontendReload?: boolean; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * This interface contains the data that is shared across all the objects of a given derived class of {@link AbstractBeccaEntity}. | ||||
|  * For example, all BAttributes will share their content, but all BBranches will have another set of this data.  | ||||
|  */ | ||||
| interface ConstructorData<T extends AbstractBeccaEntity<T>> { | ||||
|     primaryKeyName: string; | ||||
|     entityName: string; | ||||
|     hashedProperties: (keyof T)[]; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Base class for all backend entities. | ||||
|  *  | ||||
| @ -35,11 +25,12 @@ interface ConstructorData<T extends AbstractBeccaEntity<T>> { | ||||
|  */ | ||||
| abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> { | ||||
| 
 | ||||
|     protected utcDateCreated?: string; | ||||
|     protected utcDateModified?: string; | ||||
|     protected dateCreated?: string; | ||||
|     protected dateModified?: string; | ||||
|      | ||||
|     utcDateCreated!: string; | ||||
| 
 | ||||
|     isProtected?: boolean; | ||||
|     isSynced?: boolean; | ||||
|     blobId?: string; | ||||
| @ -101,6 +92,12 @@ abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> { | ||||
| 
 | ||||
|     abstract getPojo(): {}; | ||||
| 
 | ||||
|     init() { | ||||
|         // Do nothing by default, can be overriden in derived classes.
 | ||||
|     } | ||||
| 
 | ||||
|     abstract updateFromRow(row: unknown): void; | ||||
| 
 | ||||
|     get isDeleted(): boolean { | ||||
|         // TODO: Not sure why some entities don't implement it.
 | ||||
|         return false; | ||||
| @ -109,7 +106,8 @@ abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> { | ||||
|     /** | ||||
|      * Saves entity - executes SQL, but doesn't commit the transaction on its own | ||||
|      */ | ||||
|     save(): this { | ||||
|     // TODO: opts not used but called a few times, maybe should be used by derived classes or passed to beforeSaving.
 | ||||
|     save(opts?: {}): this { | ||||
|         const constructorData = (this.constructor as unknown as ConstructorData<T>); | ||||
|         const entityName = constructorData.entityName; | ||||
|         const primaryKeyName = constructorData.primaryKeyName; | ||||
|  | ||||
| @ -37,16 +37,16 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|     noteId?: number; | ||||
|     attachmentId?: string; | ||||
|     /** either noteId or revisionId to which this attachment belongs */ | ||||
|     ownerId: string; | ||||
|     role: string; | ||||
|     mime: string; | ||||
|     title: string; | ||||
|     ownerId!: string; | ||||
|     role!: string; | ||||
|     mime!: string; | ||||
|     title!: string; | ||||
|     type?: keyof typeof attachmentRoleToNoteTypeMapping; | ||||
|     position?: number; | ||||
|     blobId?: string; | ||||
|     isProtected?: boolean; | ||||
|     dateModified?: string; | ||||
|     utcDateScheduledForErasureSince?: string; | ||||
|     utcDateScheduledForErasureSince?: string | null; | ||||
|     /** optionally added to the entity */ | ||||
|     contentLength?: number; | ||||
|     isDecrypted?: boolean; | ||||
| @ -54,6 +54,11 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|     constructor(row: AttachmentRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.updateFromRow(row); | ||||
|         this.decrypt(); | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: AttachmentRow): void { | ||||
|         if (!row.ownerId?.trim()) { | ||||
|             throw new Error("'ownerId' must be given to initialize a Attachment entity"); | ||||
|         } else if (!row.role?.trim()) { | ||||
| @ -76,8 +81,6 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|         this.utcDateModified = row.utcDateModified; | ||||
|         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||
|         this.contentLength = row.contentLength; | ||||
| 
 | ||||
|         this.decrypt(); | ||||
|     } | ||||
| 
 | ||||
|     copy(): BAttachment { | ||||
| @ -127,8 +130,8 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getContent(): string | Buffer { | ||||
|         return this._getContent(); | ||||
|     getContent(): Buffer { | ||||
|         return this._getContent() as Buffer; | ||||
|     } | ||||
| 
 | ||||
|     setContent(content: string | Buffer, opts: ContentOpts) { | ||||
| @ -171,6 +174,11 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> { | ||||
| 
 | ||||
|         if (this.role === 'image' && parentNote.type === 'text') { | ||||
|             const origContent = parentNote.getContent(); | ||||
|              | ||||
|             if (typeof origContent !== "string") { | ||||
|                 throw new Error(`Note with ID '${note.noteId} has a text type but non-string content.`); | ||||
|             } | ||||
| 
 | ||||
|             const oldAttachmentUrl = `api/attachments/${this.attachmentId}/image/`; | ||||
|             const newNoteUrl = `api/images/${note.noteId}/`; | ||||
| 
 | ||||
|  | ||||
| @ -28,7 +28,7 @@ class BAttribute extends AbstractBeccaEntity<BAttribute> { | ||||
|     value!: string; | ||||
|     isInheritable!: boolean; | ||||
| 
 | ||||
|     constructor(row: AttributeRow) { | ||||
|     constructor(row?: AttributeRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         if (!row) { | ||||
| @ -52,7 +52,7 @@ class BAttribute extends AbstractBeccaEntity<BAttribute> { | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]: any[]) { | ||||
|     update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]: any) { | ||||
|         this.attributeId = attributeId; | ||||
|         this.noteId = noteId; | ||||
|         this.type = type; | ||||
|  | ||||
| @ -1,18 +1,24 @@ | ||||
| import AbstractBeccaEntity = require("./abstract_becca_entity"); | ||||
| import { BlobRow } from "./rows"; | ||||
| 
 | ||||
| // TODO: Why this does not extend the abstract becca?
 | ||||
| class BBlob { | ||||
| class BBlob extends AbstractBeccaEntity<BBlob> { | ||||
|     static get entityName() { return "blobs"; } | ||||
|     static get primaryKeyName() { return "blobId"; } | ||||
|     static get hashedProperties() { return ["blobId", "content"]; } | ||||
| 
 | ||||
|     blobId: string; | ||||
|     content: string | Buffer; | ||||
|     contentLength: number; | ||||
|     dateModified: string; | ||||
|     utcDateModified: string; | ||||
|     blobId!: string; | ||||
|     content!: string | Buffer; | ||||
|     contentLength!: number; | ||||
|     dateModified!: string; | ||||
|     utcDateModified!: string; | ||||
| 
 | ||||
|     constructor(row: BlobRow) { | ||||
|         super(); | ||||
|         this.updateFromRow(row); | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: BlobRow): void { | ||||
|         this.blobId = row.blobId; | ||||
|         this.content = row.content; | ||||
|         this.contentLength = row.contentLength; | ||||
|  | ||||
| @ -30,7 +30,7 @@ class BBranch extends AbstractBeccaEntity<BBranch> { | ||||
|     isExpanded!: boolean; | ||||
|     utcDateModified?: string; | ||||
| 
 | ||||
|     constructor(row: BranchRow) { | ||||
|     constructor(row?: BranchRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         if (!row) { | ||||
|  | ||||
| @ -19,12 +19,12 @@ class BEtapiToken extends AbstractBeccaEntity<BEtapiToken> { | ||||
|     static get primaryKeyName() { return "etapiTokenId"; } | ||||
|     static get hashedProperties() { return ["etapiTokenId", "name", "tokenHash", "utcDateCreated", "utcDateModified", "isDeleted"]; } | ||||
| 
 | ||||
|     etapiTokenId!: string; | ||||
|     etapiTokenId?: string; | ||||
|     name!: string; | ||||
|     tokenHash!: string; | ||||
|     private _isDeleted!: boolean; | ||||
|     private _isDeleted?: boolean; | ||||
| 
 | ||||
|     constructor(row: EtapiTokenRow) { | ||||
|     constructor(row?: EtapiTokenRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         if (!row) { | ||||
| @ -36,7 +36,7 @@ class BEtapiToken extends AbstractBeccaEntity<BEtapiToken> { | ||||
|     } | ||||
| 
 | ||||
|     get isDeleted() { | ||||
|         return this._isDeleted; | ||||
|         return !!this._isDeleted; | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: EtapiTokenRow) { | ||||
| @ -74,8 +74,10 @@ class BEtapiToken extends AbstractBeccaEntity<BEtapiToken> { | ||||
| 
 | ||||
|         super.beforeSaving(); | ||||
| 
 | ||||
|         if (this.etapiTokenId) { | ||||
|             this.becca.etapiTokens[this.etapiTokenId] = this; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export = BEtapiToken; | ||||
|  | ||||
| @ -70,7 +70,7 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|     children!: BNote[]; | ||||
|     targetRelations!: BAttribute[]; | ||||
| 
 | ||||
|     private __flatTextCache!: string | null; | ||||
|     __flatTextCache!: string | null; | ||||
| 
 | ||||
|     private __attributeCache!: BAttribute[] | null; | ||||
|     private __inheritableAttributeCache!: BAttribute[] | null; | ||||
| @ -86,7 +86,7 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|     /** number of note revisions for this note */ | ||||
|     private revisionCount!: number | null; | ||||
| 
 | ||||
|     constructor(row: Partial<NoteRow>) { | ||||
|     constructor(row?: Partial<NoteRow>) { | ||||
|         super(); | ||||
| 
 | ||||
|         if (!row) { | ||||
| @ -216,9 +216,8 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|      * - changes in the note metadata or title should not trigger note content sync (so we keep separate utcDateModified and entity changes records) | ||||
|      * - but to the user note content and title changes are one and the same - single dateModified (so all changes must go through Note and content is not a separate entity) | ||||
|      */ | ||||
|     // TODO: original declaration was (string | Buffer), but everywhere it's used as a string.
 | ||||
|     getContent(): string { | ||||
|         return this._getContent() as string; | ||||
|     getContent() { | ||||
|         return this._getContent(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -226,7 +225,7 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|     getJsonContent(): {} | null { | ||||
|         const content = this.getContent(); | ||||
| 
 | ||||
|         if (!content || !content.trim()) { | ||||
|         if (typeof content !== "string" || !content || !content.trim()) { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
| @ -243,7 +242,7 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     setContent(content: string, opts: ContentOpts = {}) { | ||||
|     setContent(content: Buffer | string, opts: ContentOpts = {}) { | ||||
|         this._setContent(content, opts); | ||||
| 
 | ||||
|         eventService.emit(eventService.NOTE_CONTENT_CHANGE, { entity: this }); | ||||
| @ -661,7 +660,7 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|      * @param name - relation name to filter | ||||
|      * @returns all note's relations (attributes with type relation), including inherited ones | ||||
|      */ | ||||
|     getRelations(name: string): BAttribute[] { | ||||
|     getRelations(name?: string): BAttribute[] { | ||||
|         return this.getAttributes(RELATION, name); | ||||
|     } | ||||
| 
 | ||||
| @ -1510,6 +1509,10 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|         const oldNoteUrl = `api/images/${this.noteId}/`; | ||||
|         const newAttachmentUrl = `api/attachments/${attachment.attachmentId}/image/`; | ||||
| 
 | ||||
|         if (typeof parentContent !== "string") { | ||||
|             throw new Error("Unable to convert image note into attachment because parent note does not have a string content."); | ||||
|         } | ||||
| 
 | ||||
|         const fixedContent = utils.replaceAll(parentContent, oldNoteUrl, newAttachmentUrl); | ||||
| 
 | ||||
|         parentNote.setContent(fixedContent); | ||||
| @ -1611,7 +1614,7 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|                 revisionAttachment.ownerId = revision.revisionId; | ||||
|                 revisionAttachment.setContent(noteAttachment.getContent(), { forceSave: true }); | ||||
| 
 | ||||
|                 if (this.type === 'text') { | ||||
|                 if (this.type === 'text' && typeof noteContent === "string") { | ||||
|                     // content is rewritten to point to the revision attachments
 | ||||
|                     noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`, | ||||
|                         `attachments/${revisionAttachment.attachmentId}`); | ||||
| @ -1654,7 +1657,10 @@ class BNote extends AbstractBeccaEntity<BNote> { | ||||
|             position | ||||
|         }); | ||||
| 
 | ||||
|         content = content || ""; | ||||
|         if (!content) { | ||||
|             throw new Error("Attempted to save an attachment with no content."); | ||||
|         } | ||||
| 
 | ||||
|         attachment.setContent(content, {forceSave: true}); | ||||
| 
 | ||||
|         return attachment; | ||||
|  | ||||
| @ -16,10 +16,12 @@ class BOption extends AbstractBeccaEntity<BOption> { | ||||
|     value!: string; | ||||
|     isSynced!: boolean; | ||||
| 
 | ||||
|     constructor(row: OptionRow) { | ||||
|     constructor(row?: OptionRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         if (row) { | ||||
|             this.updateFromRow(row); | ||||
|         } | ||||
|         this.becca.options[this.name] = this; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -11,14 +11,19 @@ import AbstractBeccaEntity = require('./abstract_becca_entity'); | ||||
| class BRecentNote extends AbstractBeccaEntity<BRecentNote> { | ||||
|     static get entityName() { return "recent_notes"; } | ||||
|     static get primaryKeyName() { return "noteId"; } | ||||
|     static get hashedProperties() { return ["noteId", "notePath"]; } | ||||
| 
 | ||||
|     noteId: string; | ||||
|     notePath: string; | ||||
|     utcDateCreated: string; | ||||
|     noteId!: string; | ||||
|     notePath!: string; | ||||
|     utcDateCreated!: string; | ||||
| 
 | ||||
|     constructor(row: RecentNoteRow) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.updateFromRow(row); | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: RecentNoteRow): void { | ||||
|         this.noteId = row.noteId; | ||||
|         this.notePath = row.notePath; | ||||
|         this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime(); | ||||
|  | ||||
| @ -29,22 +29,30 @@ class BRevision extends AbstractBeccaEntity<BRevision> { | ||||
|                                             "utcDateLastEdited", "utcDateCreated", "utcDateModified", "blobId"]; } | ||||
| 
 | ||||
|     revisionId?: string; | ||||
|     noteId: string; | ||||
|     type: string; | ||||
|     mime: string; | ||||
|     isProtected: boolean; | ||||
|     title: string; | ||||
|     noteId!: string; | ||||
|     type!: string; | ||||
|     mime!: string; | ||||
|     isProtected!: boolean; | ||||
|     title!: string; | ||||
|     blobId?: string; | ||||
|     dateLastEdited?: string; | ||||
|     dateCreated: string; | ||||
|     dateCreated!: string; | ||||
|     utcDateLastEdited?: string; | ||||
|     utcDateCreated: string; | ||||
|     utcDateCreated!: string; | ||||
|     contentLength?: number; | ||||
|     content?: string; | ||||
| 
 | ||||
|     constructor(row: RevisionRow, titleDecrypted = false) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.updateFromRow(row); | ||||
|         if (this.isProtected && !titleDecrypted) { | ||||
|             const decryptedTitle = protectedSessionService.isProtectedSessionAvailable() ? protectedSessionService.decryptString(this.title) : null; | ||||
|             this.title = decryptedTitle || "[protected]"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     updateFromRow(row: RevisionRow) { | ||||
|         this.revisionId = row.revisionId; | ||||
|         this.noteId = row.noteId; | ||||
|         this.type = row.type; | ||||
| @ -58,11 +66,6 @@ class BRevision extends AbstractBeccaEntity<BRevision> { | ||||
|         this.utcDateCreated = row.utcDateCreated; | ||||
|         this.utcDateModified = row.utcDateModified; | ||||
|         this.contentLength = row.contentLength; | ||||
| 
 | ||||
|         if (this.isProtected && !titleDecrypted) { | ||||
|             const decryptedTitle = protectedSessionService.isProtectedSessionAvailable() ? protectedSessionService.decryptString(this.title) : null; | ||||
|             this.title = decryptedTitle || "[protected]"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getNote() { | ||||
|  | ||||
| @ -5,7 +5,7 @@ export interface AttachmentRow { | ||||
|     ownerId?: string; | ||||
|     role: string; | ||||
|     mime: string; | ||||
|     title?: string; | ||||
|     title: string; | ||||
|     position?: number; | ||||
|     blobId?: string; | ||||
|     isProtected?: boolean; | ||||
| @ -13,7 +13,7 @@ export interface AttachmentRow { | ||||
|     utcDateModified?: string; | ||||
|     utcDateScheduledForErasureSince?: string; | ||||
|     contentLength?: number; | ||||
|     content?: string; | ||||
|     content?: Buffer | string; | ||||
| } | ||||
| 
 | ||||
| export interface RevisionRow { | ||||
| @ -46,12 +46,12 @@ export interface OptionRow { | ||||
| } | ||||
| 
 | ||||
| export interface EtapiTokenRow { | ||||
|     etapiTokenId: string; | ||||
|     etapiTokenId?: string; | ||||
|     name: string; | ||||
|     tokenHash: string; | ||||
|     utcDateCreated?: string; | ||||
|     utcDateModified?: string; | ||||
|     isDeleted: boolean; | ||||
|     isDeleted?: boolean; | ||||
| } | ||||
| 
 | ||||
| export interface BlobRow { | ||||
| @ -69,9 +69,9 @@ export interface AttributeRow { | ||||
|     noteId: string; | ||||
|     type: AttributeType; | ||||
|     name: string; | ||||
|     position: number; | ||||
|     value: string; | ||||
|     isInheritable: boolean; | ||||
|     position?: number; | ||||
|     value?: string; | ||||
|     isInheritable?: boolean; | ||||
|     utcDateModified?: string; | ||||
| } | ||||
| 
 | ||||
| @ -79,9 +79,10 @@ export interface BranchRow { | ||||
|     branchId?: string; | ||||
|     noteId: string; | ||||
|     parentNoteId: string; | ||||
|     prefix: string | null; | ||||
|     notePosition: number; | ||||
|     isExpanded: boolean; | ||||
|     prefix?: string | null; | ||||
|     notePosition: number | null; | ||||
|     isExpanded?: boolean; | ||||
|     isDeleted?: boolean; | ||||
|     utcDateModified?: string; | ||||
| } | ||||
| 
 | ||||
| @ -94,10 +95,12 @@ export type NoteType = ("file" | "image" | "search" | "noteMap" | "launcher" | " | ||||
| 
 | ||||
| export interface NoteRow { | ||||
|     noteId: string; | ||||
|     deleteId: string; | ||||
|     title: string; | ||||
|     type: NoteType; | ||||
|     mime: string; | ||||
|     isProtected: boolean; | ||||
|     isDeleted: boolean; | ||||
|     blobId: string; | ||||
|     dateCreated: string; | ||||
|     dateModified: string; | ||||
|  | ||||
| @ -1,33 +0,0 @@ | ||||
| const BAttachment = require('./entities/battachment'); | ||||
| const BAttribute = require('./entities/battribute'); | ||||
| const BBlob = require('./entities/bblob'); | ||||
| const BBranch = require('./entities/bbranch'); | ||||
| const BEtapiToken = require('./entities/betapi_token'); | ||||
| const BNote = require('./entities/bnote'); | ||||
| const BOption = require('./entities/boption'); | ||||
| const BRecentNote = require('./entities/brecent_note'); | ||||
| const BRevision = require('./entities/brevision'); | ||||
| 
 | ||||
| const ENTITY_NAME_TO_ENTITY = { | ||||
|     "attachments": BAttachment, | ||||
|     "attributes": BAttribute, | ||||
|     "blobs": BBlob, | ||||
|     "branches": BBranch, | ||||
|     "etapi_tokens": BEtapiToken, | ||||
|     "notes": BNote, | ||||
|     "options": BOption, | ||||
|     "recent_notes": BRecentNote, | ||||
|     "revisions": BRevision | ||||
| }; | ||||
| 
 | ||||
| function getEntityFromEntityName(entityName) { | ||||
|     if (!(entityName in ENTITY_NAME_TO_ENTITY)) { | ||||
|         throw new Error(`Entity for table '${entityName}' not found!`); | ||||
|     } | ||||
| 
 | ||||
|     return ENTITY_NAME_TO_ENTITY[entityName]; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|     getEntityFromEntityName | ||||
| }; | ||||
							
								
								
									
										37
									
								
								src/becca/entity_constructor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/becca/entity_constructor.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| import { ConstructorData } from './becca-interface'; | ||||
| import AbstractBeccaEntity = require('./entities/abstract_becca_entity'); | ||||
| import BAttachment = require('./entities/battachment'); | ||||
| import BAttribute = require('./entities/battribute'); | ||||
| import BBlob = require('./entities/bblob'); | ||||
| import BBranch = require('./entities/bbranch'); | ||||
| import BEtapiToken = require('./entities/betapi_token'); | ||||
| import BNote = require('./entities/bnote'); | ||||
| import BOption = require('./entities/boption'); | ||||
| import BRecentNote = require('./entities/brecent_note'); | ||||
| import BRevision = require('./entities/brevision'); | ||||
| 
 | ||||
| type EntityClass = new (row?: any) => AbstractBeccaEntity<any>; | ||||
| 
 | ||||
| const ENTITY_NAME_TO_ENTITY: Record<string, ConstructorData<any> & EntityClass> = { | ||||
|     "attachments": BAttachment, | ||||
|     "attributes": BAttribute, | ||||
|     "blobs": BBlob, | ||||
|     "branches": BBranch, | ||||
|     "etapi_tokens": BEtapiToken, | ||||
|     "notes": BNote, | ||||
|     "options": BOption, | ||||
|     "recent_notes": BRecentNote, | ||||
|     "revisions": BRevision | ||||
| }; | ||||
| 
 | ||||
| function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) { | ||||
|     if (!(entityName in ENTITY_NAME_TO_ENTITY)) { | ||||
|         throw new Error(`Entity for table '${entityName}' not found!`); | ||||
|     } | ||||
| 
 | ||||
|     return ENTITY_NAME_TO_ENTITY[entityName]; | ||||
| } | ||||
| 
 | ||||
| export = { | ||||
|     getEntityFromEntityName | ||||
| }; | ||||
| @ -1,8 +1,9 @@ | ||||
| const becca = require('./becca'); | ||||
| const log = require('../services/log'); | ||||
| const beccaService = require('./becca_service'); | ||||
| const dateUtils = require('../services/date_utils'); | ||||
| const {JSDOM} = require("jsdom"); | ||||
| import becca = require('./becca'); | ||||
| import log = require('../services/log'); | ||||
| import beccaService = require('./becca_service'); | ||||
| import dateUtils = require('../services/date_utils'); | ||||
| import { JSDOM } from "jsdom"; | ||||
| import BNote = require('./entities/bnote'); | ||||
| 
 | ||||
| const DEBUG = false; | ||||
| 
 | ||||
| @ -32,21 +33,25 @@ const IGNORED_ATTR_NAMES = [ | ||||
|     "pageurl", | ||||
| ]; | ||||
| 
 | ||||
| function filterUrlValue(value) { | ||||
| interface DateLimits { | ||||
|     minDate: string; | ||||
|     minExcludedDate: string; | ||||
|     maxExcludedDate: string; | ||||
|     maxDate: string; | ||||
| } | ||||
| 
 | ||||
| function filterUrlValue(value: string) { | ||||
|     return value | ||||
|         .replace(/https?:\/\//ig, "") | ||||
|         .replace(/www.js\./ig, "") | ||||
|         .replace(/(\.net|\.com|\.org|\.info|\.edu)/ig, ""); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @param {BNote} note | ||||
|  */ | ||||
| function buildRewardMap(note) { | ||||
| function buildRewardMap(note: BNote) { | ||||
|     // Need to use Map instead of object: https://github.com/zadam/trilium/issues/1895
 | ||||
|     const map = new Map(); | ||||
| 
 | ||||
|     function addToRewardMap(text, rewardFactor) { | ||||
|     function addToRewardMap(text: string | undefined | null, rewardFactor: number) { | ||||
|         if (!text) { | ||||
|             return; | ||||
|         } | ||||
| @ -126,7 +131,7 @@ function buildRewardMap(note) { | ||||
|         const content = note.getContent(); | ||||
|         const dom = new JSDOM(content); | ||||
| 
 | ||||
|         function addHeadingsToRewardMap(elName, rewardFactor) { | ||||
|         const addHeadingsToRewardMap = (elName: string, rewardFactor: number) => { | ||||
|             for (const el of dom.window.document.querySelectorAll(elName)) { | ||||
|                 addToRewardMap(el.textContent, rewardFactor); | ||||
|             } | ||||
| @ -146,9 +151,9 @@ function buildRewardMap(note) { | ||||
|     return map; | ||||
| } | ||||
| 
 | ||||
| const mimeCache = {}; | ||||
| const mimeCache: Record<string, string> = {}; | ||||
| 
 | ||||
| function trimMime(mime) { | ||||
| function trimMime(mime: string) { | ||||
|     if (!mime || mime === 'text/html') { | ||||
|         return; | ||||
|     } | ||||
| @ -173,7 +178,7 @@ function trimMime(mime) { | ||||
|     return mimeCache[mime]; | ||||
| } | ||||
| 
 | ||||
| function buildDateLimits(baseNote) { | ||||
| function buildDateLimits(baseNote: BNote): DateLimits { | ||||
|     const dateCreatedTs = dateUtils.parseDateTime(baseNote.utcDateCreated).getTime(); | ||||
| 
 | ||||
|     return { | ||||
| @ -193,7 +198,7 @@ const WORD_BLACKLIST = [ | ||||
|     "than", "then", "and", "either", "or", "neither", "nor", "both", "also" | ||||
| ]; | ||||
| 
 | ||||
| function splitToWords(text) { | ||||
| function splitToWords(text: string) { | ||||
|     let words = wordCache.get(text); | ||||
| 
 | ||||
|     if (!words) { | ||||
| @ -221,13 +226,13 @@ function splitToWords(text) { | ||||
|  * includeNoteLink and imageLink relation mean that notes are clearly related, but so clearly | ||||
|  * that it doesn't actually need to be shown to the user. | ||||
|  */ | ||||
| function hasConnectingRelation(sourceNote, targetNote) { | ||||
| function hasConnectingRelation(sourceNote: BNote, targetNote: BNote) { | ||||
|     return sourceNote.getAttributes().find(attr => attr.type === 'relation' | ||||
|         && ['includenotelink', 'imagelink'].includes(attr.name) | ||||
|         && attr.value === targetNote.noteId); | ||||
| } | ||||
| 
 | ||||
| async function findSimilarNotes(noteId) { | ||||
| async function findSimilarNotes(noteId: string) { | ||||
|     const results = []; | ||||
|     let i = 0; | ||||
| 
 | ||||
| @ -237,23 +242,23 @@ async function findSimilarNotes(noteId) { | ||||
|         return []; | ||||
|     } | ||||
| 
 | ||||
|     let dateLimits; | ||||
|     let dateLimits: DateLimits; | ||||
| 
 | ||||
|     try { | ||||
|         dateLimits = buildDateLimits(baseNote); | ||||
|     } | ||||
|     catch (e) { | ||||
|     catch (e: any) { | ||||
|         throw new Error(`Date limits failed with ${e.message}, entity: ${JSON.stringify(baseNote.getPojo())}`); | ||||
|     } | ||||
| 
 | ||||
|     const rewardMap = buildRewardMap(baseNote); | ||||
|     let ancestorRewardCache = {}; | ||||
|     let ancestorRewardCache: Record<string, number> = {}; | ||||
|     const ancestorNoteIds = new Set(baseNote.getAncestors().map(note => note.noteId)); | ||||
|     ancestorNoteIds.add(baseNote.noteId); | ||||
| 
 | ||||
|     let displayRewards = false; | ||||
| 
 | ||||
|     function gatherRewards(text, factor = 1) { | ||||
|     function gatherRewards(text?: string | null, factor: number = 1) { | ||||
|         if (!text) { | ||||
|             return 0; | ||||
|         } | ||||
| @ -279,7 +284,7 @@ async function findSimilarNotes(noteId) { | ||||
|         return counter; | ||||
|     } | ||||
| 
 | ||||
|     function gatherAncestorRewards(note) { | ||||
|     function gatherAncestorRewards(note?: BNote) { | ||||
|         if (!note || ancestorNoteIds.has(note.noteId)) { | ||||
|             return 0; | ||||
|         } | ||||
| @ -311,7 +316,7 @@ async function findSimilarNotes(noteId) { | ||||
|         return ancestorRewardCache[note.noteId]; | ||||
|     } | ||||
| 
 | ||||
|     function computeScore(candidateNote) { | ||||
|     function computeScore(candidateNote: BNote) { | ||||
|         let score = gatherRewards(trimMime(candidateNote.mime)) | ||||
|             + gatherAncestorRewards(candidateNote); | ||||
| 
 | ||||
| @ -451,11 +456,11 @@ async function findSimilarNotes(noteId) { | ||||
|  * see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/
 | ||||
|  */ | ||||
| function setImmediatePromise() { | ||||
|     return new Promise((resolve) => { | ||||
|     return new Promise<void>((resolve) => { | ||||
|         setTimeout(() => resolve(), 0); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     findSimilarNotes | ||||
| }; | ||||
| @ -6,4 +6,4 @@ class ValidationError { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = ValidationError; | ||||
| export = ValidationError; | ||||
| @ -1,4 +1,4 @@ | ||||
| const appInfo = require('../services/app_info.js'); | ||||
| const appInfo = require('../services/app_info'); | ||||
| const eu = require('./etapi_utils'); | ||||
| 
 | ||||
| function register(router) { | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| const becca = require('../becca/becca'); | ||||
| const eu = require('./etapi_utils'); | ||||
| const passwordEncryptionService = require('../services/encryption/password_encryption'); | ||||
| const etapiTokenService = require('../services/etapi_tokens.js'); | ||||
| const etapiTokenService = require('../services/etapi_tokens'); | ||||
| 
 | ||||
| function register(router, loginMiddleware) { | ||||
|     eu.NOT_AUTHENTICATED_ROUTE(router, 'post', '/etapi/auth/login', loginMiddleware, (req, res, next) => { | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| const eu = require('./etapi_utils'); | ||||
| const backupService = require('../services/backup.js'); | ||||
| const backupService = require('../services/backup'); | ||||
| 
 | ||||
| function register(router) { | ||||
|     eu.route(router, 'put', '/etapi/backup/:backupName', async (req, res, next) => { | ||||
|  | ||||
| @ -2,7 +2,7 @@ const cls = require('../services/cls'); | ||||
| const sql = require('../services/sql'); | ||||
| const log = require('../services/log'); | ||||
| const becca = require('../becca/becca'); | ||||
| const etapiTokenService = require('../services/etapi_tokens.js'); | ||||
| const etapiTokenService = require('../services/etapi_tokens'); | ||||
| const config = require('../services/config'); | ||||
| const GENERIC_CODE = "GENERIC"; | ||||
| 
 | ||||
|  | ||||
| @ -2,7 +2,7 @@ const becca = require('../becca/becca'); | ||||
| const utils = require('../services/utils'); | ||||
| const eu = require('./etapi_utils'); | ||||
| const mappers = require('./mappers.js'); | ||||
| const noteService = require('../services/notes.js'); | ||||
| const noteService = require('../services/notes'); | ||||
| const TaskContext = require('../services/task_context'); | ||||
| const v = require('./validators.js'); | ||||
| const searchService = require('../services/search/services/search.js'); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| const noteTypeService = require('../services/note_types.js'); | ||||
| const noteTypeService = require('../services/note_types'); | ||||
| const dateUtils = require('../services/date_utils'); | ||||
| 
 | ||||
| function mandatory(obj) { | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const appInfo = require('../../services/app_info.js'); | ||||
| const appInfo = require('../../services/app_info'); | ||||
| 
 | ||||
| function getAppInfo() { | ||||
|     return appInfo; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const beccaService = require('../../becca/becca_service.js'); | ||||
| const beccaService = require('../../becca/becca_service'); | ||||
| const searchService = require('../../services/search/services/search.js'); | ||||
| const log = require('../../services/log'); | ||||
| const utils = require('../../services/utils'); | ||||
|  | ||||
| @ -4,7 +4,7 @@ const sql = require('../../services/sql'); | ||||
| const utils = require('../../services/utils'); | ||||
| const entityChangesService = require('../../services/entity_changes'); | ||||
| const treeService = require('../../services/tree.js'); | ||||
| const eraseService = require('../../services/erase.js'); | ||||
| const eraseService = require('../../services/erase'); | ||||
| const becca = require('../../becca/becca'); | ||||
| const TaskContext = require('../../services/task_context'); | ||||
| const branchService = require('../../services/branches.js'); | ||||
|  | ||||
| @ -2,17 +2,17 @@ | ||||
| 
 | ||||
| const attributeService = require('../../services/attributes.js'); | ||||
| const cloneService = require('../../services/cloning.js'); | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const dateNoteService = require('../../services/date_notes.js'); | ||||
| const dateUtils = require('../../services/date_utils'); | ||||
| const imageService = require('../../services/image.js'); | ||||
| const appInfo = require('../../services/app_info.js'); | ||||
| const appInfo = require('../../services/app_info'); | ||||
| const ws = require('../../services/ws'); | ||||
| const log = require('../../services/log'); | ||||
| const utils = require('../../services/utils'); | ||||
| const path = require('path'); | ||||
| const htmlSanitizer = require('../../services/html_sanitizer.js'); | ||||
| const {formatAttrForSearch} = require('../../services/attribute_formatter.js'); | ||||
| const htmlSanitizer = require('../../services/html_sanitizer'); | ||||
| const {formatAttrForSearch} = require('../../services/attribute_formatter'); | ||||
| const jsdom = require("jsdom"); | ||||
| const { JSDOM } = jsdom; | ||||
| 
 | ||||
|  | ||||
| @ -2,8 +2,8 @@ | ||||
| 
 | ||||
| const sql = require('../../services/sql'); | ||||
| const log = require('../../services/log'); | ||||
| const backupService = require('../../services/backup.js'); | ||||
| const anonymizationService = require('../../services/anonymization.js'); | ||||
| const backupService = require('../../services/backup'); | ||||
| const anonymizationService = require('../../services/anonymization'); | ||||
| const consistencyChecksService = require('../../services/consistency_checks.js'); | ||||
| 
 | ||||
| function getExistingBackups() { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| const etapiTokenService = require('../../services/etapi_tokens.js'); | ||||
| const etapiTokenService = require('../../services/etapi_tokens'); | ||||
| 
 | ||||
| function getTokens() { | ||||
|     const tokens = etapiTokenService.getTokens(); | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| const protectedSessionService = require('../../services/protected_session'); | ||||
| const utils = require('../../services/utils'); | ||||
| const log = require('../../services/log'); | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const tmp = require('tmp'); | ||||
| const fs = require('fs'); | ||||
| const { Readable } = require('stream'); | ||||
|  | ||||
| @ -7,7 +7,7 @@ const singleImportService = require('../../services/import/single.js'); | ||||
| const cls = require('../../services/cls'); | ||||
| const path = require('path'); | ||||
| const becca = require('../../becca/becca'); | ||||
| const beccaLoader = require('../../becca/becca_loader.js'); | ||||
| const beccaLoader = require('../../becca/becca_loader'); | ||||
| const log = require('../../services/log'); | ||||
| const TaskContext = require('../../services/task_context'); | ||||
| const ValidationError = require('../../errors/validation_error'); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const keyboardActions = require('../../services/keyboard_actions.js'); | ||||
| const keyboardActions = require('../../services/keyboard_actions'); | ||||
| const becca = require('../../becca/becca'); | ||||
| 
 | ||||
| function getKeyboardActions() { | ||||
|  | ||||
| @ -6,12 +6,12 @@ const dateUtils = require('../../services/date_utils'); | ||||
| const instanceId = require('../../services/instance_id'); | ||||
| const passwordEncryptionService = require('../../services/encryption/password_encryption'); | ||||
| const protectedSessionService = require('../../services/protected_session'); | ||||
| const appInfo = require('../../services/app_info.js'); | ||||
| const appInfo = require('../../services/app_info'); | ||||
| const eventService = require('../../services/events'); | ||||
| const sqlInit = require('../../services/sql_init.js'); | ||||
| const sqlInit = require('../../services/sql_init'); | ||||
| const sql = require('../../services/sql'); | ||||
| const ws = require('../../services/ws'); | ||||
| const etapiTokenService = require('../../services/etapi_tokens.js'); | ||||
| const etapiTokenService = require('../../services/etapi_tokens'); | ||||
| 
 | ||||
| function loginSync(req) { | ||||
|     if (!sqlInit.schemaExists()) { | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const eraseService = require('../../services/erase.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const eraseService = require('../../services/erase'); | ||||
| const treeService = require('../../services/tree.js'); | ||||
| const sql = require('../../services/sql'); | ||||
| const utils = require('../../services/utils'); | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
| const sql = require('../../services/sql'); | ||||
| const protectedSessionService = require('../../services/protected_session'); | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const becca = require('../../becca/becca'); | ||||
| 
 | ||||
| function getRecentChanges(req) { | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const beccaService = require('../../becca/becca_service.js'); | ||||
| const revisionService = require('../../services/revisions.js'); | ||||
| const beccaService = require('../../becca/becca_service'); | ||||
| const revisionService = require('../../services/revisions'); | ||||
| const utils = require('../../services/utils'); | ||||
| const sql = require('../../services/sql'); | ||||
| const cls = require('../../services/cls'); | ||||
| const path = require('path'); | ||||
| const becca = require('../../becca/becca'); | ||||
| const blobService = require('../../services/blob'); | ||||
| const eraseService = require("../../services/erase.js"); | ||||
| const eraseService = require("../../services/erase"); | ||||
| 
 | ||||
| function getRevisionBlob(req) { | ||||
|     const preview = req.query.preview === 'true'; | ||||
|  | ||||
| @ -5,7 +5,7 @@ const SearchContext = require('../../services/search/search_context.js'); | ||||
| const searchService = require('../../services/search/services/search.js'); | ||||
| const bulkActionService = require('../../services/bulk_actions.js'); | ||||
| const cls = require('../../services/cls'); | ||||
| const {formatAttrForSearch} = require('../../services/attribute_formatter.js'); | ||||
| const {formatAttrForSearch} = require('../../services/attribute_formatter'); | ||||
| const ValidationError = require('../../errors/validation_error'); | ||||
| 
 | ||||
| function searchFromNote(req) { | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
| const imageType = require('image-type'); | ||||
| const imageService = require('../../services/image.js'); | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const {sanitizeAttributeName} = require('../../services/sanitize_attribute_name'); | ||||
| const specialNotesService = require('../../services/special_notes.js'); | ||||
| 
 | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const sqlInit = require('../../services/sql_init.js'); | ||||
| const sqlInit = require('../../services/sql_init'); | ||||
| const setupService = require('../../services/setup.js'); | ||||
| const log = require('../../services/log'); | ||||
| const appInfo = require('../../services/app_info.js'); | ||||
| const appInfo = require('../../services/app_info'); | ||||
| 
 | ||||
| function getStatus() { | ||||
|     return { | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const similarityService = require('../../becca/similarity.js'); | ||||
| const similarityService = require('../../becca/similarity'); | ||||
| const becca = require('../../becca/becca'); | ||||
| 
 | ||||
| async function getSimilarNotes(req) { | ||||
|  | ||||
| @ -4,11 +4,11 @@ const syncService = require('../../services/sync.js'); | ||||
| const syncUpdateService = require('../../services/sync_update.js'); | ||||
| const entityChangesService = require('../../services/entity_changes'); | ||||
| const sql = require('../../services/sql'); | ||||
| const sqlInit = require('../../services/sql_init.js'); | ||||
| const sqlInit = require('../../services/sql_init'); | ||||
| const optionService = require('../../services/options'); | ||||
| const contentHashService = require('../../services/content_hash.js'); | ||||
| const log = require('../../services/log'); | ||||
| const syncOptions = require('../../services/sync_options.js'); | ||||
| const syncOptions = require('../../services/sync_options'); | ||||
| const utils = require('../../services/utils'); | ||||
| const ws = require('../../services/ws'); | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| const assetPath = require('../services/asset_path.js'); | ||||
| const assetPath = require('../services/asset_path'); | ||||
| const path = require("path"); | ||||
| const express = require("express"); | ||||
| const env = require('../services/env'); | ||||
|  | ||||
| @ -9,8 +9,8 @@ const env = require('../services/env'); | ||||
| const utils = require('../services/utils'); | ||||
| const protectedSessionService = require('../services/protected_session'); | ||||
| const packageJson = require('../../package.json'); | ||||
| const assetPath = require('../services/asset_path.js'); | ||||
| const appPath = require('../services/app_path.js'); | ||||
| const assetPath = require('../services/asset_path'); | ||||
| const appPath = require('../services/app_path'); | ||||
| 
 | ||||
| function index(req, res) { | ||||
|     const options = optionService.getOptionMap(); | ||||
|  | ||||
| @ -5,8 +5,8 @@ const optionService = require('../services/options'); | ||||
| const myScryptService = require('../services/encryption/my_scrypt'); | ||||
| const log = require('../services/log'); | ||||
| const passwordService = require('../services/encryption/password'); | ||||
| const assetPath = require('../services/asset_path.js'); | ||||
| const appPath = require('../services/app_path.js'); | ||||
| const assetPath = require('../services/asset_path'); | ||||
| const appPath = require('../services/app_path'); | ||||
| const ValidationError = require('../errors/validation_error'); | ||||
| 
 | ||||
| function loginPage(req, res) { | ||||
|  | ||||
| @ -5,7 +5,7 @@ const multer = require('multer'); | ||||
| const log = require('../services/log'); | ||||
| const express = require('express'); | ||||
| const router = express.Router(); | ||||
| const auth = require('../services/auth.js'); | ||||
| const auth = require('../services/auth'); | ||||
| const cls = require('../services/cls'); | ||||
| const sql = require('../services/sql'); | ||||
| const entityChangesService = require('../services/entity_changes'); | ||||
| @ -28,14 +28,14 @@ const branchesApiRoute = require('./api/branches.js'); | ||||
| const attachmentsApiRoute = require('./api/attachments.js'); | ||||
| const autocompleteApiRoute = require('./api/autocomplete.js'); | ||||
| const cloningApiRoute = require('./api/cloning.js'); | ||||
| const revisionsApiRoute = require('./api/revisions.js'); | ||||
| const revisionsApiRoute = require('./api/revisions'); | ||||
| const recentChangesApiRoute = require('./api/recent_changes.js'); | ||||
| const optionsApiRoute = require('./api/options.js'); | ||||
| const passwordApiRoute = require('./api/password'); | ||||
| const syncApiRoute = require('./api/sync.js'); | ||||
| const loginApiRoute = require('./api/login.js'); | ||||
| const recentNotesRoute = require('./api/recent_notes.js'); | ||||
| const appInfoRoute = require('./api/app_info.js'); | ||||
| const appInfoRoute = require('./api/app_info'); | ||||
| const exportRoute = require('./api/export.js'); | ||||
| const importRoute = require('./api/import.js'); | ||||
| const setupApiRoute = require('./api/setup.js'); | ||||
| @ -56,20 +56,20 @@ const keysRoute = require('./api/keys.js'); | ||||
| const backendLogRoute = require('./api/backend_log.js'); | ||||
| const statsRoute = require('./api/stats.js'); | ||||
| const fontsRoute = require('./api/fonts.js'); | ||||
| const etapiTokensApiRoutes = require('./api/etapi_tokens.js'); | ||||
| const etapiTokensApiRoutes = require('./api/etapi_tokens'); | ||||
| const relationMapApiRoute = require('./api/relation-map'); | ||||
| const otherRoute = require('./api/other.js'); | ||||
| const shareRoutes = require('../share/routes.js'); | ||||
| 
 | ||||
| const etapiAuthRoutes = require('../etapi/auth.js'); | ||||
| const etapiAppInfoRoutes = require('../etapi/app_info.js'); | ||||
| const etapiAppInfoRoutes = require('../etapi/app_info'); | ||||
| const etapiAttachmentRoutes = require('../etapi/attachments.js'); | ||||
| const etapiAttributeRoutes = require('../etapi/attributes.js'); | ||||
| const etapiBranchRoutes = require('../etapi/branches.js'); | ||||
| const etapiNoteRoutes = require('../etapi/notes.js'); | ||||
| const etapiSpecialNoteRoutes = require('../etapi/special_notes.js'); | ||||
| const etapiSpecRoute = require('../etapi/spec.js'); | ||||
| const etapiBackupRoute = require('../etapi/backup.js'); | ||||
| const etapiBackupRoute = require('../etapi/backup'); | ||||
| 
 | ||||
| const csrfMiddleware = csurf({ | ||||
|     cookie: true, | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const sqlInit = require('../services/sql_init.js'); | ||||
| const sqlInit = require('../services/sql_init'); | ||||
| const setupService = require('../services/setup.js'); | ||||
| const utils = require('../services/utils'); | ||||
| const assetPath = require('../services/asset_path.js'); | ||||
| const appPath = require('../services/app_path.js'); | ||||
| const assetPath = require('../services/asset_path'); | ||||
| const appPath = require('../services/app_path'); | ||||
| 
 | ||||
| function setupPage(req, res) { | ||||
|     if (sqlInit.isDbInitialized()) { | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| const BUILTIN_ATTRIBUTES = require('./builtin_attributes.js'); | ||||
| const fs = require("fs-extra"); | ||||
| const dataDir = require('./data_dir'); | ||||
| const dateUtils = require('./date_utils'); | ||||
| const Database = require("better-sqlite3"); | ||||
| const sql = require('./sql'); | ||||
| const path = require("path"); | ||||
| import BUILTIN_ATTRIBUTES = require('./builtin_attributes'); | ||||
| import fs = require("fs-extra"); | ||||
| import dataDir = require('./data_dir'); | ||||
| import dateUtils = require('./date_utils'); | ||||
| import Database = require("better-sqlite3"); | ||||
| import sql = require('./sql'); | ||||
| import path = require("path"); | ||||
| 
 | ||||
| function getFullAnonymizationScript() { | ||||
|     // we want to delete all non-builtin attributes because they can contain sensitive names and values
 | ||||
| @ -48,7 +48,7 @@ function getLightAnonymizationScript() { | ||||
|               AND value != '';`;
 | ||||
| } | ||||
| 
 | ||||
| async function createAnonymizedCopy(type) { | ||||
| async function createAnonymizedCopy(type: "full" | "light") { | ||||
|     if (!['full', 'light'].includes(type)) { | ||||
|         throw new Error(`Unrecognized anonymization type '${type}'`); | ||||
|     } | ||||
| @ -1,12 +1,12 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const path = require('path'); | ||||
| const {ELECTRON_APP_ROOT_DIR} = require('./resource_dir'); | ||||
| const log = require('./log'); | ||||
| const os = require('os'); | ||||
| const fs = require('fs'); | ||||
| const config = require('./config'); | ||||
| const utils = require('./utils'); | ||||
| import path = require('path'); | ||||
| import resourceDir = require('./resource_dir'); | ||||
| import log = require('./log'); | ||||
| import os = require('os'); | ||||
| import fs = require('fs'); | ||||
| import config = require('./config'); | ||||
| import utils = require('./utils'); | ||||
| 
 | ||||
| const template = `[Desktop Entry]
 | ||||
| Type=Application | ||||
| @ -28,7 +28,7 @@ function installLocalAppIcon() { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (!fs.existsSync(path.resolve(ELECTRON_APP_ROOT_DIR, "trilium-portable.sh"))) { | ||||
|     if (!fs.existsSync(path.resolve(resourceDir.ELECTRON_APP_ROOT_DIR, "trilium-portable.sh"))) { | ||||
|         // simple heuristic to detect ".tar.xz" linux build (i.e., not flatpak, not debian)
 | ||||
|         // only in such case it's necessary to create an icon
 | ||||
|         return; | ||||
| @ -56,16 +56,16 @@ function installLocalAppIcon() { | ||||
| 
 | ||||
| function getDesktopFileContent() { | ||||
|     return template | ||||
|         .replace("#APP_ROOT_DIR#", escapePath(ELECTRON_APP_ROOT_DIR)) | ||||
|         .replace("#APP_ROOT_DIR#", escapePath(resourceDir.ELECTRON_APP_ROOT_DIR)) | ||||
|         .replace("#EXE_PATH#", escapePath(getExePath())); | ||||
| } | ||||
| 
 | ||||
| function escapePath(path) { | ||||
| function escapePath(path: string) { | ||||
|     return path.replace(/ /g, "\\ "); | ||||
| } | ||||
| 
 | ||||
| function getExePath() { | ||||
|      return path.resolve(ELECTRON_APP_ROOT_DIR, 'trilium'); | ||||
|      return path.resolve(resourceDir.ELECTRON_APP_ROOT_DIR, 'trilium'); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| @ -1,21 +1,21 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const build = require('./build.js'); | ||||
| const packageJson = require('../../package.json'); | ||||
| const {TRILIUM_DATA_DIR} = require('./data_dir'); | ||||
| import build = require('./build'); | ||||
| import packageJson = require('../../package.json'); | ||||
| import dataDir = require('./data_dir'); | ||||
| 
 | ||||
| const APP_DB_VERSION = 228; | ||||
| const SYNC_VERSION = 32; | ||||
| const CLIPPER_PROTOCOL_VERSION = "1.0"; | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     appVersion: packageJson.version, | ||||
|     dbVersion: APP_DB_VERSION, | ||||
|     nodeVersion: process.version, | ||||
|     syncVersion: SYNC_VERSION, | ||||
|     buildDate: build.buildDate, | ||||
|     buildRevision: build.buildRevision, | ||||
|     dataDirectory: TRILIUM_DATA_DIR, | ||||
|     dataDirectory: dataDir.TRILIUM_DATA_DIR, | ||||
|     clipperProtocolVersion: CLIPPER_PROTOCOL_VERSION, | ||||
|     utcDateTime: new Date().toISOString() // for timezone inference
 | ||||
| }; | ||||
| @ -1,6 +0,0 @@ | ||||
| const assetPath = require('./asset_path.js'); | ||||
| const env = require('./env'); | ||||
| 
 | ||||
| module.exports = env.isDev() | ||||
|     ? assetPath + "/app" | ||||
|     : assetPath + "/app-dist"; | ||||
							
								
								
									
										6
									
								
								src/services/app_path.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/services/app_path.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| import assetPath = require('./asset_path'); | ||||
| import env = require('./env'); | ||||
| 
 | ||||
| export = env.isDev() | ||||
|     ? assetPath + "/app" | ||||
|     : assetPath + "/app-dist"; | ||||
| @ -1,3 +0,0 @@ | ||||
| const packageJson = require('../../package.json'); | ||||
| 
 | ||||
| module.exports = `assets/v${packageJson.version}`; | ||||
							
								
								
									
										3
									
								
								src/services/asset_path.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/services/asset_path.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| import packageJson = require('../../package.json'); | ||||
| 
 | ||||
| export = `assets/v${packageJson.version}`; | ||||
| @ -1,6 +1,8 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| function formatAttrForSearch(attr, searchWithValue) { | ||||
| import BAttribute = require("../becca/entities/battribute"); | ||||
| 
 | ||||
| function formatAttrForSearch(attr: BAttribute, searchWithValue: string) { | ||||
|     let searchStr = ''; | ||||
| 
 | ||||
|     if (attr.type === 'label') { | ||||
| @ -27,7 +29,7 @@ function formatAttrForSearch(attr, searchWithValue) { | ||||
|     return searchStr; | ||||
| } | ||||
| 
 | ||||
| function formatValue(val) { | ||||
| function formatValue(val: string) { | ||||
|     if (!/[^\w]/.test(val)) { | ||||
|         return val; | ||||
|     } | ||||
| @ -45,6 +47,6 @@ function formatValue(val) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     formatAttrForSearch | ||||
| }; | ||||
| @ -4,8 +4,8 @@ const searchService = require('./search/services/search.js'); | ||||
| const sql = require('./sql'); | ||||
| const becca = require('../becca/becca'); | ||||
| const BAttribute = require('../becca/entities/battribute'); | ||||
| const {formatAttrForSearch} = require('./attribute_formatter.js'); | ||||
| const BUILTIN_ATTRIBUTES = require('./builtin_attributes.js'); | ||||
| const {formatAttrForSearch} = require('./attribute_formatter'); | ||||
| const BUILTIN_ATTRIBUTES = require('./builtin_attributes'); | ||||
| 
 | ||||
| const ATTRIBUTE_TYPES = ['label', 'relation']; | ||||
| 
 | ||||
|  | ||||
| @ -1,16 +1,27 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const etapiTokenService = require('./etapi_tokens.js'); | ||||
| const log = require('./log'); | ||||
| const sqlInit = require('./sql_init.js'); | ||||
| const utils = require('./utils'); | ||||
| const passwordEncryptionService = require('./encryption/password_encryption'); | ||||
| const config = require('./config'); | ||||
| const passwordService = require('./encryption/password'); | ||||
| import etapiTokenService = require('./etapi_tokens'); | ||||
| import log = require('./log'); | ||||
| import sqlInit = require('./sql_init'); | ||||
| import utils = require('./utils'); | ||||
| import passwordEncryptionService = require('./encryption/password_encryption'); | ||||
| import config = require('./config'); | ||||
| import passwordService = require('./encryption/password'); | ||||
| import type { NextFunction, Request, Response } from 'express'; | ||||
| 
 | ||||
| const noAuthentication = config.General && config.General.noAuthentication === true; | ||||
| 
 | ||||
| function checkAuth(req, res, next) { | ||||
| interface AppRequest extends Request { | ||||
|     headers: { | ||||
|         authorization?: string; | ||||
|         "trilium-cred"?: string; | ||||
|     } | ||||
|     session: { | ||||
|         loggedIn: boolean;         | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function checkAuth(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (!sqlInit.isDbInitialized()) { | ||||
|         res.redirect("setup"); | ||||
|     } | ||||
| @ -24,7 +35,7 @@ function checkAuth(req, res, next) { | ||||
| 
 | ||||
| // for electron things which need network stuff
 | ||||
| //  currently, we're doing that for file upload because handling form data seems to be difficult
 | ||||
| function checkApiAuthOrElectron(req, res, next) { | ||||
| function checkApiAuthOrElectron(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (!req.session.loggedIn && !utils.isElectron() && !noAuthentication) { | ||||
|         reject(req, res, "Logged in session not found"); | ||||
|     } | ||||
| @ -33,7 +44,7 @@ function checkApiAuthOrElectron(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function checkApiAuth(req, res, next) { | ||||
| function checkApiAuth(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (!req.session.loggedIn && !noAuthentication) { | ||||
|         reject(req, res, "Logged in session not found"); | ||||
|     } | ||||
| @ -42,7 +53,7 @@ function checkApiAuth(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function checkAppInitialized(req, res, next) { | ||||
| function checkAppInitialized(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (!sqlInit.isDbInitialized()) { | ||||
|         res.redirect("setup"); | ||||
|     } | ||||
| @ -51,7 +62,7 @@ function checkAppInitialized(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function checkPasswordSet(req, res, next) { | ||||
| function checkPasswordSet(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (!utils.isElectron() && !passwordService.isPasswordSet()) { | ||||
|         res.redirect("set-password"); | ||||
|     } else { | ||||
| @ -59,7 +70,7 @@ function checkPasswordSet(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function checkPasswordNotSet(req, res, next) { | ||||
| function checkPasswordNotSet(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (!utils.isElectron() && passwordService.isPasswordSet()) { | ||||
|         res.redirect("login"); | ||||
|     } else { | ||||
| @ -67,7 +78,7 @@ function checkPasswordNotSet(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function checkAppNotInitialized(req, res, next) { | ||||
| function checkAppNotInitialized(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (sqlInit.isDbInitialized()) { | ||||
|         reject(req, res, "App already initialized."); | ||||
|     } | ||||
| @ -76,7 +87,7 @@ function checkAppNotInitialized(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function checkEtapiToken(req, res, next) { | ||||
| function checkEtapiToken(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (etapiTokenService.isValidAuthHeader(req.headers.authorization)) { | ||||
|         next(); | ||||
|     } | ||||
| @ -85,7 +96,7 @@ function checkEtapiToken(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function reject(req, res, message) { | ||||
| function reject(req: AppRequest, res: Response, message: string) { | ||||
|     log.info(`${req.method} ${req.path} rejected with 401 ${message}`); | ||||
| 
 | ||||
|     res.setHeader("Content-Type", "text/plain") | ||||
| @ -93,7 +104,7 @@ function reject(req, res, message) { | ||||
|         .send(message); | ||||
| } | ||||
| 
 | ||||
| function checkCredentials(req, res, next) { | ||||
| function checkCredentials(req: AppRequest, res: Response, next: NextFunction) { | ||||
|     if (!sqlInit.isDbInitialized()) { | ||||
|         res.setHeader("Content-Type", "text/plain") | ||||
|             .status(400) | ||||
| @ -109,7 +120,7 @@ function checkCredentials(req, res, next) { | ||||
|     } | ||||
| 
 | ||||
|     const header = req.headers['trilium-cred'] || ''; | ||||
|     const auth = new Buffer.from(header, 'base64').toString(); | ||||
|     const auth = Buffer.from(header, 'base64').toString(); | ||||
|     const colonIndex = auth.indexOf(':'); | ||||
|     const password = colonIndex === -1 ? "" : auth.substr(colonIndex + 1); | ||||
|     // username is ignored
 | ||||
| @ -124,7 +135,7 @@ function checkCredentials(req, res, next) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     checkAuth, | ||||
|     checkApiAuth, | ||||
|     checkAppInitialized, | ||||
| @ -1,5 +1,5 @@ | ||||
| const log = require('./log'); | ||||
| const noteService = require('./notes.js'); | ||||
| const noteService = require('./notes'); | ||||
| const sql = require('./sql'); | ||||
| const utils = require('./utils'); | ||||
| const attributeService = require('./attributes.js'); | ||||
| @ -10,7 +10,7 @@ const axios = require('axios'); | ||||
| const dayjs = require('dayjs'); | ||||
| const xml2js = require('xml2js'); | ||||
| const cloningService = require('./cloning.js'); | ||||
| const appInfo = require('./app_info.js'); | ||||
| const appInfo = require('./app_info'); | ||||
| const searchService = require('./search/services/search.js'); | ||||
| const SearchContext = require('./search/search_context.js'); | ||||
| const becca = require('../becca/becca'); | ||||
| @ -20,7 +20,7 @@ const specialNotesService = require('./special_notes.js'); | ||||
| const branchService = require('./branches.js'); | ||||
| const exportService = require('./export/zip.js'); | ||||
| const syncMutex = require('./sync_mutex'); | ||||
| const backupService = require('./backup.js'); | ||||
| const backupService = require('./backup'); | ||||
| const optionsService = require('./options'); | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,14 +1,16 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const dateUtils = require('./date_utils'); | ||||
| const optionService = require('./options'); | ||||
| const fs = require('fs-extra'); | ||||
| const dataDir = require('./data_dir'); | ||||
| const log = require('./log'); | ||||
| const syncMutexService = require('./sync_mutex'); | ||||
| const cls = require('./cls'); | ||||
| const sql = require('./sql'); | ||||
| const path = require('path'); | ||||
| import dateUtils = require('./date_utils'); | ||||
| import optionService = require('./options'); | ||||
| import fs = require('fs-extra'); | ||||
| import dataDir = require('./data_dir'); | ||||
| import log = require('./log'); | ||||
| import syncMutexService = require('./sync_mutex'); | ||||
| import cls = require('./cls'); | ||||
| import sql = require('./sql'); | ||||
| import path = require('path'); | ||||
| 
 | ||||
| type BackupType = ("daily" | "weekly" | "monthly"); | ||||
| 
 | ||||
| function getExistingBackups() { | ||||
|     if (!fs.existsSync(dataDir.BACKUP_DIR)) { | ||||
| @ -35,13 +37,13 @@ function regularBackup() { | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function isBackupEnabled(backupType) { | ||||
| function isBackupEnabled(backupType: BackupType) { | ||||
|     const optionName = `${backupType}BackupEnabled`; | ||||
| 
 | ||||
|     return optionService.getOptionBool(optionName); | ||||
| } | ||||
| 
 | ||||
| function periodBackup(optionName, backupType, periodInSeconds) { | ||||
| function periodBackup(optionName: string, backupType: BackupType, periodInSeconds: number) { | ||||
|     if (!isBackupEnabled(backupType)) { | ||||
|         return; | ||||
|     } | ||||
| @ -56,7 +58,7 @@ function periodBackup(optionName, backupType, periodInSeconds) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async function backupNow(name) { | ||||
| async function backupNow(name: string) { | ||||
|     // we don't want to back up DB in the middle of sync with potentially inconsistent DB state
 | ||||
|     return await syncMutexService.doExclusively(async () => { | ||||
|         const backupFile = `${dataDir.BACKUP_DIR}/backup-${name}.db`; | ||||
| @ -73,7 +75,7 @@ if (!fs.existsSync(dataDir.BACKUP_DIR)) { | ||||
|     fs.mkdirSync(dataDir.BACKUP_DIR, 0o700); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     getExistingBackups, | ||||
|     backupNow, | ||||
|     regularBackup | ||||
| @ -1 +0,0 @@ | ||||
| module.exports = { buildDate:"2024-03-28T07:11:39+01:00", buildRevision: "399458b52f250b22be22d980a78de0b3390d7521" }; | ||||
							
								
								
									
										1
									
								
								src/services/build.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/services/build.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| export = { buildDate:"2024-03-28T07:11:39+01:00", buildRevision: "399458b52f250b22be22d980a78de0b3390d7521" }; | ||||
| @ -1,4 +1,4 @@ | ||||
| module.exports = [ | ||||
| export = [ | ||||
|     // label names
 | ||||
|     { type: 'label', name: 'inbox' }, | ||||
|     { type: 'label', name: 'disableVersioning' }, | ||||
| @ -1,10 +1,10 @@ | ||||
| const log = require('./log'); | ||||
| const revisionService = require('./revisions.js'); | ||||
| const revisionService = require('./revisions'); | ||||
| const becca = require('../becca/becca'); | ||||
| const cloningService = require('./cloning.js'); | ||||
| const branchService = require('./branches.js'); | ||||
| const utils = require('./utils'); | ||||
| const eraseService = require("./erase.js"); | ||||
| const eraseService = require("./erase"); | ||||
| 
 | ||||
| const ACTION_HANDLERS = { | ||||
|     addLabel: (action, note) => { | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const sql = require('./sql'); | ||||
| const sqlInit = require('./sql_init.js'); | ||||
| const sqlInit = require('./sql_init'); | ||||
| const log = require('./log'); | ||||
| const ws = require('./ws'); | ||||
| const syncMutexService = require('./sync_mutex'); | ||||
| @ -9,12 +9,12 @@ const cls = require('./cls'); | ||||
| const entityChangesService = require('./entity_changes'); | ||||
| const optionsService = require('./options'); | ||||
| const BBranch = require('../becca/entities/bbranch'); | ||||
| const revisionService = require('./revisions.js'); | ||||
| const revisionService = require('./revisions'); | ||||
| const becca = require('../becca/becca'); | ||||
| const utils = require('../services/utils'); | ||||
| const eraseService = require('../services/erase.js'); | ||||
| const eraseService = require('../services/erase'); | ||||
| const {sanitizeAttributeName} = require('./sanitize_attribute_name'); | ||||
| const noteTypes = require('../services/note_types.js').getNoteTypeNames(); | ||||
| const noteTypes = require('../services/note_types').getNoteTypeNames(); | ||||
| 
 | ||||
| class ConsistencyChecks { | ||||
|     /** | ||||
| @ -766,7 +766,7 @@ class ConsistencyChecks { | ||||
|         } | ||||
| 
 | ||||
|         if (this.reloadNeeded) { | ||||
|             require('../becca/becca_loader.js').reload("consistency checks need becca reload"); | ||||
|             require('../becca/becca_loader').reload("consistency checks need becca reload"); | ||||
|         } | ||||
| 
 | ||||
|         return !this.unrecoveredConsistencyErrors; | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| const sql = require('./sql'); | ||||
| const utils = require('./utils'); | ||||
| const log = require('./log'); | ||||
| const eraseService = require('./erase.js'); | ||||
| const eraseService = require('./erase'); | ||||
| 
 | ||||
| function getEntityHashes() { | ||||
|     // blob erasure is not synced, we should check before each sync if there's some blob to erase
 | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const noteService = require('./notes.js'); | ||||
| const noteService = require('./notes'); | ||||
| const attributeService = require('./attributes.js'); | ||||
| const dateUtils = require('./date_utils'); | ||||
| const sql = require('./sql'); | ||||
|  | ||||
| @ -65,7 +65,7 @@ function getDateTimeForFile() { | ||||
|     return new Date().toISOString().substr(0, 19).replace(/:/g, ''); | ||||
| } | ||||
| 
 | ||||
| function validateLocalDateTime(str: string) { | ||||
| function validateLocalDateTime(str: string | null | undefined) { | ||||
|     if (!str) { | ||||
|         return; | ||||
|     } | ||||
| @ -80,7 +80,7 @@ function validateLocalDateTime(str: string) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function validateUtcDateTime(str: string) { | ||||
| function validateUtcDateTime(str: string | undefined) { | ||||
|     if (!str) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| @ -78,7 +78,7 @@ function resetPassword() { | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     isPasswordSet, | ||||
|     changePassword, | ||||
|     setPassword, | ||||
|  | ||||
| @ -45,7 +45,7 @@ function putEntityChange(origEntityChange: EntityChange) { | ||||
|     cls.putEntityChange(ec); | ||||
| } | ||||
| 
 | ||||
| function putNoteReorderingEntityChange(parentNoteId: string, componentId: string) { | ||||
| function putNoteReorderingEntityChange(parentNoteId: string, componentId?: string) { | ||||
|     putEntityChange({ | ||||
|         entityName: "note_reordering", | ||||
|         entityId: parentNoteId, | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| const sql = require("./sql"); | ||||
| const revisionService = require("./revisions.js"); | ||||
| const log = require("./log"); | ||||
| const entityChangesService = require("./entity_changes"); | ||||
| const optionService = require("./options"); | ||||
| const dateUtils = require("./date_utils"); | ||||
| const sqlInit = require("./sql_init.js"); | ||||
| const cls = require("./cls"); | ||||
| import sql = require("./sql"); | ||||
| import revisionService = require("./revisions"); | ||||
| import log = require("./log"); | ||||
| import entityChangesService = require("./entity_changes"); | ||||
| import optionService = require("./options"); | ||||
| import dateUtils = require("./date_utils"); | ||||
| import sqlInit = require("./sql_init"); | ||||
| import cls = require("./cls"); | ||||
| import { EntityChange } from "./entity_changes_interface"; | ||||
| 
 | ||||
| function eraseNotes(noteIdsToErase) { | ||||
| function eraseNotes(noteIdsToErase: string[]) { | ||||
|     if (noteIdsToErase.length === 0) { | ||||
|         return; | ||||
|     } | ||||
| @ -16,17 +17,17 @@ function eraseNotes(noteIdsToErase) { | ||||
|     setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'notes' AND entityId IN (???)`, noteIdsToErase)); | ||||
| 
 | ||||
|     // we also need to erase all "dependent" entities of the erased notes
 | ||||
|     const branchIdsToErase = sql.getManyRows(`SELECT branchId FROM branches WHERE noteId IN (???)`, noteIdsToErase) | ||||
|     const branchIdsToErase = sql.getManyRows<{ branchId: string }>(`SELECT branchId FROM branches WHERE noteId IN (???)`, noteIdsToErase) | ||||
|         .map(row => row.branchId); | ||||
| 
 | ||||
|     eraseBranches(branchIdsToErase); | ||||
| 
 | ||||
|     const attributeIdsToErase = sql.getManyRows(`SELECT attributeId FROM attributes WHERE noteId IN (???)`, noteIdsToErase) | ||||
|     const attributeIdsToErase = sql.getManyRows<{ attributeId: string }>(`SELECT attributeId FROM attributes WHERE noteId IN (???)`, noteIdsToErase) | ||||
|         .map(row => row.attributeId); | ||||
| 
 | ||||
|     eraseAttributes(attributeIdsToErase); | ||||
| 
 | ||||
|     const revisionIdsToErase = sql.getManyRows(`SELECT revisionId FROM revisions WHERE noteId IN (???)`, noteIdsToErase) | ||||
|     const revisionIdsToErase = sql.getManyRows<{ revisionId: string }>(`SELECT revisionId FROM revisions WHERE noteId IN (???)`, noteIdsToErase) | ||||
|         .map(row => row.revisionId); | ||||
| 
 | ||||
|     eraseRevisions(revisionIdsToErase); | ||||
| @ -34,7 +35,7 @@ function eraseNotes(noteIdsToErase) { | ||||
|     log.info(`Erased notes: ${JSON.stringify(noteIdsToErase)}`); | ||||
| } | ||||
| 
 | ||||
| function setEntityChangesAsErased(entityChanges) { | ||||
| function setEntityChangesAsErased(entityChanges: EntityChange[]) { | ||||
|     for (const ec of entityChanges) { | ||||
|         ec.isErased = true; | ||||
|         // we're not changing hash here, not sure if good or not
 | ||||
| @ -45,7 +46,7 @@ function setEntityChangesAsErased(entityChanges) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function eraseBranches(branchIdsToErase) { | ||||
| function eraseBranches(branchIdsToErase: string[]) { | ||||
|     if (branchIdsToErase.length === 0) { | ||||
|         return; | ||||
|     } | ||||
| @ -57,7 +58,7 @@ function eraseBranches(branchIdsToErase) { | ||||
|     log.info(`Erased branches: ${JSON.stringify(branchIdsToErase)}`); | ||||
| } | ||||
| 
 | ||||
| function eraseAttributes(attributeIdsToErase) { | ||||
| function eraseAttributes(attributeIdsToErase: string[]) { | ||||
|     if (attributeIdsToErase.length === 0) { | ||||
|         return; | ||||
|     } | ||||
| @ -69,7 +70,7 @@ function eraseAttributes(attributeIdsToErase) { | ||||
|     log.info(`Erased attributes: ${JSON.stringify(attributeIdsToErase)}`); | ||||
| } | ||||
| 
 | ||||
| function eraseAttachments(attachmentIdsToErase) { | ||||
| function eraseAttachments(attachmentIdsToErase: string[]) { | ||||
|     if (attachmentIdsToErase.length === 0) { | ||||
|         return; | ||||
|     } | ||||
| @ -81,7 +82,7 @@ function eraseAttachments(attachmentIdsToErase) { | ||||
|     log.info(`Erased attachments: ${JSON.stringify(attachmentIdsToErase)}`); | ||||
| } | ||||
| 
 | ||||
| function eraseRevisions(revisionIdsToErase) { | ||||
| function eraseRevisions(revisionIdsToErase: string[]) { | ||||
|     if (revisionIdsToErase.length === 0) { | ||||
|         return; | ||||
|     } | ||||
| @ -116,7 +117,7 @@ function eraseUnusedBlobs() { | ||||
|     log.info(`Erased unused blobs: ${JSON.stringify(unusedBlobIds)}`); | ||||
| } | ||||
| 
 | ||||
| function eraseDeletedEntities(eraseEntitiesAfterTimeInSeconds = null) { | ||||
| function eraseDeletedEntities(eraseEntitiesAfterTimeInSeconds: number | null = null) { | ||||
|     // this is important also so that the erased entity changes are sent to the connected clients
 | ||||
|     sql.transactional(() => { | ||||
|         if (eraseEntitiesAfterTimeInSeconds === null) { | ||||
| @ -125,41 +126,33 @@ function eraseDeletedEntities(eraseEntitiesAfterTimeInSeconds = null) { | ||||
| 
 | ||||
|         const cutoffDate = new Date(Date.now() - eraseEntitiesAfterTimeInSeconds * 1000); | ||||
| 
 | ||||
|         const noteIdsToErase = sql.getColumn("SELECT noteId FROM notes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
| 
 | ||||
|         const noteIdsToErase = sql.getColumn<string>("SELECT noteId FROM notes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
|         eraseNotes(noteIdsToErase); | ||||
| 
 | ||||
|         const branchIdsToErase = sql.getColumn("SELECT branchId FROM branches WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
| 
 | ||||
|         const branchIdsToErase = sql.getColumn<string>("SELECT branchId FROM branches WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
|         eraseBranches(branchIdsToErase); | ||||
| 
 | ||||
|         const attributeIdsToErase = sql.getColumn("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
| 
 | ||||
|         const attributeIdsToErase = sql.getColumn<string>("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
|         eraseAttributes(attributeIdsToErase); | ||||
| 
 | ||||
|         const attachmentIdsToErase = sql.getColumn("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
| 
 | ||||
|         const attachmentIdsToErase = sql.getColumn<string>("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]); | ||||
|         eraseAttachments(attachmentIdsToErase); | ||||
| 
 | ||||
|         eraseUnusedBlobs(); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function eraseNotesWithDeleteId(deleteId) { | ||||
|     const noteIdsToErase = sql.getColumn("SELECT noteId FROM notes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
| 
 | ||||
| function eraseNotesWithDeleteId(deleteId: string) { | ||||
|     const noteIdsToErase = sql.getColumn<string>("SELECT noteId FROM notes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
|     eraseNotes(noteIdsToErase); | ||||
| 
 | ||||
|     const branchIdsToErase = sql.getColumn("SELECT branchId FROM branches WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
| 
 | ||||
|     const branchIdsToErase = sql.getColumn<string>("SELECT branchId FROM branches WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
|     eraseBranches(branchIdsToErase); | ||||
| 
 | ||||
|     const attributeIdsToErase = sql.getColumn("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
| 
 | ||||
|     const attributeIdsToErase = sql.getColumn<string>("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
|     eraseAttributes(attributeIdsToErase); | ||||
| 
 | ||||
|     const attachmentIdsToErase = sql.getColumn("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
| 
 | ||||
|     const attachmentIdsToErase = sql.getColumn<string>("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND deleteId = ?", [deleteId]); | ||||
|     eraseAttachments(attachmentIdsToErase); | ||||
| 
 | ||||
|     eraseUnusedBlobs(); | ||||
| @ -173,13 +166,13 @@ function eraseUnusedAttachmentsNow() { | ||||
|     eraseScheduledAttachments(0); | ||||
| } | ||||
| 
 | ||||
| function eraseScheduledAttachments(eraseUnusedAttachmentsAfterSeconds = null) { | ||||
| function eraseScheduledAttachments(eraseUnusedAttachmentsAfterSeconds: number | null = null) { | ||||
|     if (eraseUnusedAttachmentsAfterSeconds === null) { | ||||
|         eraseUnusedAttachmentsAfterSeconds = optionService.getOptionInt('eraseUnusedAttachmentsAfterSeconds'); | ||||
|     } | ||||
| 
 | ||||
|     const cutOffDate = dateUtils.utcDateTimeStr(new Date(Date.now() - (eraseUnusedAttachmentsAfterSeconds * 1000))); | ||||
|     const attachmentIdsToErase = sql.getColumn('SELECT attachmentId FROM attachments WHERE utcDateScheduledForErasureSince < ?', [cutOffDate]); | ||||
|     const attachmentIdsToErase = sql.getColumn<string>('SELECT attachmentId FROM attachments WHERE utcDateScheduledForErasureSince < ?', [cutOffDate]); | ||||
| 
 | ||||
|     eraseAttachments(attachmentIdsToErase); | ||||
| } | ||||
| @ -193,7 +186,7 @@ sqlInit.dbReady.then(() => { | ||||
|     setInterval(cls.wrap(() => eraseScheduledAttachments()), 3600 * 1000); | ||||
| }); | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     eraseDeletedNotesNow, | ||||
|     eraseUnusedAttachmentsNow, | ||||
|     eraseNotesWithDeleteId, | ||||
| @ -1,17 +1,17 @@ | ||||
| const becca = require('../becca/becca'); | ||||
| const utils = require('./utils'); | ||||
| const BEtapiToken = require('../becca/entities/betapi_token'); | ||||
| const crypto = require("crypto"); | ||||
| import becca = require('../becca/becca'); | ||||
| import utils = require('./utils'); | ||||
| import BEtapiToken = require('../becca/entities/betapi_token'); | ||||
| import crypto = require("crypto"); | ||||
| 
 | ||||
| function getTokens() { | ||||
|     return becca.getEtapiTokens(); | ||||
| } | ||||
| 
 | ||||
| function getTokenHash(token) { | ||||
| function getTokenHash(token: crypto.BinaryLike) { | ||||
|     return crypto.createHash('sha256').update(token).digest('base64'); | ||||
| } | ||||
| 
 | ||||
| function createToken(tokenName) { | ||||
| function createToken(tokenName: string) { | ||||
|     const token = utils.randomSecureToken(32); | ||||
|     const tokenHash = getTokenHash(token); | ||||
| 
 | ||||
| @ -25,7 +25,7 @@ function createToken(tokenName) { | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| function parseAuthToken(auth) { | ||||
| function parseAuthToken(auth: string | undefined) { | ||||
|     if (!auth) { | ||||
|         return null; | ||||
|     } | ||||
| @ -64,7 +64,7 @@ function parseAuthToken(auth) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function isValidAuthHeader(auth) { | ||||
| function isValidAuthHeader(auth: string | undefined) { | ||||
|     const parsed = parseAuthToken(auth); | ||||
| 
 | ||||
|     if (!parsed) { | ||||
| @ -93,7 +93,7 @@ function isValidAuthHeader(auth) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function renameToken(etapiTokenId, newName) { | ||||
| function renameToken(etapiTokenId: string, newName: string) { | ||||
|     const etapiToken = becca.getEtapiToken(etapiTokenId); | ||||
| 
 | ||||
|     if (!etapiToken) { | ||||
| @ -104,7 +104,7 @@ function renameToken(etapiTokenId, newName) { | ||||
|     etapiToken.save(); | ||||
| } | ||||
| 
 | ||||
| function deleteToken(etapiTokenId) { | ||||
| function deleteToken(etapiTokenId: string) { | ||||
|     const etapiToken = becca.getEtapiToken(etapiTokenId); | ||||
| 
 | ||||
|     if (!etapiToken) { | ||||
| @ -114,7 +114,7 @@ function deleteToken(etapiTokenId) { | ||||
|     etapiToken.markAsDeletedSimple(); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     getTokens, | ||||
|     createToken, | ||||
|     renameToken, | ||||
| @ -16,9 +16,9 @@ const archiver = require('archiver'); | ||||
| const log = require('../log'); | ||||
| const TaskContext = require('../task_context'); | ||||
| const ValidationError = require('../../errors/validation_error'); | ||||
| const NoteMeta = require('../meta/note_meta.js'); | ||||
| const AttachmentMeta = require('../meta/attachment_meta.js'); | ||||
| const AttributeMeta = require('../meta/attribute_meta.js'); | ||||
| const NoteMeta = require('../meta/note_meta'); | ||||
| const AttachmentMeta = require('../meta/attachment_meta'); | ||||
| const AttributeMeta = require('../meta/attribute_meta'); | ||||
| 
 | ||||
| /** | ||||
|  * @param {TaskContext} taskContext | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| const eventService = require('./events'); | ||||
| const scriptService = require('./script.js'); | ||||
| const treeService = require('./tree.js'); | ||||
| const noteService = require('./notes.js'); | ||||
| const noteService = require('./notes'); | ||||
| const becca = require('../becca/becca'); | ||||
| const BAttribute = require('../becca/entities/battribute'); | ||||
| const hiddenSubtreeService = require('./hidden_subtree.js'); | ||||
| const hiddenSubtreeService = require('./hidden_subtree'); | ||||
| const oneTimeTimer = require('./one_time_timer.js'); | ||||
| 
 | ||||
| function runAttachedRelations(note, relationName, originEntity) { | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| const becca = require('../becca/becca'); | ||||
| const noteService = require('./notes.js'); | ||||
| const BAttribute = require('../becca/entities/battribute'); | ||||
| const log = require('./log'); | ||||
| const migrationService = require('./migration.js'); | ||||
| import BAttribute = require("../becca/entities/battribute"); | ||||
| import { AttributeType, NoteType } from "../becca/entities/rows"; | ||||
| 
 | ||||
| import becca = require('../becca/becca'); | ||||
| import noteService = require('./notes'); | ||||
| import log = require('./log'); | ||||
| import migrationService = require('./migration'); | ||||
| 
 | ||||
| const LBTPL_ROOT = "_lbTplRoot"; | ||||
| const LBTPL_BASE = "_lbTplBase"; | ||||
| @ -13,13 +15,36 @@ const LBTPL_BUILTIN_WIDGET = "_lbTplBuiltinWidget"; | ||||
| const LBTPL_SPACER = "_lbTplSpacer"; | ||||
| const LBTPL_CUSTOM_WIDGET = "_lbTplCustomWidget"; | ||||
| 
 | ||||
| interface Attribute { | ||||
|     type: AttributeType; | ||||
|     name: string; | ||||
|     isInheritable?: boolean; | ||||
|     value?: string | ||||
| } | ||||
| 
 | ||||
| interface Item { | ||||
|     notePosition?: number; | ||||
|     id: string; | ||||
|     title: string; | ||||
|     type: NoteType; | ||||
|     icon?: string; | ||||
|     attributes?: Attribute[]; | ||||
|     children?: Item[]; | ||||
|     isExpanded?: boolean; | ||||
|     baseSize?: string; | ||||
|     growthFactor?: string; | ||||
|     targetNoteId?: "_backendLog" | "_globalNoteMap"; | ||||
|     builtinWidget?: "bookmarks" | "spacer" | "backInHistoryButton" | "forwardInHistoryButton" | "syncStatus" | "protectedSession" | "todayInJournal" | "calendar"; | ||||
|     command?: "jumpToNote" | "searchNotes" | "createNoteIntoInbox" | "showRecentChanges"; | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Hidden subtree is generated as a "predictable structure" which means that it avoids generating random IDs to always | ||||
|  * produce the same structure. This is needed because it is run on multiple instances in the sync cluster which might produce | ||||
|  * duplicate subtrees. This way, all instances will generate the same structure with the same IDs. | ||||
|  */ | ||||
| 
 | ||||
| const HIDDEN_SUBTREE_DEFINITION = { | ||||
| const HIDDEN_SUBTREE_DEFINITION: Item = { | ||||
|     id: '_hidden', | ||||
|     title: 'Hidden Notes', | ||||
|     type: 'doc', | ||||
| @ -244,7 +269,7 @@ function checkHiddenSubtree(force = false) { | ||||
|     checkHiddenSubtreeRecursively('root', HIDDEN_SUBTREE_DEFINITION); | ||||
| } | ||||
| 
 | ||||
| function checkHiddenSubtreeRecursively(parentNoteId, item) { | ||||
| function checkHiddenSubtreeRecursively(parentNoteId: string, item: Item) { | ||||
|     if (!item.id || !item.type || !item.title) { | ||||
|         throw new Error(`Item does not contain mandatory properties: ${JSON.stringify(item)}`); | ||||
|     } | ||||
| @ -337,7 +362,7 @@ function checkHiddenSubtreeRecursively(parentNoteId, item) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     checkHiddenSubtree, | ||||
|     LBTPL_ROOT, | ||||
|     LBTPL_BASE, | ||||
| @ -1,18 +1,18 @@ | ||||
| const sanitizeHtml = require('sanitize-html'); | ||||
| const sanitizeUrl = require('@braintree/sanitize-url').sanitizeUrl; | ||||
| import sanitizeHtml = require('sanitize-html'); | ||||
| import sanitizeUrl = require('@braintree/sanitize-url'); | ||||
| 
 | ||||
| // intended mainly as protection against XSS via import
 | ||||
| // secondarily, it (partly) protects against "CSS takeover"
 | ||||
| // sanitize also note titles, label values etc. - there are so many usages which make it difficult
 | ||||
| // to guarantee all of them are properly handled
 | ||||
| function sanitize(dirtyHtml) { | ||||
| function sanitize(dirtyHtml: string) { | ||||
|     if (!dirtyHtml) { | ||||
|         return dirtyHtml; | ||||
|     } | ||||
| 
 | ||||
|     // avoid H1 per https://github.com/zadam/trilium/issues/1552
 | ||||
|     // demote H1, and if that conflicts with existing H2, demote that, etc
 | ||||
|     const transformTags = {}; | ||||
|     const transformTags: Record<string, string> = {}; | ||||
|     const lowercasedHtml = dirtyHtml.toLowerCase(); | ||||
|     for (let i = 1; i < 6; ++i) { | ||||
|         if (lowercasedHtml.includes(`<h${i}`)) { | ||||
| @ -47,9 +47,9 @@ function sanitize(dirtyHtml) { | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     sanitize, | ||||
|     sanitizeUrl: url => { | ||||
|         return sanitizeUrl(url).trim(); | ||||
|     sanitizeUrl: (url: string) => { | ||||
|         return sanitizeUrl.sanitizeUrl(url).trim(); | ||||
|     } | ||||
| }; | ||||
| @ -3,7 +3,7 @@ | ||||
| const becca = require('../becca/becca'); | ||||
| const log = require('./log'); | ||||
| const protectedSessionService = require('./protected_session'); | ||||
| const noteService = require('./notes.js'); | ||||
| const noteService = require('./notes'); | ||||
| const optionService = require('./options'); | ||||
| const sql = require('./sql'); | ||||
| const jimp = require('jimp'); | ||||
| @ -11,7 +11,7 @@ const imageType = require('image-type'); | ||||
| const sanitizeFilename = require('sanitize-filename'); | ||||
| const isSvg = require('is-svg'); | ||||
| const isAnimated = require('is-animated'); | ||||
| const htmlSanitizer = require('./html_sanitizer.js'); | ||||
| const htmlSanitizer = require('./html_sanitizer'); | ||||
| 
 | ||||
| async function processImage(uploadBuffer, originalName, shrinkImageSwitch) { | ||||
|     const compressImages = optionService.getOptionBool("compressImages"); | ||||
| @ -154,7 +154,7 @@ function saveImageToAttachment(noteId, uploadBuffer, originalName, shrinkImageSw | ||||
|     setTimeout(() => { | ||||
|         sql.transactional(() => { | ||||
|             const note = becca.getNoteOrThrow(noteId); | ||||
|             const noteService = require('../services/notes.js'); | ||||
|             const noteService = require('../services/notes'); | ||||
|             noteService.asyncPostProcessContent(note, note.getContent()); // to mark an unused attachment for deletion
 | ||||
|         }); | ||||
|     }, 5000); | ||||
|  | ||||
| @ -4,10 +4,10 @@ const {Throttle} = require('stream-throttle'); | ||||
| const log = require('../log'); | ||||
| const utils = require('../utils'); | ||||
| const sql = require('../sql'); | ||||
| const noteService = require('../notes.js'); | ||||
| const noteService = require('../notes'); | ||||
| const imageService = require('../image.js'); | ||||
| const protectedSessionService = require('../protected_session'); | ||||
| const htmlSanitizer = require('../html_sanitizer.js'); | ||||
| const htmlSanitizer = require('../html_sanitizer'); | ||||
| const {sanitizeAttributeName} = require('../sanitize_attribute_name'); | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const marked = require("marked"); | ||||
| const htmlSanitizer = require('../html_sanitizer.js'); | ||||
| const htmlSanitizer = require('../html_sanitizer'); | ||||
| const importUtils = require('./utils'); | ||||
| 
 | ||||
| function renderToHtml(content, title) { | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const parseString = require('xml2js').parseString; | ||||
| const protectedSessionService = require('../protected_session'); | ||||
| const htmlSanitizer = require('../html_sanitizer.js'); | ||||
| const htmlSanitizer = require('../html_sanitizer'); | ||||
| 
 | ||||
| /** | ||||
|  * @param {TaskContext} taskContext | ||||
|  | ||||
| @ -1,13 +1,13 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const imageService = require('../../services/image.js'); | ||||
| const protectedSessionService = require('../protected_session'); | ||||
| const markdownService = require('./markdown.js'); | ||||
| const mimeService = require('./mime.js'); | ||||
| const utils = require('../../services/utils'); | ||||
| const importUtils = require('./utils'); | ||||
| const htmlSanitizer = require('../html_sanitizer.js'); | ||||
| const htmlSanitizer = require('../html_sanitizer'); | ||||
| 
 | ||||
| function importSingleFile(taskContext, file, parentNote) { | ||||
|     const mime = mimeService.getMime(file.originalname) || file.mimetype; | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| const BAttribute = require('../../becca/entities/battribute'); | ||||
| const utils = require('../../services/utils'); | ||||
| const log = require('../../services/log'); | ||||
| const noteService = require('../../services/notes.js'); | ||||
| const noteService = require('../../services/notes'); | ||||
| const attributeService = require('../../services/attributes.js'); | ||||
| const BBranch = require('../../becca/entities/bbranch'); | ||||
| const path = require('path'); | ||||
| @ -11,7 +11,7 @@ const protectedSessionService = require('../protected_session'); | ||||
| const mimeService = require('./mime.js'); | ||||
| const treeService = require('../tree.js'); | ||||
| const yauzl = require("yauzl"); | ||||
| const htmlSanitizer = require('../html_sanitizer.js'); | ||||
| const htmlSanitizer = require('../html_sanitizer'); | ||||
| const becca = require('../../becca/becca'); | ||||
| const BAttachment = require('../../becca/entities/battachment'); | ||||
| const markdownService = require('./markdown.js'); | ||||
|  | ||||
| @ -1,12 +1,21 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| const optionService = require('./options'); | ||||
| const log = require('./log'); | ||||
| const utils = require('./utils'); | ||||
| import optionService = require('./options'); | ||||
| import log = require('./log'); | ||||
| import utils = require('./utils'); | ||||
| 
 | ||||
| const isMac = process.platform === "darwin"; | ||||
| const isElectron = utils.isElectron(); | ||||
| 
 | ||||
| interface KeyboardShortcut { | ||||
|     separator?: string; | ||||
|     actionName?: string; | ||||
|     description?: string; | ||||
|     defaultShortcuts?: string[]; | ||||
|     effectiveShortcuts?: string[]; | ||||
|     scope?: string; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Scope here means on which element the keyboard shortcuts are attached - this means that for the shortcut to work, | ||||
|  * the focus has to be inside the element. | ||||
| @ -16,7 +25,7 @@ const isElectron = utils.isElectron(); | ||||
|  * e.g. CTRL-C in note tree does something a bit different from CTRL-C in the text editor. | ||||
|  */ | ||||
| 
 | ||||
| const DEFAULT_KEYBOARD_ACTIONS = [ | ||||
| const DEFAULT_KEYBOARD_ACTIONS: KeyboardShortcut[] = [ | ||||
|     { | ||||
|         separator: "Note navigation" | ||||
|     }, | ||||
| @ -606,15 +615,15 @@ for (const action of DEFAULT_KEYBOARD_ACTIONS) { | ||||
| } | ||||
| 
 | ||||
| function getKeyboardActions() { | ||||
|     const actions = JSON.parse(JSON.stringify(DEFAULT_KEYBOARD_ACTIONS)); | ||||
|     const actions: KeyboardShortcut[] = JSON.parse(JSON.stringify(DEFAULT_KEYBOARD_ACTIONS)); | ||||
| 
 | ||||
|     for (const action of actions) { | ||||
|         action.effectiveShortcuts = action.effectiveShortcuts ? action.defaultShortcuts.slice() : []; | ||||
|         action.effectiveShortcuts = action.defaultShortcuts ? action.defaultShortcuts.slice() : []; | ||||
|     } | ||||
| 
 | ||||
|     for (const option of optionService.getOptions()) { | ||||
|         if (option.name.startsWith('keyboardShortcuts')) { | ||||
|             let actionName = option.name.substr(17); | ||||
|             let actionName = option.name.substring(17); | ||||
|             actionName = actionName.charAt(0).toLowerCase() + actionName.slice(1); | ||||
| 
 | ||||
|             const action = actions.find(ea => ea.actionName === actionName); | ||||
| @ -636,7 +645,7 @@ function getKeyboardActions() { | ||||
|     return actions; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     DEFAULT_KEYBOARD_ACTIONS, | ||||
|     getKeyboardActions | ||||
| }; | ||||
| @ -1,16 +0,0 @@ | ||||
| class AttachmentMeta { | ||||
|     /** @type {string} */ | ||||
|     attachmentId; | ||||
|     /** @type {string} */ | ||||
|     title; | ||||
|     /** @type {string} */ | ||||
|     role; | ||||
|     /** @type {string} */ | ||||
|     mime; | ||||
|     /** @type {int} */ | ||||
|     position; | ||||
|     /** @type {string} */ | ||||
|     dataFileName; | ||||
| } | ||||
| 
 | ||||
| module.exports = AttachmentMeta; | ||||
							
								
								
									
										10
									
								
								src/services/meta/attachment_meta.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/services/meta/attachment_meta.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| interface AttachmentMeta { | ||||
|     attachmentId: string; | ||||
|     title: string; | ||||
|     role: string; | ||||
|     mime: string; | ||||
|     position: number; | ||||
|     dataFileName: string; | ||||
| } | ||||
| 
 | ||||
| export = AttachmentMeta; | ||||
| @ -1,14 +0,0 @@ | ||||
| class AttributeMeta { | ||||
|     /** @type {string} */ | ||||
|     type; | ||||
|     /** @type {string} */ | ||||
|     name; | ||||
|     /** @type {string} */ | ||||
|     value; | ||||
|     /** @type {boolean} */ | ||||
|     isInheritable; | ||||
|     /** @type {int} */ | ||||
|     position; | ||||
| } | ||||
| 
 | ||||
| module.exports = AttributeMeta; | ||||
							
								
								
									
										9
									
								
								src/services/meta/attribute_meta.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/services/meta/attribute_meta.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| interface AttributeMeta { | ||||
|     type: string; | ||||
|     name: string; | ||||
|     value: string; | ||||
|     isInheritable: boolean; | ||||
|     position: number; | ||||
| } | ||||
| 
 | ||||
| export = AttributeMeta; | ||||
| @ -1,36 +0,0 @@ | ||||
| class NoteMeta { | ||||
|     /** @type {string} */ | ||||
|     noteId; | ||||
|     /** @type {string} */ | ||||
|     notePath; | ||||
|     /** @type {boolean} */ | ||||
|     isClone; | ||||
|     /** @type {string} */ | ||||
|     title; | ||||
|     /** @type {int} */ | ||||
|     notePosition; | ||||
|     /** @type {string} */ | ||||
|     prefix; | ||||
|     /** @type {boolean} */ | ||||
|     isExpanded; | ||||
|     /** @type {string} */ | ||||
|     type; | ||||
|     /** @type {string} */ | ||||
|     mime; | ||||
|     /** @type {string} - 'html' or 'markdown', applicable to text notes only */ | ||||
|     format; | ||||
|     /** @type {string} */ | ||||
|     dataFileName; | ||||
|     /** @type {string} */ | ||||
|     dirFileName; | ||||
|     /** @type {boolean} - this file should not be imported (e.g., HTML navigation) */ | ||||
|     noImport = false; | ||||
|     /** @type {AttributeMeta[]} */ | ||||
|     attributes; | ||||
|     /** @type {AttachmentMeta[]} */ | ||||
|     attachments; | ||||
|     /** @type {NoteMeta[]|undefined} */ | ||||
|     children; | ||||
| } | ||||
| 
 | ||||
| module.exports = NoteMeta; | ||||
							
								
								
									
										24
									
								
								src/services/meta/note_meta.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/services/meta/note_meta.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| import AttributeMeta = require("./attribute_meta"); | ||||
| 
 | ||||
| interface NoteMeta { | ||||
|     noteId: string; | ||||
|     notePath: string; | ||||
|     isClone: boolean; | ||||
|     title: string; | ||||
|     notePosition: number; | ||||
|     prefix: string; | ||||
|     isExpanded: boolean; | ||||
|     type: string; | ||||
|     mime: string; | ||||
|     /** 'html' or 'markdown', applicable to text notes only */ | ||||
|     format: "html" | "markdown"; | ||||
|     dataFileName: string; | ||||
|     dirFileName: string; | ||||
|     /** this file should not be imported (e.g., HTML navigation) */ | ||||
|     noImport: boolean; | ||||
|     attributes: AttributeMeta[]; | ||||
|     attachments: AttributeMeta[]; | ||||
|     children?: NoteMeta[]; | ||||
| } | ||||
| 
 | ||||
| export = NoteMeta; | ||||
| @ -1,11 +1,18 @@ | ||||
| const backupService = require('./backup.js'); | ||||
| const sql = require('./sql'); | ||||
| const fs = require('fs-extra'); | ||||
| const log = require('./log'); | ||||
| const utils = require('./utils'); | ||||
| const resourceDir = require('./resource_dir'); | ||||
| const appInfo = require('./app_info.js'); | ||||
| const cls = require('./cls'); | ||||
| import backupService = require('./backup'); | ||||
| import sql = require('./sql'); | ||||
| import fs = require('fs-extra'); | ||||
| import log = require('./log'); | ||||
| import utils = require('./utils'); | ||||
| import resourceDir = require('./resource_dir'); | ||||
| import appInfo = require('./app_info'); | ||||
| import cls = require('./cls'); | ||||
| 
 | ||||
| interface MigrationInfo { | ||||
|     dbVersion: number; | ||||
|     name: string; | ||||
|     file: string; | ||||
|     type: string; | ||||
| } | ||||
| 
 | ||||
| async function migrate() { | ||||
|     const currentDbVersion = getDbVersion(); | ||||
| @ -25,7 +32,12 @@ async function migrate() { | ||||
|             : 'before-migration' | ||||
|     ); | ||||
| 
 | ||||
|     const migrations = fs.readdirSync(resourceDir.MIGRATIONS_DIR).map(file => { | ||||
|     const migrationFiles = fs.readdirSync(resourceDir.MIGRATIONS_DIR); | ||||
|     if (migrationFiles == null) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const migrations = migrationFiles.map(file => { | ||||
|         const match = file.match(/^([0-9]{4})__([a-zA-Z0-9_ ]+)\.(sql|js)$/); | ||||
|         if (!match) { | ||||
|             return null; | ||||
| @ -45,7 +57,7 @@ async function migrate() { | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     }).filter(el => !!el); | ||||
|     }).filter((el): el is MigrationInfo => !!el); | ||||
| 
 | ||||
|     migrations.sort((a, b) => a.dbVersion - b.dbVersion); | ||||
| 
 | ||||
| @ -67,7 +79,7 @@ async function migrate() { | ||||
|                              WHERE name = ?`, [mig.dbVersion.toString(), "dbVersion"]);
 | ||||
| 
 | ||||
|                 log.info(`Migration to version ${mig.dbVersion} has been successful.`); | ||||
|             } catch (e) { | ||||
|             } catch (e: any) { | ||||
|                 log.error(`error during migration to version ${mig.dbVersion}: ${e.stack}`); | ||||
|                 log.error("migration failed, crashing hard"); // this is not very user-friendly :-/
 | ||||
| 
 | ||||
| @ -84,7 +96,7 @@ async function migrate() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function executeMigration(mig) { | ||||
| function executeMigration(mig: MigrationInfo) { | ||||
|     if (mig.type === 'sql') { | ||||
|         const migrationSql = fs.readFileSync(`${resourceDir.MIGRATIONS_DIR}/${mig.file}`).toString('utf8'); | ||||
| 
 | ||||
| @ -131,7 +143,7 @@ async function migrateIfNecessary() { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     migrateIfNecessary, | ||||
|     isDbUpToDate | ||||
| }; | ||||
| @ -16,7 +16,7 @@ const noteTypes = [ | ||||
|     { type: 'contentWidget', defaultMime: '' } | ||||
| ]; | ||||
| 
 | ||||
| function getDefaultMimeForNoteType(typeName) { | ||||
| function getDefaultMimeForNoteType(typeName: string) { | ||||
|     const typeRec = noteTypes.find(nt => nt.type === typeName); | ||||
| 
 | ||||
|     if (!typeRec) { | ||||
| @ -26,7 +26,7 @@ function getDefaultMimeForNoteType(typeName) { | ||||
|     return typeRec.defaultMime; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
| export = { | ||||
|     getNoteTypeNames: () => noteTypes.map(nt => nt.type), | ||||
|     getDefaultMimeForNoteType | ||||
| }; | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran