mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	backend scripts should not be async because of transaction management
This commit is contained in:
		
							
								
								
									
										50
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										50
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -11,9 +11,9 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "@babel/parser": { |     "@babel/parser": { | ||||||
|       "version": "7.11.5", |       "version": "7.14.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", |       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.2.tgz", | ||||||
|       "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==", |       "integrity": "sha512-IoVDIHpsgE/fu7eXBeRWt8zLbDrSvD7H1gpomOkPpBoEN8KCruCqSDdqo8dddwQQrui30KSvQBaMUOJiuFu6QQ==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "@babel/runtime": { |     "@babel/runtime": { | ||||||
| @@ -1953,12 +1953,12 @@ | |||||||
|       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" |       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" | ||||||
|     }, |     }, | ||||||
|     "catharsis": { |     "catharsis": { | ||||||
|       "version": "0.8.11", |       "version": "0.9.0", | ||||||
|       "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", |       "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", | ||||||
|       "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", |       "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "lodash": "^4.17.14" |         "lodash": "^4.17.15" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "chalk": { |     "chalk": { | ||||||
| @@ -2957,9 +2957,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "electron": { |     "electron": { | ||||||
|       "version": "13.0.0-beta.24", |       "version": "13.0.0-beta.26", | ||||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-13.0.0-beta.24.tgz", |       "resolved": "https://registry.npmjs.org/electron/-/electron-13.0.0-beta.26.tgz", | ||||||
|       "integrity": "sha512-2zgmhrjdkWrKsBIepF1XkRCn4ODFxd4lgB58BLv3E66yiQJC0ugOnHoqeZcsskQ7bBMGGQwGAzB5nwOJ/83BOg==", |       "integrity": "sha512-glDAQjSzV26JvmB9pbdd1dLkjqUvBv9X0B8FrRvIK0BAhEmMzzZ3gKD6VPsxg2omDYMI35oThQ+92D4RxRcb+g==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@electron/get": "^1.0.1", |         "@electron/get": "^1.0.1", | ||||||
| @@ -2968,9 +2968,9 @@ | |||||||
|       }, |       }, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@types/node": { |         "@types/node": { | ||||||
|           "version": "14.14.44", |           "version": "14.14.45", | ||||||
|           "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.44.tgz", |           "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.45.tgz", | ||||||
|           "integrity": "sha512-+gaugz6Oce6ZInfI/tK4Pq5wIIkJMEJUu92RB3Eu93mtj4wjjjz9EB5mLp5s1pSsLXdC/CPut/xF20ZzAQJbTA==", |           "integrity": "sha512-DssMqTV9UnnoxDWu959sDLZzfvqCF0qDNRjaWeYSui9xkFe61kKo4l1TWNTQONpuXEm+gLMRvdlzvNHBamzmEw==", | ||||||
|           "dev": true |           "dev": true | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -5250,25 +5250,25 @@ | |||||||
|       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" |       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" | ||||||
|     }, |     }, | ||||||
|     "jsdoc": { |     "jsdoc": { | ||||||
|       "version": "3.6.6", |       "version": "3.6.7", | ||||||
|       "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.6.tgz", |       "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", | ||||||
|       "integrity": "sha512-znR99e1BHeyEkSvgDDpX0sTiTu+8aQyDl9DawrkOGZTTW8hv0deIFXx87114zJ7gRaDZKVQD/4tr1ifmJp9xhQ==", |       "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@babel/parser": "^7.9.4", |         "@babel/parser": "^7.9.4", | ||||||
|         "bluebird": "^3.7.2", |         "bluebird": "^3.7.2", | ||||||
|         "catharsis": "^0.8.11", |         "catharsis": "^0.9.0", | ||||||
|         "escape-string-regexp": "^2.0.0", |         "escape-string-regexp": "^2.0.0", | ||||||
|         "js2xmlparser": "^4.0.1", |         "js2xmlparser": "^4.0.1", | ||||||
|         "klaw": "^3.0.0", |         "klaw": "^3.0.0", | ||||||
|         "markdown-it": "^10.0.0", |         "markdown-it": "^10.0.0", | ||||||
|         "markdown-it-anchor": "^5.2.7", |         "markdown-it-anchor": "^5.2.7", | ||||||
|         "marked": "^0.8.2", |         "marked": "^2.0.3", | ||||||
|         "mkdirp": "^1.0.4", |         "mkdirp": "^1.0.4", | ||||||
|         "requizzle": "^0.2.3", |         "requizzle": "^0.2.3", | ||||||
|         "strip-json-comments": "^3.1.0", |         "strip-json-comments": "^3.1.0", | ||||||
|         "taffydb": "2.6.2", |         "taffydb": "2.6.2", | ||||||
|         "underscore": "~1.10.2" |         "underscore": "~1.13.1" | ||||||
|       }, |       }, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "bluebird": { |         "bluebird": { | ||||||
| @@ -5716,9 +5716,9 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "marked": { |     "marked": { | ||||||
|       "version": "0.8.2", |       "version": "2.0.3", | ||||||
|       "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz", |       "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.3.tgz", | ||||||
|       "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==", |       "integrity": "sha512-5otztIIcJfPc2qGTN8cVtOJEjNJZ0jwa46INMagrYfk0EvqtRuEHLsEe0LrFS0/q+ZRKT0+kXK7P2T1AN5lWRA==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "matcher": { |     "matcher": { | ||||||
| @@ -8026,9 +8026,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "underscore": { |     "underscore": { | ||||||
|       "version": "1.10.2", |       "version": "1.13.1", | ||||||
|       "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", |       "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", | ||||||
|       "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==", |       "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "unescape": { |     "unescape": { | ||||||
|   | |||||||
| @@ -80,13 +80,13 @@ | |||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "cross-env": "7.0.3", |     "cross-env": "7.0.3", | ||||||
|     "electron": "13.0.0-beta.24", |     "electron": "13.0.0-beta.26", | ||||||
|     "electron-builder": "22.11.3", |     "electron-builder": "22.11.3", | ||||||
|     "electron-packager": "15.2.0", |     "electron-packager": "15.2.0", | ||||||
|     "electron-rebuild": "2.3.5", |     "electron-rebuild": "2.3.5", | ||||||
|     "esm": "3.2.25", |     "esm": "3.2.25", | ||||||
|     "jasmine": "3.7.0", |     "jasmine": "3.7.0", | ||||||
|     "jsdoc": "3.6.6", |     "jsdoc": "3.6.7", | ||||||
|     "lorem-ipsum": "2.0.3", |     "lorem-ipsum": "2.0.3", | ||||||
|     "rcedit": "3.0.0", |     "rcedit": "3.0.0", | ||||||
|     "webpack": "5.37.0", |     "webpack": "5.37.0", | ||||||
|   | |||||||
| @@ -5,11 +5,11 @@ const attributeService = require('../../services/attributes'); | |||||||
| const becca = require('../../services/becca/becca'); | const becca = require('../../services/becca/becca'); | ||||||
| const syncService = require('../../services/sync'); | const syncService = require('../../services/sync'); | ||||||
|  |  | ||||||
| async function exec(req) { | function exec(req) { | ||||||
|     try { |     try { | ||||||
|         const {body} = req; |         const {body} = req; | ||||||
|  |  | ||||||
|         const result = await scriptService.executeScript( |         const result = scriptService.executeScript( | ||||||
|             body.script, |             body.script, | ||||||
|             body.params, |             body.params, | ||||||
|             body.startNoteId, |             body.startNoteId, | ||||||
| @@ -29,10 +29,10 @@ async function exec(req) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| async function run(req) { | function run(req) { | ||||||
|     const note = becca.getNote(req.params.noteId); |     const note = becca.getNote(req.params.noteId); | ||||||
|  |  | ||||||
|     const result = await scriptService.executeNote(note, { originEntity: note }); |     const result = scriptService.executeNote(note, { originEntity: note }); | ||||||
|  |  | ||||||
|     return { executionResult: result }; |     return { executionResult: result }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -167,7 +167,7 @@ async function searchAndExecute(req) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| async function searchFromRelation(note, relationName) { | function searchFromRelation(note, relationName) { | ||||||
|     const scriptNote = note.getRelationTarget(relationName); |     const scriptNote = note.getRelationTarget(relationName); | ||||||
|  |  | ||||||
|     if (!scriptNote) { |     if (!scriptNote) { | ||||||
| @@ -188,7 +188,7 @@ async function searchFromRelation(note, relationName) { | |||||||
|         return []; |         return []; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const result = await scriptService.executeNote(scriptNote, { originEntity: note }); |     const result = scriptService.executeNote(scriptNote, { originEntity: note }); | ||||||
|  |  | ||||||
|     if (!Array.isArray(result)) { |     if (!Array.isArray(result)) { | ||||||
|         log.info(`Result from ${scriptNote.noteId} is not an array.`); |         log.info(`Result from ${scriptNote.noteId} is not an array.`); | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ const cls = require('../services/cls'); | |||||||
| const sql = require("../services/sql"); | const sql = require("../services/sql"); | ||||||
| const becca = require("../services/becca/becca"); | const becca = require("../services/becca/becca"); | ||||||
|  |  | ||||||
| async function handleRequest(req, res) { | function handleRequest(req, res) { | ||||||
|     // express puts content after first slash into 0 index element |     // express puts content after first slash into 0 index element | ||||||
|  |  | ||||||
|     const path = req.params.path + req.params[0]; |     const path = req.params.path + req.params[0]; | ||||||
| @@ -72,7 +72,7 @@ async function handleRequest(req, res) { | |||||||
| function register(router) { | function register(router) { | ||||||
|     // explicitly no CSRF middleware since it's meant to allow integration from external services |     // explicitly no CSRF middleware since it's meant to allow integration from external services | ||||||
|  |  | ||||||
|     router.all('/custom/:path*', async (req, res, next) => { |     router.all('/custom/:path*', (req, res, next) => { | ||||||
|         cls.namespace.bindEmitter(req); |         cls.namespace.bindEmitter(req); | ||||||
|         cls.namespace.bindEmitter(res); |         cls.namespace.bindEmitter(res); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,10 +1,9 @@ | |||||||
| const ScriptContext = require('./script_context'); | const ScriptContext = require('./script_context'); | ||||||
| const repository = require('./repository'); |  | ||||||
| const cls = require('./cls'); | const cls = require('./cls'); | ||||||
| const log = require('./log'); | const log = require('./log'); | ||||||
| const becca = require("./becca/becca"); | const becca = require("./becca/becca"); | ||||||
|  |  | ||||||
| async function executeNote(note, apiParams) { | function executeNote(note, apiParams) { | ||||||
|     if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) { |     if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) { | ||||||
|         log.info(`Cannot execute note ${note.noteId} "${note.title}", note must be of type "Code: JS frontend"`); |         log.info(`Cannot execute note ${note.noteId} "${note.title}", note must be of type "Code: JS frontend"`); | ||||||
|  |  | ||||||
| @@ -16,16 +15,16 @@ async function executeNote(note, apiParams) { | |||||||
|     return executeBundle(bundle, apiParams); |     return executeBundle(bundle, apiParams); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function executeNoteNoException(note, apiParams) { | function executeNoteNoException(note, apiParams) { | ||||||
|     try { |     try { | ||||||
|         await executeNote(note, apiParams); |         executeNote(note, apiParams); | ||||||
|     } |     } | ||||||
|     catch (e) { |     catch (e) { | ||||||
|         // just swallow, exception is logged already in executeNote |         // just swallow, exception is logged already in executeNote | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| async function executeBundle(bundle, apiParams = {}) { | function executeBundle(bundle, apiParams = {}) { | ||||||
|     if (!apiParams.startNote) { |     if (!apiParams.startNote) { | ||||||
|         // this is the default case, the only exception is when we want to preserve frontend startNote |         // this is the default case, the only exception is when we want to preserve frontend startNote | ||||||
|         apiParams.startNote = bundle.note; |         apiParams.startNote = bundle.note; | ||||||
| @@ -34,12 +33,12 @@ async function executeBundle(bundle, apiParams = {}) { | |||||||
|     cls.set('sourceId', 'script'); |     cls.set('sourceId', 'script'); | ||||||
|  |  | ||||||
|     // last \r\n is necessary if script contains line comment on its last line |     // last \r\n is necessary if script contains line comment on its last line | ||||||
|     const script = "async function() {\r\n" + bundle.script + "\r\n}"; |     const script = "function() {\r\n" + bundle.script + "\r\n}"; | ||||||
|  |  | ||||||
|     const ctx = new ScriptContext(bundle.allNotes, apiParams); |     const ctx = new ScriptContext(bundle.allNotes, apiParams); | ||||||
|  |  | ||||||
|     try { |     try { | ||||||
|         return await execute(ctx, script); |         return execute(ctx, script); | ||||||
|     } |     } | ||||||
|     catch (e) { |     catch (e) { | ||||||
|         log.error(`Execution of script "${bundle.note.title}" (${bundle.note.noteId}) failed with error: ${e.message}`); |         log.error(`Execution of script "${bundle.note.title}" (${bundle.note.noteId}) failed with error: ${e.message}`); | ||||||
| @@ -49,10 +48,13 @@ async function executeBundle(bundle, apiParams = {}) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  |  * THIS METHOD CANT BE ASYNC, OTHERWISE TRANSACTION WRAPPER WON'T BE EFFECTIVE AND WE WILL BE LOSING THE | ||||||
|  |  * ENTITY CHANGES IN CLS. | ||||||
|  |  * | ||||||
|  * This method preserves frontend startNode - that's why we start execution from currentNote and override |  * This method preserves frontend startNode - that's why we start execution from currentNote and override | ||||||
|  * bundle's startNote. |  * bundle's startNote. | ||||||
|  */ |  */ | ||||||
| async function executeScript(script, params, startNoteId, currentNoteId, originEntityName, originEntityId) { | function executeScript(script, params, startNoteId, currentNoteId, originEntityName, originEntityId) { | ||||||
|     const startNote = becca.getNote(startNoteId); |     const startNote = becca.getNote(startNoteId); | ||||||
|     const currentNote = becca.getNote(currentNoteId); |     const currentNote = becca.getNote(currentNoteId); | ||||||
|     const originEntity = becca.getEntityFromName(originEntityName, originEntityId); |     const originEntity = becca.getEntityFromName(originEntityName, originEntityId); | ||||||
| @@ -63,11 +65,11 @@ async function executeScript(script, params, startNoteId, currentNoteId, originE | |||||||
|  |  | ||||||
|     const bundle = getScriptBundle(currentNote, true, null, [], backendOverrideContent); |     const bundle = getScriptBundle(currentNote, true, null, [], backendOverrideContent); | ||||||
|  |  | ||||||
|     return await executeBundle(bundle, { startNote, originEntity }); |     return executeBundle(bundle, { startNote, originEntity }); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function execute(ctx, script) { | function execute(ctx, script) { | ||||||
|     return await (function() { return eval(`const apiContext = this;\r\n(${script}\r\n)()`); }.call(ctx)); |     return function() { return eval(`const apiContext = this;\r\n(${script}\r\n)()`); }.call(ctx); | ||||||
| } | } | ||||||
|  |  | ||||||
| function getParams(params) { | function getParams(params) { | ||||||
| @@ -153,10 +155,13 @@ function getScriptBundle(note, root = true, scriptEnv = null, includedNoteIds = | |||||||
|  |  | ||||||
|     const moduleNoteIds = modules.map(mod => mod.noteId); |     const moduleNoteIds = modules.map(mod => mod.noteId); | ||||||
|  |  | ||||||
|  |     // only frontend scripts are async. Backend cannot be async because of transaction management. | ||||||
|  |     const isFrontend = scriptEnv === 'frontend'; | ||||||
|  |  | ||||||
|     if (note.isJavaScript()) { |     if (note.isJavaScript()) { | ||||||
|         bundle.script += ` |         bundle.script += ` | ||||||
| apiContext.modules['${note.noteId}'] = {}; | apiContext.modules['${note.noteId}'] = {}; | ||||||
| ${root ? 'return ' : ''}await ((async function(exports, module, require, api` + (modules.length > 0 ? ', ' : '') + | ${root ? 'return ' : ''}${isFrontend ? 'await' : ''} ((${isFrontend ? 'async' : ''} function(exports, module, require, api` + (modules.length > 0 ? ', ' : '') + | ||||||
|             modules.map(child => sanitizeVariableName(child.title)).join(', ') + `) { |             modules.map(child => sanitizeVariableName(child.title)).join(', ') + `) { | ||||||
| try { | try { | ||||||
| ${backendOverrideContent || note.getContent()}; | ${backendOverrideContent || note.getContent()}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user