diff --git a/.idea/misc.xml b/.idea/misc.xml index 1062d3362..bc4ec316b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -6,9 +6,4 @@ - - - \ No newline at end of file diff --git a/db/migrations/0195__remove_recent_notes_from_entity_changes.sql b/db/migrations/0195__remove_recent_notes_from_entity_changes.sql new file mode 100644 index 000000000..834db7fe9 --- /dev/null +++ b/db/migrations/0195__remove_recent_notes_from_entity_changes.sql @@ -0,0 +1,2 @@ +-- removing potential remnants of recent notes in entity changes, see https://github.com/zadam/trilium/issues/2842 +DELETE FROM entity_changes WHERE entityName = 'recent_notes'; diff --git a/docs/backend_api/global.html b/docs/backend_api/global.html index 18ade2d89..43d1da8e1 100644 --- a/docs/backend_api/global.html +++ b/docs/backend_api/global.html @@ -237,7 +237,7 @@ - text, code, file, image, search, book, relation-map - MANDATORY + text, code, file, image, search, book, relation-map, canvas - MANDATORY diff --git a/docs/backend_api/services_backend_script_api.js.html b/docs/backend_api/services_backend_script_api.js.html index e9641e25b..3c73eee9f 100644 --- a/docs/backend_api/services_backend_script_api.js.html +++ b/docs/backend_api/services_backend_script_api.js.html @@ -238,7 +238,7 @@ function BackendScriptApi(currentNote, apiParams) { * @property {string} parentNoteId - MANDATORY * @property {string} title - MANDATORY * @property {string|buffer} content - MANDATORY - * @property {string} type - text, code, file, image, search, book, relation-map - MANDATORY + * @property {string} type - text, code, file, image, search, book, relation-map, canvas - MANDATORY * @property {string} mime - value is derived from default mimes for type * @property {boolean} isProtected - default is false * @property {boolean} isExpanded - default is false diff --git a/docs/frontend_api/FrontendScriptApi.html b/docs/frontend_api/FrontendScriptApi.html index 6000fae0f..9ac977093 100644 --- a/docs/frontend_api/FrontendScriptApi.html +++ b/docs/frontend_api/FrontendScriptApi.html @@ -1665,143 +1665,6 @@ - - - - - - -

addTextToActiveContextEditor(text)

- - - - - - -
- Adds given text to the editor cursor -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
text - - -string - - - - this must be clear text, HTML is not supported.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - @@ -1897,8 +1760,6 @@ -
Deprecated:
- @@ -1911,7 +1772,7 @@
Source:
@@ -2067,7 +1928,7 @@
Source:
@@ -2427,7 +2288,7 @@
Source:
@@ -2618,7 +2479,114 @@ -

getActiveContextCodeEditor() → {Promise.<CodeMirror>}

+

getActiveNoteDetailWidget() → {Promise.<NoteDetailWidget>}

+ + + + + + +
+ Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the +implementation of actual widget type. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<NoteDetailWidget> + + +
+
+ + + + + + + + + + + + + +

getActiveTabCodeEditor() → {Promise.<CodeMirror>}

@@ -2670,7 +2638,7 @@
Source:
@@ -2728,435 +2696,6 @@ -

getActiveContextNote() → {NoteShort}

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- active note (loaded into right pane) -
- - - -
-
- Type -
-
- -NoteShort - - -
-
- - - - - - - - - - - - - -

getActiveContextNotePath() → {Promise.<(string|null)>}

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- returns note path of active note or null if there isn't active note -
- - - -
-
- Type -
-
- -Promise.<(string|null)> - - -
-
- - - - - - - - - - - - - -

getActiveContextTextEditor() → {Promise.<CKEditor>}

- - - - - - -
- See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- instance of CKEditor -
- - - -
-
- Type -
-
- -Promise.<CKEditor> - - -
-
- - - - - - - - - - - - - -

getActiveNoteDetailWidget() → {Promise.<NoteDetailWidget>}

- - - - - - -
- Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the -implementation of actual widget type. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -Promise.<NoteDetailWidget> - - -
-
- - - - - - - - - - - - -

getActiveTabNote() → {NoteShort}

@@ -3193,8 +2732,6 @@ implementation of actual widget type. -
Deprecated:
- @@ -3207,7 +2744,7 @@ implementation of actual widget type.
Source:
@@ -3301,8 +2838,6 @@ implementation of actual widget type. -
Deprecated:
- @@ -3315,7 +2850,7 @@ implementation of actual widget type.
Source:
@@ -3373,7 +2908,7 @@ implementation of actual widget type. -

getActiveTabTextEditor(callbackopt)

+

getActiveTabTextEditor(callbackopt) → {Promise.<CKEditor>}

@@ -3440,7 +2975,7 @@ implementation of actual widget type. - callback receiving "textEditor" instance + deprecated (use returned promise): callback receiving "textEditor" instance @@ -3469,8 +3004,6 @@ implementation of actual widget type. -
Deprecated:
- @@ -3483,7 +3016,7 @@ implementation of actual widget type.
Source:
@@ -3508,6 +3041,28 @@ implementation of actual widget type. +
Returns:
+ + +
+ instance of CKEditor +
+ + + +
+
+ Type +
+
+ +Promise.<CKEditor> + + +
+
+ + @@ -3620,7 +3175,7 @@ implementation of actual widget type.
Source:
@@ -3777,7 +3332,7 @@ implementation of actual widget type.
Source:
@@ -3932,7 +3487,7 @@ implementation of actual widget type.
Source:
@@ -4194,7 +3749,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -4657,7 +4212,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4812,7 +4367,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4967,7 +4522,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5404,7 +4959,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5560,7 +5115,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5716,7 +5271,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -5853,7 +5408,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -6007,7 +5562,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -6093,7 +5648,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -6948,7 +6503,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -7099,7 +6654,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -7403,6 +6958,326 @@ Internally this serializes the anonymous function into string and sends it to ba + + + + + + +

triggerCommand(name, data)

+ + + + + + +
+ Trigger command. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + +
data + + +object + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

triggerEvent(name, data)

+ + + + + + +
+ Trigger event. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + +
data + + +object + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + @@ -7465,7 +7340,7 @@ Typical use case is when new note has been created, we should wait until it is s
Source:
diff --git a/docs/frontend_api/NoteShort.html b/docs/frontend_api/NoteShort.html index 2bfe195bd..9796f8771 100644 --- a/docs/frontend_api/NoteShort.html +++ b/docs/frontend_api/NoteShort.html @@ -167,7 +167,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -267,7 +267,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -335,7 +335,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -403,7 +403,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -471,7 +471,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -543,7 +543,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -611,7 +611,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -679,7 +679,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -747,7 +747,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -815,7 +815,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -883,7 +883,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -955,7 +955,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1103,7 +1103,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1303,7 +1303,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1481,7 +1481,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1589,7 +1589,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1693,7 +1693,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1795,7 +1795,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1897,7 +1897,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -1999,7 +1999,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -2150,7 +2150,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -2317,7 +2317,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -2472,7 +2472,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -2582,7 +2582,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -2756,7 +2756,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -2956,7 +2956,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -3134,7 +3134,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -3289,7 +3289,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -3456,7 +3456,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -3611,7 +3611,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -3766,7 +3766,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -3933,7 +3933,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4088,7 +4088,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4194,7 +4194,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4296,7 +4296,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4398,7 +4398,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4500,7 +4500,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4651,7 +4651,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4818,7 +4818,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -4973,7 +4973,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -5143,7 +5143,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -5294,7 +5294,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -5400,7 +5400,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -5513,7 +5513,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -5619,7 +5619,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -5721,7 +5721,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -5895,7 +5895,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6001,7 +6001,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6152,7 +6152,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6330,7 +6330,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6485,7 +6485,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6640,7 +6640,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6795,7 +6795,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6903,7 +6903,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -6987,7 +6987,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -7093,7 +7093,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
@@ -7199,7 +7199,7 @@ This note's representation is used in note tree and is kept in Froca.
Source:
diff --git a/docs/frontend_api/entities_note_short.js.html b/docs/frontend_api/entities_note_short.js.html index 724618c18..8e27a11a8 100644 --- a/docs/frontend_api/entities_note_short.js.html +++ b/docs/frontend_api/entities_note_short.js.html @@ -44,7 +44,8 @@ const NOTE_TYPE_ICONS = { "relation-map": "bx bx-map-alt", "book": "bx bx-book", "note-map": "bx bx-map-alt", - "mermaid": "bx bx-selection" + "mermaid": "bx bx-selection", + "canvas": "bx bx-pen" }; /** diff --git a/docs/frontend_api/services_frontend_script_api.js.html b/docs/frontend_api/services_frontend_script_api.js.html index 8a4cbef6e..fe896a184 100644 --- a/docs/frontend_api/services_frontend_script_api.js.html +++ b/docs/frontend_api/services_frontend_script_api.js.html @@ -327,6 +327,24 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain */ this.showError = toastService.showError; + /** + * Trigger command. + * + * @method + * @param {string} name + * @param {object} data + */ + this.triggerCommand = (name, data) => appContext.triggerCommand(name, data); + + /** + * Trigger event. + * + * @method + * @param {string} name + * @param {object} data + */ + this.triggerEvent = (name, data) => appContext.triggerEvent(name, data); + /** * @method * @deprecated - this is now no-op since all the changes should be gracefully handled per widget diff --git a/libraries/lodash.debounce.js b/libraries/lodash.debounce.js new file mode 100644 index 000000000..4dcbf96c9 --- /dev/null +++ b/libraries/lodash.debounce.js @@ -0,0 +1,70 @@ +/** + * Returns a function, that, as long as it continues to be invoked, will not + * be triggered. The function will be called after it stops being called for + * N milliseconds. If `immediate` is passed, trigger the function on the + * leading edge, instead of the trailing. The function also has a property 'clear' + * that is a function which will clear the timer to prevent previously scheduled executions. + * + * @source underscore.js + * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ + * @param {Function} function to wrap + * @param {Number} timeout in ms (`100`) + * @param {Boolean} whether to execute at the beginning (`false`) + * @api public + */ +function debounce(func, wait_ms, immediate){ + var timeout, args, context, timestamp, result; + if (null == wait_ms) wait_ms = 100; + + function later() { + var last = Date.now() - timestamp; + + if (last < wait_ms && last >= 0) { + timeout = setTimeout(later, wait_ms - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + context = args = null; + } + } + }; + + var debounced = function(){ + context = this; + args = arguments; + timestamp = Date.now(); + var callNow = immediate && !timeout; + if (!timeout) timeout = setTimeout(later, wait_ms); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + + debounced.clear = function() { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + }; + + debounced.flush = function() { + if (timeout) { + result = func.apply(context, args); + context = args = null; + + clearTimeout(timeout); + timeout = null; + } + }; + + return debounced; +}; + +// Adds compatibility for ES modules +debounce.debounce = debounce; + +export default debounce; diff --git a/package-lock.json b/package-lock.json index 1fd5ff38e..fa9248ab0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "AGPL-3.0-only", "dependencies": { "@electron/remote": "2.0.8", + "@excalidraw/excalidraw": "0.11.0", "archiver": "5.3.1", "async-mutex": "0.3.2", "axios": "0.27.2", @@ -20,7 +21,7 @@ "cookie-parser": "1.4.6", "csurf": "1.11.0", "dayjs": "1.11.2", - "ejs": "3.1.7", + "ejs": "3.1.8", "electron-debug": "3.2.0", "electron-dl": "3.3.1", "electron-find": "1.0.7", @@ -28,7 +29,7 @@ "express": "4.18.1", "express-partial-content": "1.0.2", "express-rate-limit": "6.4.0", - "express-session": "1.17.2", + "express-session": "1.17.3", "fs-extra": "10.1.0", "helmet": "5.0.2", "html": "1.0.0", @@ -49,6 +50,8 @@ "open": "8.4.0", "portscanner": "2.2.0", "rand-token": "1.0.1", + "react": "17.0.2", + "react-dom": "17.0.2", "request": "2.88.2", "rimraf": "3.0.2", "sanitize-filename": "1.6.3", @@ -70,7 +73,7 @@ }, "devDependencies": { "cross-env": "7.0.3", - "electron": "16.2.4", + "electron": "16.2.6", "electron-builder": "23.0.3", "electron-packager": "15.5.1", "electron-rebuild": "3.2.7", @@ -79,7 +82,7 @@ "jsdoc": "3.6.10", "lorem-ipsum": "2.0.4", "rcedit": "3.0.1", - "webpack": "5.72.0", + "webpack": "5.72.1", "webpack-cli": "4.9.2" }, "optionalDependencies": { @@ -87,9 +90,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.2.tgz", - "integrity": "sha512-IoVDIHpsgE/fu7eXBeRWt8zLbDrSvD7H1gpomOkPpBoEN8KCruCqSDdqo8dddwQQrui30KSvQBaMUOJiuFu6QQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz", + "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -241,6 +244,18 @@ "node": ">= 10.0.0" } }, + "node_modules/@excalidraw/excalidraw": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.11.0.tgz", + "integrity": "sha512-wY0UdnN9JAcBKLzkGlVXiPSKgTO06YeeBhoIy/ezIiMJtfFtWBPjRjJROkdIGqnUmBz5L16MkuXE7b8j1b1ouw==", + "dependencies": { + "dotenv": "10.0.0" + }, + "peerDependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" + } + }, "node_modules/@gar/promisify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", @@ -742,6 +757,148 @@ "node": ">= 10.0.0" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz", + "integrity": "sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "peer": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "peer": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "peer": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "optional": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@npmcli/fs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.0.tgz", @@ -934,17 +1091,6 @@ "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==", "devOptional": true }, - "node_modules/@types/plist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz", - "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -954,13 +1100,6 @@ "@types/node": "*" } }, - "node_modules/@types/verror": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.5.tgz", - "integrity": "sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==", - "dev": true, - "optional": true - }, "node_modules/@types/yargs": { "version": "17.0.7", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.7.tgz", @@ -1195,7 +1334,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "devOptional": true }, "node_modules/accepts": { "version": "1.3.8", @@ -1673,16 +1812,6 @@ "node": ">=0.8" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", @@ -2346,6 +2475,60 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/canvas": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.9.1.tgz", + "integrity": "sha512-vSQti1uG/2gjv3x6QLOZw7TctfufaerTWbVe+NSduHxxLGB+qf3kFgQ6n66DSnuoINtVUjrLLIK2R+lxrBG07A==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.15.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/canvas/node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "peer": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/canvas/node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/canvas/node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "peer": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -2460,9 +2643,9 @@ "devOptional": true }, "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", "dev": true }, "node_modules/clean-stack": { @@ -2510,71 +2693,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "optional": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "optional": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "optional": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -2728,7 +2846,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, + "devOptional": true, "bin": { "color-support": "bin.js" } @@ -2739,15 +2857,6 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, - "node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2971,16 +3080,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "node_modules/crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "optional": true, - "dependencies": { - "buffer": "^5.1.0" - } - }, "node_modules/crc-32": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", @@ -3205,9 +3304,9 @@ "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -3409,6 +3508,15 @@ "node": ">=0.4.0" } }, + "node_modules/dir-compare/node_modules/colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/dir-compare/node_modules/commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", @@ -3450,33 +3558,6 @@ "node": ">=0.10.0" } }, - "node_modules/dmg-license": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", - "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "deprecated": "Disk image license agreements are deprecated by Apple and will probably be removed in a future macOS release. Discussion at: https://github.com/argv-minus-one/dmg-license/issues/11", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - }, - "bin": { - "dmg-license": "bin/dmg-license.js" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -3562,10 +3643,9 @@ } }, "node_modules/dotenv": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", - "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", - "dev": true, + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", "engines": { "node": ">=10" } @@ -3596,9 +3676,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/ejs": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", - "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", "dependencies": { "jake": "^10.8.5" }, @@ -3610,9 +3690,9 @@ } }, "node_modules/electron": { - "version": "16.2.4", - "resolved": "https://registry.npmjs.org/electron/-/electron-16.2.4.tgz", - "integrity": "sha512-A40aU+gh41EtyspwEBMSuy5KBB56Z8OYSDsqZK9Y8nJdVIFKDtp824x/jnU7N6zNnzVil6oDIFBMGp/hkFu6FQ==", + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-16.2.6.tgz", + "integrity": "sha512-FJLnIu318WNh1WigMmWqSidOPwipwym2Qi3Hs/YY6znquztf6ZJuaq/TdJJyHIJHld+znG0hSmq3VbyW5KUr9A==", "hasInstallScript": true, "dependencies": { "@electron/get": "^1.13.0", @@ -4588,7 +4668,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "devOptional": true }, "node_modules/encodeurl": { "version": "1.0.2", @@ -4602,7 +4682,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -4612,7 +4691,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -4630,9 +4708,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", + "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -4960,11 +5038,11 @@ } }, "node_modules/express-session": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", - "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==", + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz", + "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~2.0.0", @@ -4978,9 +5056,9 @@ } }, "node_modules/express-session/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "engines": { "node": ">= 0.6" } @@ -5195,9 +5273,9 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, "node_modules/filelist": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", - "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dependencies": { "minimatch": "^5.0.1" } @@ -5473,19 +5551,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -6057,23 +6122,6 @@ "ms": "^2.0.0" } }, - "node_modules/iconv-corefoundation": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", - "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - }, - "engines": { - "node": "^8.11.2 || >=10" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -6244,6 +6292,18 @@ "is-ci": "bin.js" } }, + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-docker": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", @@ -6538,9 +6598,9 @@ "dev": true }, "node_modules/jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "dependencies": { "@types/node": "*", @@ -6588,6 +6648,11 @@ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.2.tgz", "integrity": "sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw==" }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -6745,10 +6810,10 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "node_modules/json-schema": { @@ -7020,6 +7085,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lorem-ipsum": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/lorem-ipsum/-/lorem-ipsum-2.0.4.tgz", @@ -7054,6 +7130,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "devOptional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -7103,7 +7180,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, + "devOptional": true, "dependencies": { "semver": "^6.0.0" }, @@ -7118,7 +7195,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, + "devOptional": true, "bin": { "semver": "bin/semver.js" } @@ -7486,6 +7563,13 @@ "node": ">= 0.10.0" } }, + "node_modules/nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "optional": true, + "peer": true + }, "node_modules/nanoid": { "version": "3.1.30", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", @@ -7527,13 +7611,6 @@ "node": ">=10" } }, - "node_modules/node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "dev": true, - "optional": true - }, "node_modules/node-api-version": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.1.4.tgz", @@ -7543,6 +7620,52 @@ "semver": "^7.3.5" } }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "optional": true, + "peer": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "optional": true, + "peer": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "optional": true, + "peer": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "optional": true, + "peer": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-gyp": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", @@ -7694,7 +7817,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, + "devOptional": true, "dependencies": { "abbrev": "1" }, @@ -8247,9 +8370,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" }, @@ -8290,9 +8413,9 @@ } }, "node_modules/plist": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", - "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==", "dev": true, "dependencies": { "base64-js": "^1.5.1", @@ -8602,6 +8725,31 @@ "node": ">= 10.0.0" } }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, "node_modules/read-config-file": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.2.0.tgz", @@ -8618,6 +8766,15 @@ "node": ">=12.0.0" } }, + "node_modules/read-config-file/node_modules/dotenv": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -8807,12 +8964,20 @@ } }, "node_modules/resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-alpn": { @@ -8973,6 +9138,15 @@ "node": ">=10" } }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -8996,13 +9170,13 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.4.0" }, "bin": { "semver": "bin/semver.js" }, "engines": { - "node": ">=10" + "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/semver-compare": { @@ -9032,6 +9206,14 @@ "semver": "bin/semver.js" } }, + "node_modules/semver/node_modules/lru-cache": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.8.1.tgz", + "integrity": "sha512-E1v547OCgJvbvevfjgK9sNKIVXO96NnsTsFPBlg4ZxjhsJSODoH9lk8Bm0OxvHNm6Vm5Yqkl/1fErDxhYL8Skg==", + "engines": { + "node": ">=12" + } + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -9323,31 +9505,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/smart-buffer": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", @@ -9660,6 +9817,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -10323,9 +10492,9 @@ } }, "node_modules/webpack": { - "version": "5.72.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz", - "integrity": "sha512-qmSmbspI0Qo5ld49htys8GY9XhS9CGqFoHTsOVAnjBdg0Zn79y135R+k4IR4rKK6+eKaabMhJwiVB7xw0SJu5w==", + "version": "5.72.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", + "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -10337,13 +10506,13 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.9.3", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", @@ -10919,9 +11088,9 @@ }, "dependencies": { "@babel/parser": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.2.tgz", - "integrity": "sha512-IoVDIHpsgE/fu7eXBeRWt8zLbDrSvD7H1gpomOkPpBoEN8KCruCqSDdqo8dddwQQrui30KSvQBaMUOJiuFu6QQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz", + "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==", "dev": true }, "@babel/runtime": { @@ -11037,6 +11206,14 @@ } } }, + "@excalidraw/excalidraw": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.11.0.tgz", + "integrity": "sha512-wY0UdnN9JAcBKLzkGlVXiPSKgTO06YeeBhoIy/ezIiMJtfFtWBPjRjJROkdIGqnUmBz5L16MkuXE7b8j1b1ouw==", + "requires": { + "dotenv": "10.0.0" + } + }, "@gar/promisify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", @@ -11422,6 +11599,123 @@ } } }, + "@mapbox/node-pre-gyp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz", + "integrity": "sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==", + "optional": true, + "peer": true, + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "optional": true, + "peer": true + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "optional": true, + "peer": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "optional": true, + "peer": true + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "optional": true, + "peer": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "optional": true, + "peer": true + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "optional": true, + "peer": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "optional": true, + "peer": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "optional": true, + "peer": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "optional": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, "@npmcli/fs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.0.tgz", @@ -11595,17 +11889,6 @@ "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==", "devOptional": true }, - "@types/plist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz", - "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==", - "dev": true, - "optional": true, - "requires": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -11615,13 +11898,6 @@ "@types/node": "*" } }, - "@types/verror": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.5.tgz", - "integrity": "sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==", - "dev": true, - "optional": true - }, "@types/yargs": { "version": "17.0.7", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.7.tgz", @@ -11843,7 +12119,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "devOptional": true }, "accepts": { "version": "1.3.8", @@ -12230,13 +12506,6 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "optional": true - }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", @@ -12770,6 +13039,49 @@ "integrity": "sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==", "dev": true }, + "canvas": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.9.1.tgz", + "integrity": "sha512-vSQti1uG/2gjv3x6QLOZw7TctfufaerTWbVe+NSduHxxLGB+qf3kFgQ6n66DSnuoINtVUjrLLIK2R+lxrBG07A==", + "optional": true, + "peer": true, + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.15.0", + "simple-get": "^3.0.3" + }, + "dependencies": { + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "peer": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "peer": true + }, + "simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "peer": true, + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + } + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -12852,9 +13164,9 @@ "devOptional": true }, "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", "dev": true }, "clean-stack": { @@ -12884,55 +13196,6 @@ "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", "dev": true }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "optional": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "optional": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "optional": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, "cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -13059,7 +13322,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true + "devOptional": true }, "colorette": { "version": "2.0.16", @@ -13067,12 +13330,6 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -13245,16 +13502,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "optional": true, - "requires": { - "buffer": "^5.1.0" - } - }, "crc-32": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", @@ -13418,9 +13665,9 @@ "integrity": "sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==" }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" }, @@ -13575,6 +13822,12 @@ "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", "dev": true }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, "commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", @@ -13612,23 +13865,6 @@ } } }, - "dmg-license": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", - "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "dev": true, - "optional": true, - "requires": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - } - }, "dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -13690,10 +13926,9 @@ } }, "dotenv": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", - "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", - "dev": true + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" }, "dotenv-expand": { "version": "5.1.0", @@ -13721,17 +13956,17 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "ejs": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", - "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", "requires": { "jake": "^10.8.5" } }, "electron": { - "version": "16.2.4", - "resolved": "https://registry.npmjs.org/electron/-/electron-16.2.4.tgz", - "integrity": "sha512-A40aU+gh41EtyspwEBMSuy5KBB56Z8OYSDsqZK9Y8nJdVIFKDtp824x/jnU7N6zNnzVil6oDIFBMGp/hkFu6FQ==", + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-16.2.6.tgz", + "integrity": "sha512-FJLnIu318WNh1WigMmWqSidOPwipwym2Qi3Hs/YY6znquztf6ZJuaq/TdJJyHIJHld+znG0hSmq3VbyW5KUr9A==", "requires": { "@electron/get": "^1.13.0", "@types/node": "^14.6.2", @@ -14465,7 +14700,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "devOptional": true }, "encodeurl": { "version": "1.0.2", @@ -14476,7 +14711,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "requires": { "iconv-lite": "^0.6.2" @@ -14486,7 +14720,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -14503,9 +14736,9 @@ } }, "enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", + "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -14780,11 +15013,11 @@ "requires": {} }, "express-session": { - "version": "1.17.2", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", - "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==", + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz", + "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==", "requires": { - "cookie": "0.4.1", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~2.0.0", @@ -14795,9 +15028,9 @@ }, "dependencies": { "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" }, "debug": { "version": "2.6.9", @@ -14918,9 +15151,9 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, "filelist": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", - "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "requires": { "minimatch": "^5.0.1" }, @@ -15130,12 +15363,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -15597,17 +15824,6 @@ "ms": "^2.0.0" } }, - "iconv-corefoundation": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", - "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", - "dev": true, - "optional": true, - "requires": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - } - }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -15738,6 +15954,15 @@ "ci-info": "^3.2.0" } }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-docker": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", @@ -15944,9 +16169,9 @@ "dev": true }, "jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "requires": { "@types/node": "*", @@ -15987,6 +16212,11 @@ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.2.tgz", "integrity": "sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw==" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -16110,10 +16340,10 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "json-schema": { @@ -16340,6 +16570,14 @@ "is-unicode-supported": "^0.1.0" } }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "lorem-ipsum": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/lorem-ipsum/-/lorem-ipsum-2.0.4.tgz", @@ -16366,6 +16604,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "devOptional": true, "requires": { "yallist": "^4.0.0" } @@ -16404,7 +16643,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, + "devOptional": true, "requires": { "semver": "^6.0.0" }, @@ -16413,7 +16652,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "devOptional": true } } }, @@ -16697,6 +16936,13 @@ "xtend": "^4.0.0" } }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "optional": true, + "peer": true + }, "nanoid": { "version": "3.1.30", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", @@ -16726,13 +16972,6 @@ "semver": "^7.3.5" } }, - "node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "dev": true, - "optional": true - }, "node-api-version": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.1.4.tgz", @@ -16742,6 +16981,43 @@ "semver": "^7.3.5" } }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "optional": true, + "peer": true, + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "optional": true, + "peer": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "optional": true, + "peer": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "optional": true, + "peer": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-gyp": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", @@ -16860,7 +17136,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, + "devOptional": true, "requires": { "abbrev": "1" } @@ -17294,9 +17570,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pify": { "version": "2.3.0", @@ -17322,9 +17598,9 @@ } }, "plist": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", - "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==", "dev": true, "requires": { "base64-js": "^1.5.1", @@ -17552,6 +17828,25 @@ "cross-spawn-windows-exe": "^1.1.0" } }, + "react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, "read-config-file": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.2.0.tgz", @@ -17563,6 +17858,14 @@ "js-yaml": "^4.1.0", "json5": "^2.2.0", "lazy-val": "^1.0.4" + }, + "dependencies": { + "dotenv": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "dev": true + } } }, "read-pkg": { @@ -17724,12 +18027,14 @@ } }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-alpn": { @@ -17864,6 +18169,15 @@ "xmlchars": "^2.2.0" } }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -17880,7 +18194,14 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.4.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.8.1.tgz", + "integrity": "sha512-E1v547OCgJvbvevfjgK9sNKIVXO96NnsTsFPBlg4ZxjhsJSODoH9lk8Bm0OxvHNm6Vm5Yqkl/1fErDxhYL8Skg==" + } } }, "semver-compare": { @@ -18130,27 +18451,6 @@ } } }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "optional": true - } - } - }, "smart-buffer": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", @@ -18392,6 +18692,12 @@ "has-flag": "^4.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -18906,9 +19212,9 @@ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" }, "webpack": { - "version": "5.72.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz", - "integrity": "sha512-qmSmbspI0Qo5ld49htys8GY9XhS9CGqFoHTsOVAnjBdg0Zn79y135R+k4IR4rKK6+eKaabMhJwiVB7xw0SJu5w==", + "version": "5.72.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", + "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -18920,13 +19226,13 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.9.3", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", diff --git a/package.json b/package.json index dc38d7816..5b7042461 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "test-all": "npm run test && npm run test-es6" }, "dependencies": { + "@excalidraw/excalidraw": "0.11.0", "archiver": "5.3.1", "async-mutex": "0.3.2", "axios": "0.27.2", @@ -34,7 +35,7 @@ "cookie-parser": "1.4.6", "csurf": "1.11.0", "dayjs": "1.11.2", - "ejs": "3.1.7", + "ejs": "3.1.8", "electron-debug": "3.2.0", "electron-dl": "3.3.1", "electron-window-state": "5.0.3", @@ -42,7 +43,7 @@ "express": "4.18.1", "express-partial-content": "1.0.2", "express-rate-limit": "6.4.0", - "express-session": "1.17.2", + "express-session": "1.17.3", "fs-extra": "10.1.0", "helmet": "5.0.2", "html": "1.0.0", @@ -63,6 +64,8 @@ "open": "8.4.0", "portscanner": "2.2.0", "rand-token": "1.0.1", + "react": "17.0.2", + "react-dom": "17.0.2", "request": "2.88.2", "rimraf": "3.0.2", "sanitize-filename": "1.6.3", @@ -81,7 +84,7 @@ }, "devDependencies": { "cross-env": "7.0.3", - "electron": "16.2.4", + "electron": "16.2.6", "electron-builder": "23.0.3", "electron-packager": "15.5.1", "electron-rebuild": "3.2.7", @@ -90,7 +93,7 @@ "jsdoc": "3.6.10", "lorem-ipsum": "2.0.4", "rcedit": "3.0.1", - "webpack": "5.72.0", + "webpack": "5.72.1", "webpack-cli": "4.9.2" }, "optionalDependencies": { diff --git a/spec/search/parser.spec.js b/spec/search/parser.spec.js index 493fc5d5f..05df9ef40 100644 --- a/spec/search/parser.spec.js +++ b/spec/search/parser.spec.js @@ -58,11 +58,8 @@ describe("Parser", () => { expect(subs[0].constructor.name).toEqual("NoteFlatTextExp"); expect(subs[0].tokens).toEqual(["hello", "hi"]); - expect(subs[1].constructor.name).toEqual("NoteContentProtectedFulltextExp"); + expect(subs[1].constructor.name).toEqual("NoteContentFulltextExp"); expect(subs[1].tokens).toEqual(["hello", "hi"]); - - expect(subs[2].constructor.name).toEqual("NoteContentUnprotectedFulltextExp"); - expect(subs[2].tokens).toEqual(["hello", "hi"]); }); it("simple label comparison", () => { diff --git a/src/app.js b/src/app.js index b530ca7e4..abc3c2451 100644 --- a/src/app.js +++ b/src/app.js @@ -30,6 +30,11 @@ app.use(express.urlencoded({extended: false})); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/libraries', express.static(path.join(__dirname, '..', 'libraries'))); +// excalidraw-view mode in shared notes +app.use('/node_modules/react/umd/react.production.min.js', express.static(path.join(__dirname, '..', 'node_modules/react/umd/react.production.min.js'))); +app.use('/node_modules/react-dom/umd/react-dom.production.min.js', express.static(path.join(__dirname, '..', 'node_modules/react-dom/umd/react-dom.production.min.js'))); +// expose whole dist folder since complete assets are needed in edit and share +app.use('/node_modules/@excalidraw/excalidraw/dist/', express.static(path.join(__dirname, '..', 'node_modules/@excalidraw/excalidraw/dist/'))); app.use('/images', express.static(path.join(__dirname, '..', 'images'))); const sessionParser = session({ secret: sessionSecret, diff --git a/src/public/app/dialogs/note_revisions.js b/src/public/app/dialogs/note_revisions.js index 19da96cc8..95e13d70b 100644 --- a/src/public/app/dialogs/note_revisions.js +++ b/src/public/app/dialogs/note_revisions.js @@ -171,6 +171,28 @@ async function setContentPane() { $content.html($table); } + else if (revisionItem.type === 'canvas') { + /** + * FIXME: We load a font called Virgil.wof2, which originates from excalidraw.com + * REMOVE external dependency!!!! This is defined in the svg in defs.style + */ + const content = fullNoteRevision.content; + + try { + const data = JSON.parse(content) + const svg = data.svg || "no svg present." + + /** + * maxWidth: 100% use full width of container but do not enlarge! + * height:auto to ensure that height scales with width + */ + const $svgHtml = $(svg).css({maxWidth: "100%", height: "auto"}); + $content.html($('
').append($svgHtml)); + } catch(err) { + console.error("error parsing fullNoteRevision.content as JSON", fullNoteRevision.content, err); + $content.html($("
").text("Error parsing content. Please check console.error() for more details.")); + } + } else { $content.text("Preview isn't available for this note type."); } diff --git a/src/public/app/entities/note_short.js b/src/public/app/entities/note_short.js index 2c403080d..13bae5a93 100644 --- a/src/public/app/entities/note_short.js +++ b/src/public/app/entities/note_short.js @@ -16,7 +16,8 @@ const NOTE_TYPE_ICONS = { "relation-map": "bx bx-map-alt", "book": "bx bx-book", "note-map": "bx bx-map-alt", - "mermaid": "bx bx-selection" + "mermaid": "bx bx-selection", + "canvas": "bx bx-pen" }; /** diff --git a/src/public/app/services/frontend_script_api.js b/src/public/app/services/frontend_script_api.js index 257fee0df..dee3b7a7d 100644 --- a/src/public/app/services/frontend_script_api.js +++ b/src/public/app/services/frontend_script_api.js @@ -299,6 +299,24 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain */ this.showError = toastService.showError; + /** + * Trigger command. + * + * @method + * @param {string} name + * @param {object} data + */ + this.triggerCommand = (name, data) => appContext.triggerCommand(name, data); + + /** + * Trigger event. + * + * @method + * @param {string} name + * @param {object} data + */ + this.triggerEvent = (name, data) => appContext.triggerEvent(name, data); + /** * @method * @deprecated - this is now no-op since all the changes should be gracefully handled per widget diff --git a/src/public/app/services/library_loader.js b/src/public/app/services/library_loader.js index b6f0dbc8e..a80ac1cbf 100644 --- a/src/public/app/services/library_loader.js +++ b/src/public/app/services/library_loader.js @@ -56,6 +56,17 @@ const MERMAID = { js: [ "libraries/mermaid.min.js" ] } +const EXCALIDRAW = { + js: [ + "node_modules/react/umd/react.production.min.js", + "node_modules/react-dom/umd/react-dom.production.min.js", + "node_modules/@excalidraw/excalidraw/dist/excalidraw.production.min.js", + ], + // css: [ + // "stylesheets/somestyle.css" + // ] +}; + async function requireLibrary(library) { if (library.css) { library.css.map(cssUrl => requireCss(cssUrl)); @@ -106,5 +117,6 @@ export default { KATEX, WHEEL_ZOOM, FORCE_GRAPH, - MERMAID + MERMAID, + EXCALIDRAW } diff --git a/src/public/app/services/note_content_renderer.js b/src/public/app/services/note_content_renderer.js index f7c970f1b..771f860b7 100644 --- a/src/public/app/services/note_content_renderer.js +++ b/src/public/app/services/note_content_renderer.js @@ -141,6 +141,27 @@ async function getRenderedContent(note, options = {}) { $renderedContent.append($content); } + else if (type === 'canvas') { + // make sure surrounding container has size of what is visible. Then image is shrinked to its boundaries + $renderedContent.css({height: "100%", width:"100%"}); + + const noteComplement = await froca.getNoteComplement(note.noteId); + const content = noteComplement.content || ""; + + try { + const placeHolderSVG = ""; + const data = JSON.parse(content) + const svg = data.svg || placeHolderSVG; + /** + * maxWidth: size down to 100% (full) width of container but do not enlarge! + * height:auto to ensure that height scales with width + */ + $renderedContent.append($(svg).css({maxWidth: "100%", maxHeight: "100%", height: "auto", width: "auto"})); + } catch(err) { + console.error("error parsing content as JSON", content, err); + $renderedContent.append($("
").text("Error parsing content. Please check console.error() for more details.")); + } + } else if (!options.tooltip && type === 'protected-session') { const $button = $(``) .on('click', protectedSessionService.enterProtectedSession); diff --git a/src/public/app/services/note_list_renderer.js b/src/public/app/services/note_list_renderer.js index 22e593470..705a0d31f 100644 --- a/src/public/app/services/note_list_renderer.js +++ b/src/public/app/services/note_list_renderer.js @@ -99,13 +99,15 @@ const TPL = ` padding: 10px; } - .note-book-content.type-image img { + .note-book-content.type-image img, .note-book-content.type-canvas svg { max-width: 100%; max-height: 100%; object-fit: contain; } - .note-book-card.type-image .note-book-content img, .note-book-card.type-text .note-book-content img { + .note-book-card.type-image .note-book-content img, + .note-book-card.type-text .note-book-content img, + .note-book-card.type-canvas .note-book-content img { max-width: 100%; max-height: 100%; } diff --git a/src/public/app/services/protected_session_holder.js b/src/public/app/services/protected_session_holder.js index 86ff20b2b..8fdae303c 100644 --- a/src/public/app/services/protected_session_holder.js +++ b/src/public/app/services/protected_session_holder.js @@ -1,17 +1,5 @@ -import options from './options.js'; import server from "./server.js"; -let lastProtectedSessionOperationDate = 0; - -setInterval(() => { - const protectedSessionTimeout = options.getInt('protectedSessionTimeout'); - if (lastProtectedSessionOperationDate - && Date.now() - lastProtectedSessionOperationDate > protectedSessionTimeout * 1000) { - - resetProtectedSession(); - } -}, 10000); - function enableProtectedSession() { glob.isProtectedSessionAvailable = true; @@ -26,9 +14,9 @@ function isProtectedSessionAvailable() { return glob.isProtectedSessionAvailable; } -function touchProtectedSession() { +async function touchProtectedSession() { if (isProtectedSessionAvailable()) { - lastProtectedSessionOperationDate = Date.now(); + await server.post("login/protected/touch"); } } diff --git a/src/public/app/services/tree_context_menu.js b/src/public/app/services/tree_context_menu.js index f22de134b..89d860804 100644 --- a/src/public/app/services/tree_context_menu.js +++ b/src/public/app/services/tree_context_menu.js @@ -33,7 +33,8 @@ class TreeContextMenu { { title: "Note Map", command: command, type: "note-map", uiIcon: "map-alt" }, { title: "Render HTML note", command: command, type: "render", uiIcon: "extension" }, { title: "Book", command: command, type: "book", uiIcon: "book" }, - { title: "Mermaid diagram", command: command, type: "mermaid", uiIcon: "selection" } + { title: "Mermaid diagram", command: command, type: "mermaid", uiIcon: "selection" }, + { title: "Canvas", command: command, type: "canvas", uiIcon: "pen" }, ]; } diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js index 213787b10..9facea6f8 100644 --- a/src/public/app/services/utils.js +++ b/src/public/app/services/utils.js @@ -359,6 +359,12 @@ function isValidAttributeName(name) { return ATTR_NAME_MATCHER.test(name); } +function sleep(time_ms) { + return new Promise((resolve) => { + setTimeout(resolve, time_ms); + }); +} + export default { reloadFrontendApp, parseDate, @@ -402,5 +408,6 @@ export default { initHelpButtons, openHelp, filterAttributeName, - isValidAttributeName + isValidAttributeName, + sleep, }; diff --git a/src/public/app/widgets/note_detail.js b/src/public/app/widgets/note_detail.js index ef1d0fd42..0a0790fa8 100644 --- a/src/public/app/widgets/note_detail.js +++ b/src/public/app/widgets/note_detail.js @@ -10,6 +10,7 @@ import FileTypeWidget from "./type_widgets/file.js"; import ImageTypeWidget from "./type_widgets/image.js"; import RenderTypeWidget from "./type_widgets/render.js"; import RelationMapTypeWidget from "./type_widgets/relation_map.js"; +import CanvasTypeWidget from "./type_widgets/canvas.js"; import ProtectedSessionTypeWidget from "./type_widgets/protected_session.js"; import BookTypeWidget from "./type_widgets/book.js"; import appContext from "../services/app_context.js"; @@ -50,6 +51,7 @@ const typeWidgetClasses = { 'search': NoneTypeWidget, 'render': RenderTypeWidget, 'relation-map': RelationMapTypeWidget, + 'canvas': CanvasTypeWidget, 'protected-session': ProtectedSessionTypeWidget, 'book': BookTypeWidget, 'note-map': NoteMapTypeWidget @@ -66,7 +68,7 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { const {noteId} = note; const dto = note.dto; - dto.content = this.getTypeWidget().getContent(); + dto.content = await this.getTypeWidget().getContent(); // for read only notes if (dto.content === undefined) { @@ -145,11 +147,14 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { this.checkFullHeight(); } + /** + * sets full height of container that contains note content for a subset of note-types + */ checkFullHeight() { // https://github.com/zadam/trilium/issues/2522 this.$widget.toggleClass("full-height", !this.noteContext.hasNoteList() - && ['editable-text', 'editable-code'].includes(this.type) + && ['editable-text', 'editable-code', 'canvas'].includes(this.type) && this.mime !== 'text/x-sqlite;schema=trilium'); } diff --git a/src/public/app/widgets/note_type.js b/src/public/app/widgets/note_type.js index a81e446e3..e3206ebc0 100644 --- a/src/public/app/widgets/note_type.js +++ b/src/public/app/widgets/note_type.js @@ -11,6 +11,7 @@ const NOTE_TYPES = [ { type: "text", mime: "text/html", title: "Text", selectable: true }, { type: "relation-map", mime: "application/json", title: "Relation Map", selectable: true }, { type: "render", mime: '', title: "Render Note", selectable: true }, + { type: "canvas", mime: 'application/json', title: "Canvas", selectable: true }, { type: "book", mime: '', title: "Book", selectable: true }, { type: "mermaid", mime: 'text/mermaid', title: "Mermaid Diagram", selectable: true }, { type: "code", mime: 'text/plain', title: "Code", selectable: true } diff --git a/src/public/app/widgets/note_wrapper.js b/src/public/app/widgets/note_wrapper.js index 6de26926e..227543c65 100644 --- a/src/public/app/widgets/note_wrapper.js +++ b/src/public/app/widgets/note_wrapper.js @@ -32,7 +32,7 @@ export default class NoteWrapperWidget extends FlexContainer { refresh(noteContext) { this.$widget.toggleClass("full-content-width", - ['image', 'mermaid', 'book', 'render'].includes(noteContext?.note?.type) + ['image', 'mermaid', 'book', 'render', 'canvas'].includes(noteContext?.note?.type) || !!noteContext?.note?.hasLabel('fullContentWidth') ); } diff --git a/src/public/app/widgets/type_widgets/canvas.js b/src/public/app/widgets/type_widgets/canvas.js new file mode 100644 index 000000000..483baa572 --- /dev/null +++ b/src/public/app/widgets/type_widgets/canvas.js @@ -0,0 +1,477 @@ +import libraryLoader from "../../services/library_loader.js"; +import TypeWidget from "./type_widget.js"; +import utils from '../../services/utils.js'; +import froca from "../../services/froca.js"; +import debounce from "../../../../../libraries/lodash.debounce.js"; + +const {sleep} = utils; + +const TPL = ` +
+ + +
+
+`; + +/** + * # Canvas note with excalidraw + * @author thfrei 2022-05-11 + * + * Background: + * excalidraw gives great support for hand drawn notes. It also allows to include images and support + * for sketching. Excalidraw has a vibrant and active community. + * + * Functionality: + * We store the excalidraw assets (elements, appState, files) in the note. In addition to that, we + * export the SVG from the canvas on every update. The SVG is also saved in the note. It is used + * for displaying any canvas note inside of a text note as an image. + * + * Paths not taken. + * - excalidraw-to-svg (node.js) could be used to avoid storing the svg in the backend. + * We could render the SVG on the fly. However, as of now, it does not render any hand drawn + * (freedraw) paths. There is an issue with Path2D object not present in node-canvas library + * used by jsdom. (See Trilium PR for samples and other issues in respective library. + * Link will be added later). Related links: + * - https://github.com/Automattic/node-canvas/pull/2013 + * - https://github.com/google/canvas-5-polyfill + * - https://github.com/Automattic/node-canvas/issues/1116 + * - https://www.npmjs.com/package/path2d-polyfill + * - excalidraw-to-svg (node.js) takes quite some time to load an image (1-2s) + * - excalidraw-utils (browser) does render freedraw, however NOT freedraw with background. It is not + * used, since it is a big dependency, and has the same functionality as react + excalidraw. + * - infinite-drawing-canvas with fabric.js. This library lacked a lot of feature, excalidraw already + * has. + * + * Known issues: + * - v0.11.0 of excalidraw does not render freedraw backgrounds in the svg + * - the 3 excalidraw fonts should be included in the share and everywhere, so that it is shown + * when requiring svg. + * + * Discussion of storing svg in the note: + * - Pro: we will combat bit-rot. Showing the SVG will be very fast and easy, since it is already there. + * - Con: The note will get bigger (~40-50%?), we will generate more bandwith. However, using trilium + * desktop instance mitigates that issue. + * + * Roadmap: + * - Support image-notes as reference in excalidraw + * - Support canvas note as reference (svg) in other canvas notes. + * - Make it easy to include a canvas note inside a text note + * - Support for excalidraw libraries. Maybe special code notes with a tag. + */ +export default class ExcalidrawTypeWidget extends TypeWidget { + constructor() { + super(); + + // constants + this.SCENE_VERSION_INITIAL = -1; + this.SCENE_VERSION_ERROR = -2; + + // config + this.DEBOUNCE_TIME_ONCHANGEHANDLER = 750; // ms + // ensure that assets are loaded from trilium + window.EXCALIDRAW_ASSET_PATH = `${window.location.origin}/node_modules/@excalidraw/excalidraw/dist/`; + + // temporary vars + this.currentNoteId = ""; + this.currentSceneVersion = this.SCENE_VERSION_INITIAL; + + // will be overwritten + this.excalidrawRef; + this.$render; + this.renderElement; + this.$widget; + this.reactHandlers; // used to control react state + + this.createExcalidrawReactApp = this.createExcalidrawReactApp.bind(this); + this.onChangeHandler = this.onChangeHandler.bind(this); + this.isNewSceneVersion = this.isNewSceneVersion.bind(this); + } + + /** + * (trilium) + * @returns {string} "canvas" + */ + static getType() { + return "canvas"; + } + + /** + * (trilium) + * renders note + */ + doRender() { + this.$widget = $(TPL); + + this.$widget.toggleClass("full-height", true); // only add + this.$render = this.$widget.find('.canvas-render'); + this.renderElement = this.$render.get(0); + + libraryLoader + .requireLibrary(libraryLoader.EXCALIDRAW) + .then(() => { + const React = window.React; + const ReactDOM = window.ReactDOM; + + ReactDOM.unmountComponentAtNode(this.renderElement); + ReactDOM.render(React.createElement(this.createExcalidrawReactApp), this.renderElement); + }) + + return this.$widget; + } + + /** + * (trilium) + * called to populate the widget container with the note content + * + * @param {note} note + */ + async doRefresh(note) { + // see if note changed, since we do not get a new class for a new note + const noteChanged = this.currentNoteId !== note.noteId; + if (noteChanged) { + // reset scene to omit unnecessary onchange handler + this.currentSceneVersion = this.SCENE_VERSION_INITIAL; + } + this.currentNoteId = note.noteId; + + // get note from backend and put into canvas + const noteComplement = await froca.getNoteComplement(note.noteId); + + // before we load content into excalidraw, make sure excalidraw has loaded + while (!this.excalidrawRef || !this.excalidrawRef.current) { + this.log("excalidrawRef not yet loeaded, sleep 200ms..."); + await sleep(200); + } + + /** + * new and empty note - make sure that canvas is empty. + * If we do not set it manually, we occasionally get some "bleeding" from another + * note into this fresh note. Probably due to that this note-instance does not get + * newly instantiated? + */ + if (this.excalidrawRef.current && noteComplement.content === "") { + const sceneData = { + elements: [], + appState: {}, + collaborators: [] + }; + + this.excalidrawRef.current.updateScene(sceneData); + } + + /** + * load saved content into excalidraw canvas + */ + else if (this.excalidrawRef.current && noteComplement.content) { + let content ={ + elements: [], + appState: [], + files: [], + }; + + try { + content = JSON.parse(noteComplement.content || ""); + } catch(err) { + console.error("Error parsing content. Probably note.type changed", + "Starting with empty canvas" + , note, noteComplement, err); + } + + const {elements, appState, files} = content; + + /** + * use widths and offsets of current view, since stored appState has the state from + * previous edit. using the stored state would lead to pointer mismatch. + */ + const boundingClientRect = this.excalidrawWrapperRef.current.getBoundingClientRect(); + appState.width = boundingClientRect.width; + appState.height = boundingClientRect.height; + appState.offsetLeft = boundingClientRect.left; + appState.offsetTop = boundingClientRect.top; + + const sceneData = { + elements, + appState, + collaborators: [] + }; + + // files are expected in an array when loading. they are stored as an key-index object + // see example for loading here: + // https://github.com/excalidraw/excalidraw/blob/c5a7723185f6ca05e0ceb0b0d45c4e3fbcb81b2a/src/packages/excalidraw/example/App.js#L68 + const fileArray = []; + for (const fileId in files) { + const file = files[fileId]; + // TODO: dataURL is replaceable with a trilium image url + // maybe we can save normal images (pasted) with base64 data url, and trilium images + // with their respective url! nice + // file.dataURL = "http://localhost:8080/api/images/ltjOiU8nwoZx/start.png"; + fileArray.push(file); + } + + this.sceneVersion = window.Excalidraw.getSceneVersion(elements); + + this.excalidrawRef.current.updateScene(sceneData); + this.excalidrawRef.current.addFiles(fileArray); + } + + // set initial scene version + if (this.currentSceneVersion === this.SCENE_VERSION_INITIAL) { + this.currentSceneVersion = this.getSceneVersion(); + } + } + + /** + * (trilium) + * gets data from widget container that will be sent via spacedUpdate.scheduleUpdate(); + * this is automatically called after this.saveData(); + */ + async getContent() { + const elements = this.excalidrawRef.current.getSceneElements(); + const appState = this.excalidrawRef.current.getAppState(); + + /** + * A file is not deleted, even though removed from canvas. therefore we only keep + * files that are referenced by an element. Maybe this will change with new excalidraw version? + */ + const files = this.excalidrawRef.current.getFiles(); + + /** + * parallel svg export to combat bitrot and enable rendering image for note inclusion, + * preview and share. + */ + const svg = await window.Excalidraw.exportToSvg({ + elements, + appState, + exportPadding: 5, // 5 px padding + metadata: 'trilium-export', + files + }); + const svgString = svg.outerHTML; + + /** + * workaround until https://github.com/excalidraw/excalidraw/pull/5065 is merged and published + */ + const svgSafeString = this.replaceExternalAssets(svgString); + + const activeFiles = {}; + elements.forEach((element) => { + if (element.fileId) { + activeFiles[element.fileId] = files[element.fileId]; + } + }) + + const content = { + _meta: "This note has type `canvas`. It uses excalidraw and stores an exported svg alongside.", + elements, // excalidraw + appState, // excalidraw + files: activeFiles, // excalidraw + svg: svgSafeString, // not needed for excalidraw, used for note_short, content, and image api + }; + + const contentString = JSON.stringify(content); + + return contentString; + } + + /** + * (trilium) + * save content to backend + * spacedUpdate is kind of a debouncer. + */ + saveData() { + this.spacedUpdate.scheduleUpdate(); + } + + onChangeHandler() { + const appState = this.excalidrawRef.current.getAppState() || {}; + + // changeHandler is called upon any tiny change in excalidraw. button clicked, hover, etc. + // make sure only when a new element is added, we actually save something. + const isNewSceneVersion = this.isNewSceneVersion(); + /** + * FIXME: however, we might want to make an exception, if viewport changed, since viewport + * is desired to save? (add) and appState background, and some things + */ + + // upon updateScene, onchange is called, even though "nothing really changed" that is worth saving + const isNotInitialScene = this.currentSceneVersion !== this.SCENE_VERSION_INITIAL; + + const shouldSave = isNewSceneVersion && isNotInitialScene; + + if (shouldSave) { + this.updateSceneVersion(); + this.saveData(); + } else { + // do nothing + } + } + + createExcalidrawReactApp() { + const React = window.React; + const Excalidraw = window.Excalidraw; + + const excalidrawRef = React.useRef(null); + this.excalidrawRef = excalidrawRef; + const excalidrawWrapperRef = React.useRef(null); + this.excalidrawWrapperRef = excalidrawWrapperRef; + const [dimensions, setDimensions] = React.useState({ + width: undefined, + height: undefined + }); + + const [viewModeEnabled, setViewModeEnabled] = React.useState(false); + const [zenModeEnabled, setZenModeEnabled] = React.useState(false); + const [gridModeEnabled, setGridModeEnabled] = React.useState(false); + const [synchronized, setSynchronized] = React.useState(true); + + React.useEffect(() => { + const dimensions = { + width: excalidrawWrapperRef.current.getBoundingClientRect().width, + height: excalidrawWrapperRef.current.getBoundingClientRect().height + }; + setDimensions(dimensions); + + const onResize = () => { + const dimensions = { + width: excalidrawWrapperRef.current.getBoundingClientRect().width, + height: excalidrawWrapperRef.current.getBoundingClientRect().height + }; + setDimensions(dimensions); + }; + + window.addEventListener("resize", onResize); + + return () => window.removeEventListener("resize", onResize); + }, [excalidrawWrapperRef]); + + const onLinkOpen = React.useCallback((element, event) => { + const link = element.link; + const { nativeEvent } = event.detail; + const isNewTab = nativeEvent.ctrlKey || nativeEvent.metaKey; + const isNewWindow = nativeEvent.shiftKey; + const isInternalLink = link.startsWith("/") + || link.includes(window.location.origin); + + if (isInternalLink && !isNewTab && !isNewWindow) { + // signal that we're handling the redirect ourselves + event.preventDefault(); + // do a custom redirect, such as passing to react-router + // ... + } else { + // open in same tab + } + }, []); + + return React.createElement( + React.Fragment, + null, + React.createElement( + "div", + { + className: "excalidraw-wrapper", + ref: excalidrawWrapperRef + }, + React.createElement(Excalidraw.default, { + ref: excalidrawRef, + width: dimensions.width, + height: dimensions.height, + // initialData: InitialData, + onPaste: (data, event) => { + this.log("Verbose: excalidraw internal paste. No trilium action implemented.", data, event); + }, + onChange: debounce(this.onChangeHandler, this.DEBOUNCE_TIME_ONCHANGEHANDLER), + // onPointerUpdate: (payload) => console.log(payload), + onCollabButtonClick: () => { + window.alert("You clicked on collab button. No collaboration is implemented."); + }, + viewModeEnabled: viewModeEnabled, + zenModeEnabled: zenModeEnabled, + gridModeEnabled: gridModeEnabled, + isCollaborating: false, + detectScroll: false, + handleKeyboardGlobally: false, + autoFocus: true, + onLinkOpen, + }) + ) + ); + } + + /** + * needed to ensure, that multipleOnChangeHandler calls do not trigger a safe. + * we compare the scene version as suggested in: + * https://github.com/excalidraw/excalidraw/issues/3014#issuecomment-778115329 + * + * info: sceneVersions are not incrementing. it seems to be a pseudo-random number + */ + isNewSceneVersion() { + const sceneVersion = this.getSceneVersion(); + + return this.currentSceneVersion === this.SCENE_VERSION_INITIAL // initial scene version update + || this.currentSceneVersion !== sceneVersion // ensure scene changed + ; + } + + getSceneVersion() { + if (this.excalidrawRef) { + const elements = this.excalidrawRef.current.getSceneElements(); + const sceneVersion = window.Excalidraw.getSceneVersion(elements); + return sceneVersion; + } else { + return this.SCENE_VERSION_ERROR; + } + } + + updateSceneVersion() { + this.currentSceneVersion = this.getSceneVersion(); + } + + /** + * logs to console.log with some predefined title + * + * @param {...any} args + */ + log(...args) { + let title = ''; + if (this.note) { + title = this.note.title; + } else { + title = this.noteId + "nt/na"; + } + + console.log(title, "=", this.noteId, "==", ...args); + } + + /** + * replaces exlicraw.com with own assets + * + * workaround until https://github.com/excalidraw/excalidraw/pull/5065 is merged and published + * needed for v0.11.0 + * + * @param {string} string + * @returns + */ + replaceExternalAssets = (string) => { + let result = string; + // exlidraw.com asset in react usage + result = result.replaceAll("https://excalidraw.com/", window.EXCALIDRAW_ASSET_PATH+"excalidraw-assets/"); + return result; + } +} diff --git a/src/public/app/widgets/type_widgets/type_widget.js b/src/public/app/widgets/type_widgets/type_widget.js index 49aa2212d..f3dd88317 100644 --- a/src/public/app/widgets/type_widgets/type_widget.js +++ b/src/public/app/widgets/type_widgets/type_widget.js @@ -38,6 +38,9 @@ export default class TypeWidget extends NoteContextAwareWidget { return this.$widget.is(":visible") && this.noteContext?.ntxId === appContext.tabManager.activeNtxId; } + /** + * @returns {Promise|*} promise resolving content or directly the content + */ getContent() {} focus() {} diff --git a/src/routes/api/image.js b/src/routes/api/image.js index 379eaf65f..7807f1fb9 100644 --- a/src/routes/api/image.js +++ b/src/routes/api/image.js @@ -11,7 +11,7 @@ function returnImage(req, res) { if (!image) { return res.sendStatus(404); } - else if (image.type !== 'image') { + else if (!["image", "canvas"].includes(image.type)){ return res.sendStatus(400); } else if (image.isDeleted || image.data === null) { @@ -19,10 +19,27 @@ function returnImage(req, res) { return res.send(fs.readFileSync(RESOURCE_DIR + '/db/image-deleted.png')); } - res.set('Content-Type', image.mime); - res.set("Cache-Control", "no-cache, no-store, must-revalidate"); - - res.send(image.getContent()); + /** + * special "image" type. the canvas is actually type application/json + * to avoid bitrot and enable usage as referenced image the svg is included. + */ + if (image.type === 'canvas') { + const content = image.getContent(); + try { + const data = JSON.parse(content); + + const svg = data.svg || '' + res.set('Content-Type', "image/svg+xml"); + res.set("Cache-Control", "no-cache, no-store, must-revalidate"); + res.send(svg); + } catch(err) { + res.status(500).send("there was an error parsing excalidraw to svg"); + } + } else { + res.set('Content-Type', image.mime); + res.set("Cache-Control", "no-cache, no-store, must-revalidate"); + res.send(image.getContent()); + } } function uploadImage(req) { diff --git a/src/routes/api/login.js b/src/routes/api/login.js index fa8685d8a..89d3ec4d7 100644 --- a/src/routes/api/login.js +++ b/src/routes/api/login.js @@ -83,6 +83,10 @@ function logoutFromProtectedSession() { ws.sendMessageToAllClients({ type: 'protectedSessionLogout' }); } +function touchProtectedSession() { + protectedSessionService.touchProtectedSession(); +} + function token(req) { const password = req.body.password; @@ -92,7 +96,7 @@ function token(req) { // for backwards compatibility with Sender which does not send the name const tokenName = req.body.tokenName || "Trilium Sender / Web Clipper"; - + const {authToken} = etapiTokenService.createToken(tokenName); return { token: authToken }; @@ -102,5 +106,6 @@ module.exports = { loginSync, loginToProtectedSession, logoutFromProtectedSession, + touchProtectedSession, token }; diff --git a/src/routes/routes.js b/src/routes/routes.js index f899e4f7d..b51f1a521 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -285,6 +285,7 @@ function register(app) { apiRoute(POST, '/api/special-notes/search-note', specialNotesRoute.createSearchNote); apiRoute(POST, '/api/special-notes/save-search-note', specialNotesRoute.saveSearchNote); + // :filename is not used by trilium, but instead used for "save as" to assign a human readable filename route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage); route(POST, '/api/images', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.uploadImage, apiResultHandler); route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.updateImage, apiResultHandler); @@ -358,6 +359,7 @@ function register(app) { route(POST, '/api/login/sync', [], loginApiRoute.loginSync, apiResultHandler); // this is for entering protected mode so user has to be already logged-in (that's the reason we don't require username) apiRoute(POST, '/api/login/protected', loginApiRoute.loginToProtectedSession); + apiRoute(POST, '/api/login/protected/touch', loginApiRoute.touchProtectedSession); apiRoute(POST, '/api/logout/protected', loginApiRoute.logoutFromProtectedSession); route(POST, '/api/login/token', [], loginApiRoute.token, apiResultHandler); diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js index 757c067bb..dadc40c6a 100644 --- a/src/services/backend_script_api.js +++ b/src/services/backend_script_api.js @@ -210,7 +210,7 @@ function BackendScriptApi(currentNote, apiParams) { * @property {string} parentNoteId - MANDATORY * @property {string} title - MANDATORY * @property {string|buffer} content - MANDATORY - * @property {string} type - text, code, file, image, search, book, relation-map - MANDATORY + * @property {string} type - text, code, file, image, search, book, relation-map, canvas - MANDATORY * @property {string} mime - value is derived from default mimes for type * @property {boolean} isProtected - default is false * @property {boolean} isExpanded - default is false diff --git a/src/services/entity_changes.js b/src/services/entity_changes.js index 209e0c7f5..62eabc944 100644 --- a/src/services/entity_changes.js +++ b/src/services/entity_changes.js @@ -135,7 +135,6 @@ function fillAllEntityChanges() { fillEntityChanges("branches", "branchId"); fillEntityChanges("note_revisions", "noteRevisionId"); fillEntityChanges("note_revision_contents", "noteRevisionId"); - fillEntityChanges("recent_notes", "noteId"); fillEntityChanges("attributes", "attributeId"); fillEntityChanges("etapi_tokens", "etapiTokenId"); fillEntityChanges("options", "name", 'isSynced = 1'); diff --git a/src/services/export/single.js b/src/services/export/single.js index 2937b40d7..881bb394b 100644 --- a/src/services/export/single.js +++ b/src/services/export/single.js @@ -41,7 +41,7 @@ function exportSingleNote(taskContext, branch, format, res) { extension = mimeTypes.extension(note.mime) || 'code'; mime = note.mime; } - else if (note.type === 'relation-map' || note.type === 'search') { + else if (note.type === 'relation-map' || note.type === 'canvas' || note.type === 'search') { payload = content; extension = 'json'; mime = 'application/json'; diff --git a/src/services/note_types.js b/src/services/note_types.js index 05a242c94..cdc890162 100644 --- a/src/services/note_types.js +++ b/src/services/note_types.js @@ -7,6 +7,7 @@ module.exports = [ 'search', 'relation-map', 'book', - 'note-map', - 'mermaid' + 'note-map', + 'mermaid', + 'canvas' ]; \ No newline at end of file diff --git a/src/services/notes.js b/src/services/notes.js index 86344061b..9accb08d8 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -53,7 +53,7 @@ function deriveMime(type, mime) { mime = 'text/html'; } else if (type === 'code' || type === 'mermaid') { mime = 'text/plain'; - } else if (['relation-map', 'search'].includes(type)) { + } else if (['relation-map', 'search', 'canvas'].includes(type)) { mime = 'application/json'; } else if (['render', 'book'].includes(type)) { mime = ''; @@ -84,7 +84,7 @@ function copyChildAttributes(parentNote, childNote) { * - {string} parentNoteId * - {string} title * - {*} content - * - {string} type - text, code, file, image, search, book, relation-map, render + * - {string} type - text, code, file, image, search, book, relation-map, canvas, render * * Following are optional (have defaults) * - {string} mime - value is derived from default mimes for type diff --git a/src/services/protected_session.js b/src/services/protected_session.js index 7dfddc2df..ad125deca 100644 --- a/src/services/protected_session.js +++ b/src/services/protected_session.js @@ -2,6 +2,7 @@ const log = require('./log'); const dataEncryptionService = require('./data_encryption'); +const options = require("./options"); let dataKey = null; @@ -54,6 +55,27 @@ function decryptString(cipherText) { return dataEncryptionService.decryptString(getDataKey(), cipherText); } +let lastProtectedSessionOperationDate = null; + +function touchProtectedSession() { + if (isProtectedSessionAvailable()) { + lastProtectedSessionOperationDate = Date.now(); + } +} + +setInterval(() => { + const protectedSessionTimeout = options.getOptionInt('protectedSessionTimeout'); + if (isProtectedSessionAvailable() + && lastProtectedSessionOperationDate + && Date.now() - lastProtectedSessionOperationDate > protectedSessionTimeout * 1000) { + + resetDataKey(); + + require('./ws').reloadFrontend(); + } +}, 30000); + + module.exports = { setDataKey, resetDataKey, @@ -61,5 +83,6 @@ module.exports = { encrypt, decrypt, decryptString, - decryptNotes + decryptNotes, + touchProtectedSession }; diff --git a/src/services/search/expressions/note_content_fulltext.js b/src/services/search/expressions/note_content_fulltext.js new file mode 100644 index 000000000..548578c2b --- /dev/null +++ b/src/services/search/expressions/note_content_fulltext.js @@ -0,0 +1,116 @@ +"use strict"; + +const Expression = require('./expression'); +const NoteSet = require('../note_set'); +const log = require('../../log'); +const becca = require('../../../becca/becca'); +const protectedSessionService = require('../../protected_session'); +const striptags = require('striptags'); +const utils = require("../../utils"); + +const ALLOWED_OPERATORS = ['*=*', '=', '*=', '=*', '%=']; + +const cachedRegexes = {}; + +function getRegex(str) { + if (!(str in cachedRegexes)) { + cachedRegexes[str] = new RegExp(str, 'ms'); // multiline, dot-all + } + + return cachedRegexes[str]; +} + +class NoteContentFulltextExp extends Expression { + constructor(operator, {tokens, raw, flatText}) { + super(); + + if (!ALLOWED_OPERATORS.includes(operator)) { + throw new Error(`Note content can be searched only with operators: ` + ALLOWED_OPERATORS.join(", ") + `, operator ${operator} given.`); + } + + this.operator = operator; + this.tokens = tokens; + this.raw = !!raw; + this.flatText = !!flatText; + } + + execute(inputNoteSet) { + const resultNoteSet = new NoteSet(); + const sql = require('../../sql'); + + for (let {noteId, type, mime, content, isProtected} of sql.iterateRows(` + SELECT noteId, type, mime, content, isProtected + FROM notes JOIN note_contents USING (noteId) + WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0`)) { + + if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) { + continue; + } + + if (isProtected) { + if (!protectedSessionService.isProtectedSessionAvailable()) { + continue; + } + + try { + content = protectedSessionService.decryptString(content); + } catch (e) { + log.info(`Cannot decrypt content of note ${noteId}`); + continue; + } + } + + content = this.preprocessContent(content, type, mime); + + if (this.tokens.length === 1) { + const [token] = this.tokens; + + if ((this.operator === '=' && token === content) + || (this.operator === '*=' && content.endsWith(token)) + || (this.operator === '=*' && content.startsWith(token)) + || (this.operator === '*=*' && content.includes(token)) + || (this.operator === '%=' && getRegex(token).test(content))) { + + resultNoteSet.add(becca.notes[noteId]); + } + } + else { + const nonMatchingToken = this.tokens.find(token => + !content.includes(token) && + ( + // in case of default fulltext search we should consider both title, attrs and content + // so e.g. "hello world" should match when "hello" is in title and "world" in content + !this.flatText + || !becca.notes[noteId].getFlatText().includes(token) + ) + ); + + if (!nonMatchingToken) { + resultNoteSet.add(becca.notes[noteId]); + } + } + } + + return resultNoteSet; + } + + preprocessContent(content, type, mime) { + content = utils.normalize(content.toString()); + + if (type === 'text' && mime === 'text/html') { + if (!this.raw && content.length < 20000) { // striptags is slow for very large notes + // allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412 + content = striptags(content, ['a']); + + // at least the closing tag can be easily stripped + content = content.replace(/<\/a>/ig, ""); + } + + content = content.replace(/ /g, ' '); + } + + return content.trim(); + } +} + +module.exports = NoteContentFulltextExp; diff --git a/src/services/search/expressions/note_content_protected_fulltext.js b/src/services/search/expressions/note_content_protected_fulltext.js deleted file mode 100644 index 05130e087..000000000 --- a/src/services/search/expressions/note_content_protected_fulltext.js +++ /dev/null @@ -1,89 +0,0 @@ -"use strict"; - -const Expression = require('./expression'); -const NoteSet = require('../note_set'); -const log = require('../../log'); -const becca = require('../../../becca/becca'); -const protectedSessionService = require('../../protected_session'); -const striptags = require('striptags'); -const utils = require("../../utils"); - -// FIXME: create common subclass with NoteContentUnprotectedFulltextExp to avoid duplication -class NoteContentProtectedFulltextExp extends Expression { - constructor(operator, {tokens, raw, flatText}) { - super(); - - if (operator !== '*=*') { - throw new Error(`Note content can be searched only with *=* operator`); - } - - this.tokens = tokens; - this.raw = !!raw; - this.flatText = !!flatText; - } - - execute(inputNoteSet) { - const resultNoteSet = new NoteSet(); - - if (!protectedSessionService.isProtectedSessionAvailable()) { - return resultNoteSet; - } - - const sql = require('../../sql'); - - for (let {noteId, type, mime, content} of sql.iterateRows(` - SELECT noteId, type, mime, content - FROM notes JOIN note_contents USING (noteId) - WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0 AND isProtected = 1`)) { - - if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) { - continue; - } - - try { - content = protectedSessionService.decryptString(content); - } - catch (e) { - log.info(`Cannot decrypt content of note ${noteId}`); - continue; - } - - content = this.preprocessContent(content, type, mime); - - const nonMatchingToken = this.tokens.find(token => - !content.includes(token) && - ( - // in case of default fulltext search we should consider both title, attrs and content - // so e.g. "hello world" should match when "hello" is in title and "world" in content - !this.flatText - || !becca.notes[noteId].getFlatText().includes(token) - ) - ); - - if (!nonMatchingToken) { - resultNoteSet.add(becca.notes[noteId]); - } - } - - return resultNoteSet; - } - - preprocessContent(content, type, mime) { - content = utils.normalize(content.toString()); - - if (type === 'text' && mime === 'text/html') { - if (!this.raw && content.length < 20000) { // striptags is slow for very large notes - // allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412 - content = striptags(content, ['a']); - - // at least the closing tag can be easily stripped - content = content.replace(/<\/a>/ig, ""); - } - - content = content.replace(/ /g, ' '); - } - return content; - } -} - -module.exports = NoteContentProtectedFulltextExp; diff --git a/src/services/search/expressions/note_content_unprotected_fulltext.js b/src/services/search/expressions/note_content_unprotected_fulltext.js deleted file mode 100644 index 7abbd0d78..000000000 --- a/src/services/search/expressions/note_content_unprotected_fulltext.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; - -const Expression = require('./expression'); -const NoteSet = require('../note_set'); -const becca = require('../../../becca/becca'); -const striptags = require('striptags'); -const utils = require("../../utils"); - -// FIXME: create common subclass with NoteContentProtectedFulltextExp to avoid duplication -class NoteContentUnprotectedFulltextExp extends Expression { - constructor(operator, {tokens, raw, flatText}) { - super(); - - if (operator !== '*=*') { - throw new Error(`Note content can be searched only with *=* operator`); - } - - this.tokens = tokens; - this.raw = !!raw; - this.flatText = !!flatText; - } - - execute(inputNoteSet) { - const resultNoteSet = new NoteSet(); - - const sql = require('../../sql'); - - for (let {noteId, type, mime, content} of sql.iterateRows(` - SELECT noteId, type, mime, content - FROM notes JOIN note_contents USING (noteId) - WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0 AND isProtected = 0`)) { - - if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) { - continue; - } - - content = this.preprocessContent(content, type, mime); - - const nonMatchingToken = this.tokens.find(token => - !content.includes(token) && - ( - // in case of default fulltext search we should consider both title, attrs and content - // so e.g. "hello world" should match when "hello" is in title and "world" in content - !this.flatText - || !becca.notes[noteId].getFlatText().includes(token) - ) - ); - - if (!nonMatchingToken) { - resultNoteSet.add(becca.notes[noteId]); - } - } - - return resultNoteSet; - } - - preprocessContent(content, type, mime) { - content = utils.normalize(content.toString()); - - if (type === 'text' && mime === 'text/html') { - if (!this.raw && content.length < 20000) { // striptags is slow for very large notes - // allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412 - content = striptags(content, ['a']); - - // at least the closing tag can be easily stripped - content = content.replace(/<\/a>/ig, ""); - } - - content = content.replace(/ /g, ' '); - } - return content; - } -} - -module.exports = NoteContentUnprotectedFulltextExp; diff --git a/src/services/search/services/build_comparator.js b/src/services/search/services/build_comparator.js index 561f3df66..6d3ba463a 100644 --- a/src/services/search/services/build_comparator.js +++ b/src/services/search/services/build_comparator.js @@ -1,3 +1,13 @@ +const cachedRegexes = {}; + +function getRegex(str) { + if (!(str in cachedRegexes)) { + cachedRegexes[str] = new RegExp(str); + } + + return cachedRegexes[str]; +} + const stringComparators = { "=": comparedValue => (val => val === comparedValue), "!=": comparedValue => (val => val !== comparedValue), @@ -8,6 +18,7 @@ const stringComparators = { "*=": comparedValue => (val => val && val.endsWith(comparedValue)), "=*": comparedValue => (val => val && val.startsWith(comparedValue)), "*=*": comparedValue => (val => val && val.includes(comparedValue)), + "%=": comparedValue => (val => val && !!getRegex(comparedValue).test(val)), }; const numericComparators = { diff --git a/src/services/search/services/lex.js b/src/services/search/services/lex.js index 5234900f7..c6bdc2dfd 100644 --- a/src/services/search/services/lex.js +++ b/src/services/search/services/lex.js @@ -9,7 +9,7 @@ function lex(str) { let currentWord = ''; function isSymbolAnOperator(chr) { - return ['=', '*', '>', '<', '!', "-", "+"].includes(chr); + return ['=', '*', '>', '<', '!', "-", "+", '%'].includes(chr); } function isPreviousSymbolAnOperator() { diff --git a/src/services/search/services/parse.js b/src/services/search/services/parse.js index 9ba5ce506..8ab99fe31 100644 --- a/src/services/search/services/parse.js +++ b/src/services/search/services/parse.js @@ -12,8 +12,7 @@ const PropertyComparisonExp = require('../expressions/property_comparison'); const AttributeExistsExp = require('../expressions/attribute_exists'); const LabelComparisonExp = require('../expressions/label_comparison'); const NoteFlatTextExp = require('../expressions/note_flat_text'); -const NoteContentProtectedFulltextExp = require('../expressions/note_content_protected_fulltext'); -const NoteContentUnprotectedFulltextExp = require('../expressions/note_content_unprotected_fulltext'); +const NoteContentFulltextExp = require('../expressions/note_content_fulltext.js'); const OrderByAndLimitExp = require('../expressions/order_by_and_limit'); const AncestorExp = require("../expressions/ancestor"); const buildComparator = require('./build_comparator'); @@ -32,8 +31,7 @@ function getFulltext(tokens, searchContext) { if (!searchContext.fastSearch) { return new OrExp([ new NoteFlatTextExp(tokens), - new NoteContentProtectedFulltextExp('*=*', {tokens, flatText: true}), - new NoteContentUnprotectedFulltextExp('*=*', {tokens, flatText: true}) + new NoteContentFulltextExp('*=*', {tokens, flatText: true}) ]); } else { @@ -42,7 +40,7 @@ function getFulltext(tokens, searchContext) { } function isOperator(str) { - return str.match(/^[!=<>*]+$/); + return str.match(/^[!=<>*%]+$/); } function getExpression(tokens, searchContext, level = 0) { @@ -140,10 +138,7 @@ function getExpression(tokens, searchContext, level = 0) { i++; - return new OrExp([ - new NoteContentUnprotectedFulltextExp(operator, {tokens: [tokens[i].token], raw }), - new NoteContentProtectedFulltextExp(operator, {tokens: [tokens[i].token], raw }) - ]); + return new NoteContentFulltextExp(operator, {tokens: [tokens[i].token], raw }); } if (tokens[i].token === 'parents') { @@ -196,8 +191,7 @@ function getExpression(tokens, searchContext, level = 0) { return new OrExp([ new PropertyComparisonExp(searchContext, 'title', '*=*', tokens[i].token), - new NoteContentProtectedFulltextExp('*=*', {tokens: [tokens[i].token]}), - new NoteContentUnprotectedFulltextExp('*=*', {tokens: [tokens[i].token]}) + new NoteContentFulltextExp('*=*', {tokens: [tokens[i].token]}) ]); } diff --git a/src/services/utils.js b/src/services/utils.js index f4f31c69e..85b719d01 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -168,7 +168,7 @@ const STRING_MIME_TYPES = [ function isStringNote(type, mime) { // render and book are string note in the sense that they are expected to contain empty string - return ["text", "code", "relation-map", "search", "render", "book", "mermaid"].includes(type) + return ["text", "code", "relation-map", "search", "render", "book", "mermaid", "canvas"].includes(type) || mime.startsWith('text/') || STRING_MIME_TYPES.includes(mime); } @@ -192,7 +192,7 @@ function formatDownloadTitle(filename, type, mime) { if (type === 'text') { return filename + '.html'; - } else if (['relation-map', 'search'].includes(type)) { + } else if (['relation-map', 'canvas', 'search'].includes(type)) { return filename + '.json'; } else { if (!mime) { diff --git a/src/share/canvas_share.js b/src/share/canvas_share.js new file mode 100644 index 000000000..70da159a0 --- /dev/null +++ b/src/share/canvas_share.js @@ -0,0 +1,102 @@ +/** + * this is used as a "standalone js" file and required by a shared note directly via script-tags + * + * data input comes via window variable as follow + * const {elements, appState, files} = window.triliumExcalidraw; + */ + +document.getElementById("excalidraw-app").style.height = appState.height+"px"; + +const App = () => { + const excalidrawRef = React.useRef(null); + const excalidrawWrapperRef = React.useRef(null); + const [dimensions, setDimensions] = React.useState({ + width: undefined, + height: appState.height, + }); + const [viewModeEnabled, setViewModeEnabled] = React.useState(false); + + // ensure that assets are loaded from trilium + + /** + * resizing + */ + React.useEffect(() => { + const dimensions = { + width: excalidrawWrapperRef.current.getBoundingClientRect().width, + height: excalidrawWrapperRef.current.getBoundingClientRect().height + }; + setDimensions(dimensions); + + const onResize = () => { + const dimensions = { + width: excalidrawWrapperRef.current.getBoundingClientRect().width, + height: excalidrawWrapperRef.current.getBoundingClientRect().height + }; + setDimensions(dimensions); + }; + + window.addEventListener("resize", onResize); + // ensure that resize is also called for split creation and deletion + // not really the problem. problem is saved appState! + // self.$renderElement.addEventListener("resize", onResize); + + return () => window.removeEventListener("resize", onResize); + }, [excalidrawWrapperRef]); + + return React.createElement( + React.Fragment, + null, + React.createElement( + "div", + { + className: "excalidraw-wrapper", + ref: excalidrawWrapperRef + }, + React.createElement(Excalidraw.default, { + ref: excalidrawRef, + width: dimensions.width, + height: dimensions.height, + initialData: { + elements, appState, files + }, + viewModeEnabled: !viewModeEnabled, + zenModeEnabled: false, + gridModeEnabled: false, + isCollaborating: false, + detectScroll: false, + handleKeyboardGlobally: false, + autoFocus: true, + renderFooter: () => { + return React.createElement( + React.Fragment, + null, + React.createElement( + "div", + { + className: "excalidraw-top-right-ui excalidraw Island", + }, + React.createElement( + "label", + { + style: { + padding: "5px", + }, + className: "excalidraw Stack", + }, + React.createElement( + "button", + { + onClick: () => setViewModeEnabled(!viewModeEnabled) + }, + viewModeEnabled ? " Enter simple view mode " : " Enter extended view mode " + ), + "" + ), + )); + }, + }) + ) + ); +}; +ReactDOM.render(React.createElement(App), document.getElementById("excalidraw-app")); diff --git a/src/share/content_renderer.js b/src/share/content_renderer.js index 3ff390bc5..6584b4b23 100644 --- a/src/share/content_renderer.js +++ b/src/share/content_renderer.js @@ -85,6 +85,38 @@ document.addEventListener("DOMContentLoaded", function() { else if (note.type === 'book') { isEmpty = true; } + else if (note.type === 'canvas') { + header += ``; + header += ``; + header += ``; + header += ``; + header += ``; + + content = `
+ +
+
+ Get Image Link + +
`; + } else { content = '

This note type cannot be displayed.

'; } @@ -99,7 +131,3 @@ document.addEventListener("DOMContentLoaded", function() { module.exports = { getContent }; - - - - diff --git a/src/share/routes.js b/src/share/routes.js index 917e66d14..ce858ad6b 100644 --- a/src/share/routes.js +++ b/src/share/routes.js @@ -1,3 +1,6 @@ +const express = require('express'); +const path = require('path'); + const shaca = require("./shaca/shaca"); const shacaLoader = require("./shaca/shaca_loader"); const shareRoot = require("./share_root"); @@ -55,6 +58,8 @@ function register(router) { }); } + router.use('/share/canvas_share.js', express.static(path.join(__dirname, 'canvas_share.js'))); + router.get(['/share', '/share/'], (req, res, next) => { shacaLoader.ensureLoad(); @@ -110,6 +115,7 @@ function register(router) { res.send(note.getContent()); }); + // :filename is not used by trilium, but instead used for "save as" to assign a human readable filename router.get('/share/api/images/:noteId/:filename', (req, res, next) => { shacaLoader.ensureLoad(); @@ -118,15 +124,31 @@ function register(router) { if (!image) { return res.status(404).send(`Note '${req.params.noteId}' not found`); } - else if (image.type !== 'image') { - return res.status(400).send("Requested note is not an image"); + else if (!["image", "canvas"].includes(image.type)) { + return res.status(400).send("Requested note is not a shareable image"); + } else if (image.type === "canvas") { + /** + * special "image" type. the canvas is actually type application/json + * to avoid bitrot and enable usage as referenced image the svg is included. + */ + const content = image.getContent(); + try { + const data = JSON.parse(content); + + const svg = data.svg || ''; + addNoIndexHeader(image, res); + res.set('Content-Type', "image/svg+xml"); + res.set("Cache-Control", "no-cache, no-store, must-revalidate"); + res.send(svg); + } catch(err) { + res.status(500).send("there was an error parsing excalidraw to svg"); + } + } else { + // normal image + res.set('Content-Type', image.mime); + addNoIndexHeader(image, res); + res.send(image.getContent()); } - - addNoIndexHeader(image, res); - - res.setHeader('Content-Type', image.mime); - - res.send(image.getContent()); }); // used for PDF viewing diff --git a/trilium.iml b/trilium.iml index 6905b014e..cffe441d0 100644 --- a/trilium.iml +++ b/trilium.iml @@ -13,9 +13,10 @@ + - + \ No newline at end of file