You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2026-01-29 07:46:13 +02:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
051d628250 | ||
|
|
d8f365834b | ||
|
|
6dc6acc644 | ||
|
|
30e1164df9 | ||
|
|
a8821dfcb5 | ||
|
|
54b15a1917 | ||
|
|
e2d27275db | ||
|
|
b90cb89e0f | ||
|
|
a6516c5f14 | ||
|
|
249a744e9d |
@@ -225,7 +225,6 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.j
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
|
||||
@@ -357,7 +356,6 @@ packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
|
||||
2
.github/workflows/cla.yml
vendored
2
.github/workflows/cla.yml
vendored
@@ -33,5 +33,5 @@ jobs:
|
||||
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
|
||||
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
|
||||
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
|
||||
lock-pullrequest-aftermerge: false
|
||||
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
|
||||
#use-dco-flag: true - If you are using DCO instead of CLA
|
||||
|
||||
32
.github/workflows/github-actions-main.yml
vendored
32
.github/workflows/github-actions-main.yml
vendored
@@ -176,35 +176,3 @@ jobs:
|
||||
# Basic test to ensure that the created build is valid. It should exit with
|
||||
# code 0 if it works.
|
||||
docker run joplin/server:0.0.0-beta node dist/app.js migrate list
|
||||
|
||||
- name: Check HTTP request
|
||||
run: |
|
||||
# Need to pass environment variables:
|
||||
docker run -p 22300:22300 joplin/server:0.0.0-beta node dist/app.js --env dev &
|
||||
|
||||
# Wait for server to start
|
||||
sleep 10
|
||||
|
||||
# Check if status code is correct
|
||||
# if the actual_status DOES NOT include the expected_status
|
||||
# it exits the process with code 1
|
||||
|
||||
expected_status="HTTP/1.1 200 OK"
|
||||
actual_status=$(curl -I -X GET http://localhost:22300/api/ping | head -n 1)
|
||||
if [[ ! "$actual_status" =~ "$expected_status" ]]; then
|
||||
echo 'Failed while checking the status code after request to /api/ping'
|
||||
echo 'expected: ' $expected_status
|
||||
echo 'actual: ' $actual_status
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Check if the body response is correct
|
||||
# if the actual_body is different of expected_body exit with code 1
|
||||
expected_body='{"status":"ok","message":"Joplin Server is running"}'
|
||||
actual_body=$(curl http://localhost:22300/api/ping)
|
||||
|
||||
if [[ "$actual_body" != "$expected_body" ]]; then
|
||||
echo 'Failed while checking the body response after request to /api/ping'
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -210,7 +210,6 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.j
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
|
||||
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
|
||||
@@ -342,7 +341,6 @@ packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.js
|
||||
packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/utils/markupLanguageUtils.js
|
||||
packages/app-mobile/PluginAssetsLoader.js
|
||||
packages/app-mobile/components/ActionButton.js
|
||||
|
||||
@@ -36,7 +36,7 @@ index 6afcbbf0cc8ca2d69dd78077d61e59a90b2136bb..9f8d72b4ec5b2b3d290975d6a255917c
|
||||
def kotlin_version = getExtOrDefault('kotlinVersion')
|
||||
|
||||
diff --git a/android/src/main/java/com/reactnativevosk/VoskModule.kt b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4e3ff404a 100644
|
||||
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..f3da440bc2863a59db6d2d1691c54d8d4870cb3f 100644
|
||||
--- a/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||
+++ b/android/src/main/java/com/reactnativevosk/VoskModule.kt
|
||||
@@ -19,13 +19,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
@@ -66,25 +66,7 @@ index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4
|
||||
sendEvent("onResult", text)
|
||||
}
|
||||
}
|
||||
@@ -93,12 +105,11 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
@ReactMethod
|
||||
fun loadModel(path: String, promise: Promise) {
|
||||
cleanModel();
|
||||
- StorageService.unpack(context, path, "models",
|
||||
- { model: Model? ->
|
||||
- this.model = model
|
||||
- promise.resolve("Model successfully loaded")
|
||||
- }
|
||||
- ) { e: IOException ->
|
||||
+
|
||||
+ try {
|
||||
+ this.model = Model(path);
|
||||
+ promise.resolve("Model successfully loaded")
|
||||
+ } catch (e: IOException) {
|
||||
this.model = null
|
||||
promise.reject(e)
|
||||
}
|
||||
@@ -153,6 +164,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
@@ -153,6 +165,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
|
||||
cleanRecognizer();
|
||||
}
|
||||
|
||||
|
||||
@@ -353,43 +353,5 @@
|
||||
"web/bundles/": true,
|
||||
"web/env.php": true,
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "transpile-server",
|
||||
"type": "shell",
|
||||
"command": "cd ${workspaceFolder}/packages/server && yarn tsc",
|
||||
"group": "build",
|
||||
}
|
||||
]
|
||||
},
|
||||
"launch": {
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Server",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "transpile-server",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/**/*.js",
|
||||
"!**/node_modules/**"
|
||||
],
|
||||
"program": "${workspaceFolder}/packages/server/src/app.ts",
|
||||
"args": [
|
||||
"--env", "dev"
|
||||
],
|
||||
"env": {
|
||||
"JOPLIN_IS_TESTING": "1",
|
||||
"TERMS_URL": "https://example.com",
|
||||
"PRIVACY_URL": "https://example.com",
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<a data-from-md title='<style>' href='&#x22&#x2c&#x22&#x61&#x22&#x29&#x3b&#x74&#x6f&#x70&#x2e&#x72&#x65&#x71&#x75&#x69&#x72&#x65&#x28&#x27&#x63&#x68&#x69&#x6c&#x64&#x5f&#x70&#x72&#x6f&#x63&#x65&#x73&#x73&#x27&#x29&#x2e&#x65&#x78&#x65&#x63&#x28&#x27&#x6f&#x70&#x65&#x6e&#x20&#x2f&#x53&#x79&#x73&#x74&#x65&#x6d&#x2f&#x41&#x70&#x70&#x6c&#x69&#x63&#x61&#x74&#x69&#x6f&#x6e&#x73&#x2f&#x43&#x61&#x6c&#x63&#x75&#x6c&#x61&#x74&#x6f&#x72&#x2e&#x61&#x70&#x70&#x27&#x29&#x3b&#x2f&#x2f' onclick='postMessage("&#x22&#x2c&#x22&#x61&#x22&#x29&#x3b&#x74&#x6f&#x70&#x2e&#x72&#x65&#x71&#x75&#x69&#x72&#x65&#x28&#x27&#x63&#x68&#x69&#x6c&#x64&#x5f&#x70&#x72&#x6f&#x63&#x65&#x73&#x73&#x27&#x29&#x2e&#x65&#x78&#x65&#x63&#x28&#x27&#x6f&#x70&#x65&#x6e&#x20&#x2f&#x53&#x79&#x73&#x74&#x65&#x6d&#x2f&#x41&#x70&#x70&#x6c&#x69&#x63&#x61&#x74&#x69&#x6f&#x6e&#x73&#x2f&#x43&#x61&#x6c&#x63&#x75&#x6c&#x61&#x74&#x6f&#x72&#x2e&#x61&#x70&#x70&#x27&#x29&#x3b&#x2f&#x2f", { resourceId: "" }); return false;'>xxxxx</a>
|
||||
@@ -1 +0,0 @@
|
||||
[xxxxx](","a");top.require('child_process').exec('open /System/Applications/Calculator.app');// '<style>')
|
||||
@@ -34,7 +34,7 @@ import ShareFolderDialog from '../ShareFolderDialog/ShareFolderDialog';
|
||||
import { ShareInvitation } from '@joplin/lib/services/share/reducer';
|
||||
import removeKeylessItems from '../ResizableLayout/utils/removeKeylessItems';
|
||||
import { localSyncInfoFromState } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
import { isCallbackUrl, parseCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
||||
import { parseCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
||||
import ElectronAppWrapper from '../../ElectronAppWrapper';
|
||||
import { showMissingMasterKeyMessage } from '@joplin/lib/services/e2ee/utils';
|
||||
import { MasterKeyEntity } from '@joplin/lib/services/e2ee/types';
|
||||
@@ -173,7 +173,6 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
private openCallbackUrl(url: string) {
|
||||
if (!isCallbackUrl(url)) throw new Error(`Invalid callback URL: ${url}`);
|
||||
const { command, params } = parseCallbackUrl(url);
|
||||
void CommandService.instance().execute(command.toString(), params.id);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import { loadScript } from '../../../utils/loadScript';
|
||||
import bridge from '../../../../services/bridge';
|
||||
import { TinyMceEditorEvents } from './utils/types';
|
||||
import type { Editor } from 'tinymce';
|
||||
import { joplinCommandToTinyMceCommands, TinyMceCommand } from './utils/joplinCommandToTinyMceCommands';
|
||||
const { clipboard } = require('electron');
|
||||
const supportedLocales = require('./supportedLocales');
|
||||
|
||||
@@ -79,6 +78,23 @@ function stripMarkup(markupLanguage: number, markup: string, options: any = null
|
||||
return markupToHtml_.stripMarkup(markupLanguage, markup, options);
|
||||
}
|
||||
|
||||
interface TinyMceCommand {
|
||||
name: string;
|
||||
value?: any;
|
||||
ui?: boolean;
|
||||
}
|
||||
|
||||
interface JoplinCommandToTinyMceCommands {
|
||||
[key: string]: TinyMceCommand;
|
||||
}
|
||||
|
||||
const joplinCommandToTinyMceCommands: JoplinCommandToTinyMceCommands = {
|
||||
'textBold': { name: 'mceToggleFormat', value: 'bold' },
|
||||
'textItalic': { name: 'mceToggleFormat', value: 'italic' },
|
||||
'textLink': { name: 'mceLink' },
|
||||
'search': { name: 'SearchReplace' },
|
||||
};
|
||||
|
||||
interface LastOnChangeEventInfo {
|
||||
content: string;
|
||||
resourceInfos: ResourceInfos;
|
||||
@@ -258,17 +274,11 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (joplinCommandToTinyMceCommands[cmd.name] === true) {
|
||||
// Already handled in useWindowCommandHandlers.ts
|
||||
} else if (joplinCommandToTinyMceCommands[cmd.name] === false) {
|
||||
// Explicitely not supported
|
||||
} else {
|
||||
const tinyMceCmd: TinyMceCommand = { ...(joplinCommandToTinyMceCommands[cmd.name] as TinyMceCommand) };
|
||||
if (!('ui' in tinyMceCmd)) tinyMceCmd.ui = false;
|
||||
if (!('value' in tinyMceCmd)) tinyMceCmd.value = null;
|
||||
const tinyMceCmd: TinyMceCommand = { ...joplinCommandToTinyMceCommands[cmd.name] };
|
||||
if (!('ui' in tinyMceCmd)) tinyMceCmd.ui = false;
|
||||
if (!('value' in tinyMceCmd)) tinyMceCmd.value = null;
|
||||
|
||||
editor.execCommand(tinyMceCmd.name, tinyMceCmd.ui, tinyMceCmd.value);
|
||||
}
|
||||
editor.execCommand(tinyMceCmd.name, tinyMceCmd.ui, tinyMceCmd.value);
|
||||
|
||||
return true;
|
||||
},
|
||||
@@ -593,15 +603,11 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
joplinSup: { inline: 'sup', remove: 'all' },
|
||||
},
|
||||
setup: (editor: Editor) => {
|
||||
editor.addCommand('joplinAttach', () => {
|
||||
insertResourcesIntoContentRef.current();
|
||||
});
|
||||
|
||||
editor.ui.registry.addButton('joplinAttach', {
|
||||
tooltip: _('Attach file'),
|
||||
icon: 'paperclip',
|
||||
onAction: async function() {
|
||||
editor.execCommand('joplinAttach');
|
||||
insertResourcesIntoContentRef.current();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
export interface TinyMceCommand {
|
||||
name: string;
|
||||
value?: any;
|
||||
ui?: boolean;
|
||||
}
|
||||
|
||||
interface JoplinCommandToTinyMceCommands {
|
||||
[key: string]: TinyMceCommand | boolean;
|
||||
}
|
||||
|
||||
// If the mapping is simply `true` it means that the command is supported via
|
||||
// useWindowCommandHandlers.ts. We still add it here to have the complete list
|
||||
// of supported commands.
|
||||
export const joplinCommandToTinyMceCommands: JoplinCommandToTinyMceCommands = {
|
||||
'textBold': { name: 'mceToggleFormat', value: 'bold' },
|
||||
'textItalic': { name: 'mceToggleFormat', value: 'italic' },
|
||||
'textCode': { name: 'mceToggleFormat', value: 'code' },
|
||||
'textLink': { name: 'mceLink' },
|
||||
'search': { name: 'SearchReplace' },
|
||||
'attachFile': { name: 'joplinAttach' },
|
||||
'insertDateTime': true,
|
||||
};
|
||||
@@ -4,7 +4,6 @@ import editorCommandDeclarations from '../editorCommandDeclarations';
|
||||
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import time from '@joplin/lib/time';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import { joplinCommandToTinyMceCommands } from '../NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands';
|
||||
|
||||
const commandsWithDependencies = [
|
||||
require('../commands/showLocalSearch'),
|
||||
@@ -25,8 +24,6 @@ interface HookDependencies {
|
||||
}
|
||||
|
||||
function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, setFormNote: Function): CommandRuntime {
|
||||
const markdownEditorOnly = !Object.keys(joplinCommandToTinyMceCommands).includes(declaration.name);
|
||||
|
||||
return {
|
||||
execute: async (_context: CommandContext, ...args: any[]) => {
|
||||
if (!editorRef.current) {
|
||||
@@ -68,7 +65,7 @@ function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, s
|
||||
// currently selected text.
|
||||
//
|
||||
// https://github.com/laurent22/joplin/issues/5707
|
||||
enabledCondition: `(!modalDialogVisible || gotoAnythingVisible) ${markdownEditorOnly ? '&& markdownEditorPaneVisible' : ''} && oneNoteSelected && noteIsMarkdown`,
|
||||
enabledCondition: '(!modalDialogVisible || gotoAnythingVisible) && markdownEditorPaneVisible && oneNoteSelected && noteIsMarkdown',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.11.11",
|
||||
"version": "2.11.9",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
@@ -117,6 +117,7 @@
|
||||
"@types/styled-components": "5.1.26",
|
||||
"electron": "19.1.4",
|
||||
"electron-builder": "22.11.7",
|
||||
"electron-notarize": "1.2.2",
|
||||
"electron-rebuild": "3.2.9",
|
||||
"glob": "8.1.0",
|
||||
"gulp": "4.0.2",
|
||||
@@ -133,7 +134,6 @@
|
||||
"7zip-bin-win": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/notarize": "1.2.4",
|
||||
"@electron/remote": "2.0.9",
|
||||
"@fortawesome/fontawesome-free": "5.15.4",
|
||||
"@joeattardi/emoji-button": "4.6.4",
|
||||
@@ -162,7 +162,7 @@
|
||||
"react": "18.2.0",
|
||||
"react-datetime": "3.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-redux": "8.0.7",
|
||||
"react-redux": "8.0.5",
|
||||
"react-select": "5.7.3",
|
||||
"react-toggle-button": "2.2.0",
|
||||
"react-tooltip": "4.5.1",
|
||||
@@ -171,7 +171,7 @@
|
||||
"roboto-fontface": "0.10.0",
|
||||
"smalltalk": "2.5.1",
|
||||
"sqlite3": "5.1.6",
|
||||
"styled-components": "5.3.11",
|
||||
"styled-components": "5.3.10",
|
||||
"styled-system": "5.1.5",
|
||||
"taboverride": "4.0.3",
|
||||
"tinymce": "5.10.6"
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { notarize } from '@electron/notarize';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const electron_notarize = require('electron-notarize');
|
||||
const execCommand = require('./execCommand');
|
||||
|
||||
function isDesktopAppTag(tagName: string) {
|
||||
function isDesktopAppTag(tagName) {
|
||||
if (!tagName) return false;
|
||||
return tagName[0] === 'v';
|
||||
}
|
||||
|
||||
interface Params {
|
||||
appOutDir: string;
|
||||
packager: {
|
||||
appInfo: {
|
||||
productFilename: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default async (params: Params) => {
|
||||
module.exports = async function(params) {
|
||||
if (process.platform !== 'darwin') return;
|
||||
|
||||
console.info('Checking if notarization should be done...');
|
||||
@@ -35,8 +26,8 @@ export default async (params: Params) => {
|
||||
// Same appId in electron-builder.
|
||||
const appId = 'net.cozic.joplin-desktop';
|
||||
|
||||
const appPath = join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
|
||||
if (!existsSync(appPath)) {
|
||||
const appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
|
||||
if (!fs.existsSync(appPath)) {
|
||||
throw new Error(`Cannot find application at: ${appPath}`);
|
||||
}
|
||||
|
||||
@@ -49,7 +40,7 @@ export default async (params: Params) => {
|
||||
}, 60000);
|
||||
|
||||
try {
|
||||
await notarize({
|
||||
await electron_notarize.notarize({
|
||||
appBundleId: appId,
|
||||
appPath: appPath,
|
||||
|
||||
@@ -67,12 +58,7 @@ export default async (params: Params) => {
|
||||
// Use this to get it:
|
||||
//
|
||||
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
|
||||
// ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
// In our case, the team ID is the same as the legacy ASC_PROVIDER
|
||||
teamId: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
tool: 'notarytool',
|
||||
ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -0,0 +1,7 @@
|
||||
French small model for Vosk
|
||||
|
||||
WER
|
||||
|
||||
%WER 23.95 [ 37203 / 155330, 5373 ins, 4427 del, 27403 sub ] exp/chain_a/tdnn/decode_test_cv/wer_12_0.0
|
||||
%WER 19.30 [ 2975 / 15412, 683 ins, 672 del, 1620 sub ] exp/chain_a/tdnn/decode_test_mtedx/wer_10_0.0
|
||||
%WER 27.25 [ 20208 / 74145, 2647 ins, 5852 del, 11709 sub ] exp/chain_a/tdnn/decode_test_podcast_reseg/wer_10_0.0
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
--use-energy=false
|
||||
--sample-frequency=16000
|
||||
--num-mel-bins=40
|
||||
--num-ceps=40
|
||||
--low-freq=40
|
||||
--high-freq=-200
|
||||
--allow-upsample=true
|
||||
--allow-downsample=true
|
||||
@@ -0,0 +1,10 @@
|
||||
--min-active=200
|
||||
--max-active=7000
|
||||
--beam=13.0
|
||||
--lattice-beam=4.0
|
||||
--acoustic-scale=1.0
|
||||
--frame-subsampling-factor=3
|
||||
--endpoint.silence-phones=1:2:3:4:5:6:7:8:9:10
|
||||
--endpoint.rule2.min-trailing-silence=0.5
|
||||
--endpoint.rule3.min-trailing-silence=1.0
|
||||
--endpoint.rule4.min-trailing-silence=2.0
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,76 @@
|
||||
9365
|
||||
9366
|
||||
9367
|
||||
9368
|
||||
9369
|
||||
9370
|
||||
9371
|
||||
9372
|
||||
9373
|
||||
9374
|
||||
9375
|
||||
9376
|
||||
9377
|
||||
9378
|
||||
9379
|
||||
9380
|
||||
9381
|
||||
9382
|
||||
9383
|
||||
9384
|
||||
9385
|
||||
9386
|
||||
9387
|
||||
9388
|
||||
9389
|
||||
9390
|
||||
9391
|
||||
9392
|
||||
9393
|
||||
9394
|
||||
9395
|
||||
9396
|
||||
9397
|
||||
9398
|
||||
9399
|
||||
9400
|
||||
9401
|
||||
9402
|
||||
9403
|
||||
9404
|
||||
9405
|
||||
9406
|
||||
9407
|
||||
9408
|
||||
9409
|
||||
9410
|
||||
9411
|
||||
9412
|
||||
9413
|
||||
9414
|
||||
9415
|
||||
9416
|
||||
9417
|
||||
9418
|
||||
9419
|
||||
9420
|
||||
9421
|
||||
9422
|
||||
9423
|
||||
9424
|
||||
9425
|
||||
9426
|
||||
9427
|
||||
9428
|
||||
9429
|
||||
9430
|
||||
9431
|
||||
9432
|
||||
9433
|
||||
9434
|
||||
9435
|
||||
9436
|
||||
9437
|
||||
9438
|
||||
9439
|
||||
9440
|
||||
@@ -0,0 +1,154 @@
|
||||
1 nonword
|
||||
2 begin
|
||||
3 end
|
||||
4 internal
|
||||
5 singleton
|
||||
6 nonword
|
||||
7 begin
|
||||
8 end
|
||||
9 internal
|
||||
10 singleton
|
||||
11 begin
|
||||
12 end
|
||||
13 internal
|
||||
14 singleton
|
||||
15 begin
|
||||
16 end
|
||||
17 internal
|
||||
18 singleton
|
||||
19 begin
|
||||
20 end
|
||||
21 internal
|
||||
22 singleton
|
||||
23 begin
|
||||
24 end
|
||||
25 internal
|
||||
26 singleton
|
||||
27 begin
|
||||
28 end
|
||||
29 internal
|
||||
30 singleton
|
||||
31 begin
|
||||
32 end
|
||||
33 internal
|
||||
34 singleton
|
||||
35 begin
|
||||
36 end
|
||||
37 internal
|
||||
38 singleton
|
||||
39 begin
|
||||
40 end
|
||||
41 internal
|
||||
42 singleton
|
||||
43 begin
|
||||
44 end
|
||||
45 internal
|
||||
46 singleton
|
||||
47 begin
|
||||
48 end
|
||||
49 internal
|
||||
50 singleton
|
||||
51 begin
|
||||
52 end
|
||||
53 internal
|
||||
54 singleton
|
||||
55 begin
|
||||
56 end
|
||||
57 internal
|
||||
58 singleton
|
||||
59 begin
|
||||
60 end
|
||||
61 internal
|
||||
62 singleton
|
||||
63 begin
|
||||
64 end
|
||||
65 internal
|
||||
66 singleton
|
||||
67 begin
|
||||
68 end
|
||||
69 internal
|
||||
70 singleton
|
||||
71 begin
|
||||
72 end
|
||||
73 internal
|
||||
74 singleton
|
||||
75 begin
|
||||
76 end
|
||||
77 internal
|
||||
78 singleton
|
||||
79 begin
|
||||
80 end
|
||||
81 internal
|
||||
82 singleton
|
||||
83 begin
|
||||
84 end
|
||||
85 internal
|
||||
86 singleton
|
||||
87 begin
|
||||
88 end
|
||||
89 internal
|
||||
90 singleton
|
||||
91 begin
|
||||
92 end
|
||||
93 internal
|
||||
94 singleton
|
||||
95 begin
|
||||
96 end
|
||||
97 internal
|
||||
98 singleton
|
||||
99 begin
|
||||
100 end
|
||||
101 internal
|
||||
102 singleton
|
||||
103 begin
|
||||
104 end
|
||||
105 internal
|
||||
106 singleton
|
||||
107 begin
|
||||
108 end
|
||||
109 internal
|
||||
110 singleton
|
||||
111 begin
|
||||
112 end
|
||||
113 internal
|
||||
114 singleton
|
||||
115 begin
|
||||
116 end
|
||||
117 internal
|
||||
118 singleton
|
||||
119 begin
|
||||
120 end
|
||||
121 internal
|
||||
122 singleton
|
||||
123 begin
|
||||
124 end
|
||||
125 internal
|
||||
126 singleton
|
||||
127 begin
|
||||
128 end
|
||||
129 internal
|
||||
130 singleton
|
||||
131 begin
|
||||
132 end
|
||||
133 internal
|
||||
134 singleton
|
||||
135 begin
|
||||
136 end
|
||||
137 internal
|
||||
138 singleton
|
||||
139 begin
|
||||
140 end
|
||||
141 internal
|
||||
142 singleton
|
||||
143 begin
|
||||
144 end
|
||||
145 internal
|
||||
146 singleton
|
||||
147 begin
|
||||
148 end
|
||||
149 internal
|
||||
150 singleton
|
||||
151 begin
|
||||
152 end
|
||||
153 internal
|
||||
154 singleton
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
[
|
||||
1.022245e+11 -6.33291e+09 -2.480997e+09 8.290258e+09 -9.084483e+09 -8.092173e+09 -1.4735e+10 -7.041795e+09 -1.171205e+10 -2.976464e+08 -1.009425e+10 -6765179 -7.821326e+09 1.449499e+09 -6.413975e+09 -5.303802e+08 -4.998635e+09 9.521598e+07 -3.073041e+09 1.56756e+08 -1.287956e+09 1.738752e+08 -2.382392e+08 -2.716675e+07 4.404485e+08 -1.913359e+08 7.780919e+08 -4.006922e+08 7.895809e+08 -5.401082e+08 5.17605e+08 -6.227134e+08 6.58271e+08 -6.204593e+07 5.187754e+08 -4.497048e+08 4.219366e+07 -2.78742e+08 -1.797385e+07 -3.604475e+07 1.053647e+09
|
||||
1.040194e+13 6.245521e+11 4.223293e+11 6.831219e+11 6.078478e+11 6.3425e+11 7.943839e+11 6.013323e+11 6.781652e+11 5.272091e+11 5.810814e+11 4.353831e+11 4.473305e+11 3.42063e+11 3.083377e+11 2.14257e+11 1.892057e+11 1.163827e+11 8.367058e+10 4.203224e+10 2.297476e+10 7.596307e+09 1.099877e+09 2.886651e+08 3.797438e+09 9.372847e+09 1.629059e+10 2.196351e+10 2.747149e+10 3.072878e+10 3.238528e+10 3.330232e+10 3.407238e+10 3.230687e+10 2.676914e+10 2.252055e+10 1.914305e+10 1.565974e+10 1.224627e+10 8.415393e+09 0 ]
|
||||
@@ -0,0 +1,2 @@
|
||||
--left-context=3
|
||||
--right-context=3
|
||||
@@ -0,0 +1 @@
|
||||
1b7180e6-e500-4818-adc8-a41fe97a84ce
|
||||
@@ -46,7 +46,6 @@ import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import VoiceTypingDialog from '../voiceTyping/VoiceTypingDialog';
|
||||
import { voskEnabled } from '../../services/voiceTyping/vosk';
|
||||
import { isSupportedLanguage } from '../../services/voiceTyping/vosk.android';
|
||||
const urlUtils = require('@joplin/lib/urlUtils');
|
||||
|
||||
// import Vosk from 'react-native-vosk';
|
||||
@@ -1001,7 +1000,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
});
|
||||
|
||||
// Voice typing is enabled only for French language and on Android for now
|
||||
if (voskEnabled && shim.mobilePlatform() === 'android' && isSupportedLanguage(currentLocale())) {
|
||||
if (voskEnabled && shim.mobilePlatform() === 'android' && currentLocale() === 'fr_FR') {
|
||||
output.push({
|
||||
title: _('Voice typing...'),
|
||||
onPress: () => {
|
||||
@@ -1308,7 +1307,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
|
||||
const renderVoiceTypingDialog = () => {
|
||||
if (!this.state.voiceTypingDialogShown) return null;
|
||||
return <VoiceTypingDialog locale={currentLocale()} onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
||||
return <VoiceTypingDialog onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { Banner, ActivityIndicator, Modal } from 'react-native-paper';
|
||||
import { _, languageName } from '@joplin/lib/locale';
|
||||
import { Banner, ActivityIndicator } from 'react-native-paper';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import useAsyncEffect, { AsyncEffectEvent } from '@joplin/lib/hooks/useAsyncEffect';
|
||||
import { getVosk, Recorder, startRecording, Vosk } from '../../services/voiceTyping/vosk';
|
||||
import { IconSource } from 'react-native-paper/lib/typescript/src/components/Icon';
|
||||
import { modelIsDownloaded } from '../../services/voiceTyping/vosk.android';
|
||||
|
||||
interface Props {
|
||||
locale: string;
|
||||
onDismiss: ()=> void;
|
||||
onText: (text: string)=> void;
|
||||
}
|
||||
@@ -18,39 +16,30 @@ enum RecorderState {
|
||||
Recording = 2,
|
||||
Processing = 3,
|
||||
Error = 4,
|
||||
Downloading = 5,
|
||||
}
|
||||
|
||||
const useVosk = (locale: string): [Error | null, boolean, Vosk|null] => {
|
||||
const useVosk = (): [Error | null, Vosk|null] => {
|
||||
const [vosk, setVosk] = useState<Vosk>(null);
|
||||
const [error, setError] = useState<Error>(null);
|
||||
const [mustDownloadModel, setMustDownloadModel] = useState<boolean | null>(null);
|
||||
|
||||
useAsyncEffect(async (event: AsyncEffectEvent) => {
|
||||
if (mustDownloadModel === null) return;
|
||||
|
||||
try {
|
||||
const v = await getVosk(locale);
|
||||
const v = await getVosk();
|
||||
if (event.cancelled) return;
|
||||
setVosk(v);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
} finally {
|
||||
setMustDownloadModel(false);
|
||||
}
|
||||
}, [locale, mustDownloadModel]);
|
||||
}, []);
|
||||
|
||||
useAsyncEffect(async (_event: AsyncEffectEvent) => {
|
||||
setMustDownloadModel(!(await modelIsDownloaded(locale)));
|
||||
}, [locale]);
|
||||
|
||||
return [error, mustDownloadModel, vosk];
|
||||
return [error, vosk];
|
||||
};
|
||||
|
||||
export default (props: Props) => {
|
||||
const [recorder, setRecorder] = useState<Recorder>(null);
|
||||
const [recorderState, setRecorderState] = useState<RecorderState>(RecorderState.Loading);
|
||||
const [voskError, mustDownloadModel, vosk] = useVosk(props.locale);
|
||||
|
||||
const [voskError, vosk] = useVosk();
|
||||
|
||||
useEffect(() => {
|
||||
if (voskError) {
|
||||
@@ -60,12 +49,6 @@ export default (props: Props) => {
|
||||
}
|
||||
}, [vosk, voskError]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mustDownloadModel) {
|
||||
setRecorderState(RecorderState.Downloading);
|
||||
}
|
||||
}, [mustDownloadModel]);
|
||||
|
||||
useEffect(() => {
|
||||
if (recorderState === RecorderState.Recording) {
|
||||
setRecorder(startRecording(vosk, {
|
||||
@@ -77,7 +60,7 @@ export default (props: Props) => {
|
||||
}, [recorderState, vosk, props.onText]);
|
||||
|
||||
const onDismiss = useCallback(() => {
|
||||
if (recorder) recorder.cleanup();
|
||||
recorder.cleanup();
|
||||
props.onDismiss();
|
||||
}, [recorder, props.onDismiss]);
|
||||
|
||||
@@ -86,7 +69,6 @@ export default (props: Props) => {
|
||||
[RecorderState.Loading]: () => _('Loading...'),
|
||||
[RecorderState.Recording]: () => _('Please record your voice...'),
|
||||
[RecorderState.Processing]: () => _('Converting speech to text...'),
|
||||
[RecorderState.Downloading]: () => _('Downloading %s language files...', languageName(props.locale)),
|
||||
[RecorderState.Error]: () => _('Error: %s', voskError.message),
|
||||
};
|
||||
|
||||
@@ -98,7 +80,6 @@ export default (props: Props) => {
|
||||
[RecorderState.Loading]: ({ size }: { size: number }) => <ActivityIndicator animating={true} style={{ width: size, height: size }} />,
|
||||
[RecorderState.Recording]: 'microphone',
|
||||
[RecorderState.Processing]: 'microphone',
|
||||
[RecorderState.Downloading]: ({ size }: { size: number }) => <ActivityIndicator animating={true} style={{ width: size, height: size }} />,
|
||||
[RecorderState.Error]: 'alert-circle-outline',
|
||||
};
|
||||
|
||||
@@ -106,18 +87,16 @@ export default (props: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal visible={true} style={{ display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
|
||||
<Banner
|
||||
visible={true}
|
||||
icon={renderIcon()}
|
||||
actions={[
|
||||
{
|
||||
label: _('Done'),
|
||||
onPress: onDismiss,
|
||||
},
|
||||
]}>
|
||||
{`${_('Voice typing...')}\n${renderContent()}`}
|
||||
</Banner>
|
||||
</Modal>
|
||||
<Banner
|
||||
visible={true}
|
||||
icon={renderIcon()}
|
||||
actions={[
|
||||
{
|
||||
label: _('Done'),
|
||||
onPress: onDismiss,
|
||||
},
|
||||
]}>
|
||||
{`${_('Voice typing...')}\n${renderContent()}`}
|
||||
</Banner>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -347,7 +347,7 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-fingerprint-scanner (6.0.0):
|
||||
- React
|
||||
- react-native-geolocation (3.0.6):
|
||||
- react-native-geolocation (2.1.0):
|
||||
- React-Core
|
||||
- react-native-get-random-values (1.8.0):
|
||||
- React-Core
|
||||
@@ -483,15 +483,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNVectorIcons (9.2.0):
|
||||
- React-Core
|
||||
- RNZipArchive (6.0.9):
|
||||
- React-Core
|
||||
- RNZipArchive/Core (= 6.0.9)
|
||||
- SSZipArchive (~> 2.2)
|
||||
- RNZipArchive/Core (6.0.9):
|
||||
- React-Core
|
||||
- SSZipArchive (~> 2.2)
|
||||
- SocketRocket (0.6.0)
|
||||
- SSZipArchive (2.4.3)
|
||||
- Yoga (1.14.0)
|
||||
- YogaKit (1.18.1):
|
||||
- Yoga (~> 1.14)
|
||||
@@ -585,7 +577,6 @@ DEPENDENCIES:
|
||||
- RNSecureRandom (from `../node_modules/react-native-securerandom`)
|
||||
- RNShare (from `../node_modules/react-native-share`)
|
||||
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
|
||||
- RNZipArchive (from `../node_modules/react-native-zip-archive`)
|
||||
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
SPEC REPOS:
|
||||
@@ -604,7 +595,6 @@ SPEC REPOS:
|
||||
- libevent
|
||||
- OpenSSL-Universal
|
||||
- SocketRocket
|
||||
- SSZipArchive
|
||||
- YogaKit
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
@@ -734,8 +724,6 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-share"
|
||||
RNVectorIcons:
|
||||
:path: "../node_modules/react-native-vector-icons"
|
||||
RNZipArchive:
|
||||
:path: "../node_modules/react-native-zip-archive"
|
||||
Yoga:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
@@ -779,7 +767,7 @@ SPEC CHECKSUMS:
|
||||
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
|
||||
react-native-document-picker: 69ca2094d8780cfc1e7e613894d15290fdc54bba
|
||||
react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe
|
||||
react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903
|
||||
react-native-geolocation: 69f4fd37650b8e7fee91816d395e62dd16f5ab8d
|
||||
react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a
|
||||
react-native-image-picker: ec9b713e248760bfa0f879f0715391de4651a7cb
|
||||
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
|
||||
@@ -816,9 +804,7 @@ SPEC CHECKSUMS:
|
||||
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
|
||||
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
|
||||
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
|
||||
RNZipArchive: 68a0c6db4b1c103f846f1559622050df254a3ade
|
||||
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
|
||||
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
|
||||
Yoga: e7ea9e590e27460d28911403b894722354d73479
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
"@joplin/react-native-saf-x": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/datetimepicker": "7.1.0",
|
||||
"@react-native-community/geolocation": "3.0.6",
|
||||
"@react-native-community/datetimepicker": "7.0.1",
|
||||
"@react-native-community/geolocation": "2.1.0",
|
||||
"@react-native-community/netinfo": "9.3.10",
|
||||
"@react-native-community/push-notification-ios": "1.11.0",
|
||||
"@react-native-community/slider": "4.4.2",
|
||||
@@ -69,8 +69,7 @@
|
||||
"react-native-version-info": "1.1.1",
|
||||
"react-native-vosk": "0.1.12",
|
||||
"react-native-webview": "12.4.0",
|
||||
"react-native-zip-archive": "6.0.9",
|
||||
"react-redux": "8.0.7",
|
||||
"react-redux": "7.2.9",
|
||||
"redux": "4.2.1",
|
||||
"rn-fetch-blob": "0.12.0",
|
||||
"stream": "0.0.2",
|
||||
@@ -117,7 +116,7 @@
|
||||
"metro-react-native-babel-preset": "0.73.9",
|
||||
"nodemon": "2.0.22",
|
||||
"ts-jest": "29.1.0",
|
||||
"ts-loader": "9.4.3",
|
||||
"ts-loader": "9.4.2",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "5.0.2",
|
||||
"uglify-js": "3.17.4",
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
import { languageCodeOnly } from '@joplin/lib/locale';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Vosk from 'react-native-vosk';
|
||||
import { unzip } from 'react-native-zip-archive';
|
||||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
const md5 = require('md5');
|
||||
|
||||
const logger = Logger.create('voiceTyping/vosk');
|
||||
|
||||
enum State {
|
||||
Idle = 0,
|
||||
Recording,
|
||||
Completing,
|
||||
}
|
||||
|
||||
interface StartOptions {
|
||||
onResult: (text: string)=> void;
|
||||
}
|
||||
|
||||
let vosk_: Record<string, Vosk> = {};
|
||||
|
||||
let vosk_: Vosk|null = null;
|
||||
let state_: State = State.Idle;
|
||||
|
||||
export const voskEnabled = true;
|
||||
@@ -31,113 +23,12 @@ export interface Recorder {
|
||||
cleanup: ()=> void;
|
||||
}
|
||||
|
||||
const supportedLanguages = {
|
||||
'en': 'https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip',
|
||||
'cn': 'https://alphacephei.com/vosk/models/vosk-model-small-cn-0.22.zip',
|
||||
'ru': 'https://alphacephei.com/vosk/models/vosk-model-small-ru-0.22.zip',
|
||||
'fr': 'https://alphacephei.com/vosk/models/vosk-model-small-fr-0.22.zip',
|
||||
'de': 'https://alphacephei.com/vosk/models/vosk-model-small-de-0.15.zip',
|
||||
'es': 'https://alphacephei.com/vosk/models/vosk-model-small-es-0.42.zip',
|
||||
'pt': 'https://alphacephei.com/vosk/models/vosk-model-small-pt-0.3.zip',
|
||||
'tr': 'https://alphacephei.com/vosk/models/vosk-model-small-tr-0.3.zip',
|
||||
'vn': 'https://alphacephei.com/vosk/models/vosk-model-small-vn-0.4.zip',
|
||||
'it': 'https://alphacephei.com/vosk/models/vosk-model-small-it-0.22.zip',
|
||||
'nl': 'https://alphacephei.com/vosk/models/vosk-model-small-nl-0.22.zip',
|
||||
'uk': 'https://alphacephei.com/vosk/models/vosk-model-small-uk-v3-small.zip',
|
||||
'ja': 'https://alphacephei.com/vosk/models/vosk-model-small-ja-0.22.zip',
|
||||
'hi': 'https://alphacephei.com/vosk/models/vosk-model-small-hi-0.22.zip',
|
||||
'cs': 'https://alphacephei.com/vosk/models/vosk-model-small-cs-0.4-rhasspy.zip',
|
||||
'pl': 'https://alphacephei.com/vosk/models/vosk-model-small-pl-0.22.zip',
|
||||
'uz': 'https://alphacephei.com/vosk/models/vosk-model-small-uz-0.22.zip',
|
||||
'ko': 'https://alphacephei.com/vosk/models/vosk-model-small-ko-0.22.zip',
|
||||
};
|
||||
|
||||
export const isSupportedLanguage = (locale: string) => {
|
||||
const l = languageCodeOnly(locale).toLowerCase();
|
||||
return Object.keys(supportedLanguages).includes(l);
|
||||
};
|
||||
|
||||
// Where all the models files for all the languages are
|
||||
const getModelRootDir = () => {
|
||||
return `${RNFetchBlob.fs.dirs.DocumentDir}/vosk-models`;
|
||||
};
|
||||
|
||||
// Where we unzip a model after downloading it
|
||||
const getUnzipDir = (locale: string) => {
|
||||
return `${getModelRootDir()}/${locale}`;
|
||||
};
|
||||
|
||||
// Where the model for a particular language is
|
||||
const getModelDir = (locale: string) => {
|
||||
return `${getUnzipDir(locale)}/model`;
|
||||
};
|
||||
|
||||
const languageModelUrl = (locale: string) => {
|
||||
const l = languageCodeOnly(locale).toLowerCase();
|
||||
if (!(l in supportedLanguages)) throw new Error(`No language file for: ${locale}`);
|
||||
return (supportedLanguages as any)[l];
|
||||
};
|
||||
|
||||
export const modelIsDownloaded = async (locale: string) => {
|
||||
const uuidFile = `${getModelDir(locale)}/uuid`;
|
||||
return shim.fsDriver().exists(uuidFile);
|
||||
};
|
||||
|
||||
export const getVosk = async (locale: string) => {
|
||||
if (vosk_[locale]) return vosk_[locale];
|
||||
|
||||
const vosk = new Vosk();
|
||||
const modelDir = await downloadModel(locale);
|
||||
logger.info(`Loading model from ${modelDir}`);
|
||||
await shim.fsDriver().readDirStats(modelDir);
|
||||
const result = await vosk.loadModel(modelDir);
|
||||
export const getVosk = async () => {
|
||||
if (vosk_) return vosk_;
|
||||
vosk_ = new Vosk();
|
||||
const result = await vosk_.loadModel('model-fr-fr');
|
||||
logger.info('getVosk:', result);
|
||||
|
||||
vosk_ = { [locale]: vosk };
|
||||
|
||||
return vosk;
|
||||
};
|
||||
|
||||
const downloadModel = async (locale: string) => {
|
||||
const modelUrl = languageModelUrl(locale);
|
||||
const unzipDir = getUnzipDir(locale);
|
||||
const zipFilePath = `${unzipDir}.zip`;
|
||||
const modelDir = getModelDir(locale);
|
||||
const uuidFile = `${modelDir}/uuid`;
|
||||
|
||||
if (await modelIsDownloaded(locale)) {
|
||||
logger.info(`Model for ${locale} already exists at ${modelDir}`);
|
||||
return modelDir;
|
||||
}
|
||||
|
||||
await shim.fsDriver().remove(unzipDir);
|
||||
|
||||
logger.info(`Downloading model from: ${modelUrl}`);
|
||||
|
||||
await shim.fetchBlob(languageModelUrl(locale), {
|
||||
path: zipFilePath,
|
||||
});
|
||||
|
||||
logger.info(`Unzipping ${zipFilePath} => ${unzipDir}`);
|
||||
|
||||
await unzip(zipFilePath, unzipDir);
|
||||
|
||||
const dirs = await shim.fsDriver().readDirStats(unzipDir);
|
||||
if (dirs.length !== 1) {
|
||||
logger.error('Expected 1 directory but got', dirs);
|
||||
throw new Error(`Expected 1 directory, but got ${dirs.length}`);
|
||||
}
|
||||
|
||||
const fullUnzipPath = `${unzipDir}/${dirs[0].path}`;
|
||||
|
||||
logger.info(`Moving ${fullUnzipPath} => ${modelDir}`);
|
||||
await shim.fsDriver().rename(fullUnzipPath, modelDir);
|
||||
|
||||
await shim.fsDriver().writeFile(uuidFile, md5(modelUrl));
|
||||
|
||||
await shim.fsDriver().remove(zipFilePath);
|
||||
|
||||
return modelDir;
|
||||
return vosk_;
|
||||
};
|
||||
|
||||
export const startRecording = (vosk: Vosk, options: StartOptions): Recorder => {
|
||||
@@ -219,9 +110,8 @@ export const startRecording = (vosk: Vosk, options: StartOptions): Recorder => {
|
||||
});
|
||||
},
|
||||
cleanup: () => {
|
||||
if (state_ === State.Recording) {
|
||||
if (state_ !== State.Idle) {
|
||||
logger.info('Cancelling...');
|
||||
state_ = State.Completing;
|
||||
vosk.stopOnly();
|
||||
completeRecording('', null);
|
||||
}
|
||||
|
||||
@@ -13,15 +13,7 @@ export interface Recorder {
|
||||
cleanup: ()=> void;
|
||||
}
|
||||
|
||||
export const isSupportedLanguage = (_locale: string) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const modelIsDownloaded = async (_locale: string) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const getVosk = async (_locale: string) => {
|
||||
export const getVosk = async () => {
|
||||
return {} as any;
|
||||
};
|
||||
|
||||
|
||||
@@ -116,13 +116,6 @@ export default class FsDriverRN extends FsDriverBase {
|
||||
return RNFS.moveFile(source, dest);
|
||||
}
|
||||
|
||||
public async rename(source: string, dest: string) {
|
||||
if (isScopedUri(source) || isScopedUri(dest)) {
|
||||
await RNSAF.rename(source, dest);
|
||||
}
|
||||
return RNFS.moveFile(source, dest);
|
||||
}
|
||||
|
||||
public async exists(path: string) {
|
||||
if (isScopedUri(path)) {
|
||||
return RNSAF.exists(path);
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": "2.3.0",
|
||||
"domhandler": "5.0.3",
|
||||
"domhandler": "3.3.0",
|
||||
"domutils": "3.1.0",
|
||||
"entities": "2.2.0"
|
||||
},
|
||||
|
||||
@@ -3,14 +3,13 @@ import * as callbackUrlUtils from './callbackUrlUtils';
|
||||
describe('callbackUrlUtils', () => {
|
||||
|
||||
it('should identify valid callback urls', () => {
|
||||
const url = 'joplin://x-callback-url/openFolder?a=b';
|
||||
const url = 'joplin://x-callback-url/123?a=b';
|
||||
expect(callbackUrlUtils.isCallbackUrl(url)).toBe(true);
|
||||
});
|
||||
|
||||
it('should identify invalid callback urls', () => {
|
||||
expect(callbackUrlUtils.isCallbackUrl('not-joplin://x-callback-url/123?a=b')).toBe(false);
|
||||
expect(callbackUrlUtils.isCallbackUrl('joplin://xcallbackurl/123?a=b')).toBe(false);
|
||||
expect(callbackUrlUtils.isCallbackUrl('joplin://x-callback-url/invalidCommand?a=b')).toBe(false);
|
||||
});
|
||||
|
||||
it('should build valid note callback urls', () => {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
const URL = require('url-parse');
|
||||
|
||||
export function isCallbackUrl(s: string) {
|
||||
return s.startsWith('joplin://x-callback-url/openNote?') ||
|
||||
s.startsWith('joplin://x-callback-url/openFolder?') ||
|
||||
s.startsWith('joplin://x-callback-url/openTag?');
|
||||
return s.startsWith('joplin://x-callback-url/');
|
||||
}
|
||||
|
||||
export function getNoteCallbackUrl(noteId: string) {
|
||||
|
||||
@@ -508,8 +508,7 @@ function languageNameInEnglish(languageCode: string) {
|
||||
return codeToLanguageE_[languageCode] ? codeToLanguageE_[languageCode] : '';
|
||||
}
|
||||
|
||||
function languageName(canonicalName: string, defaultToEnglish: boolean = true) {
|
||||
const languageCode = languageCodeOnly(canonicalName);
|
||||
function languageName(languageCode: string, defaultToEnglish: boolean = true) {
|
||||
if (codeToLanguage_[languageCode]) return codeToLanguage_[languageCode];
|
||||
if (defaultToEnglish) return languageNameInEnglish(languageCode);
|
||||
return '';
|
||||
@@ -604,4 +603,4 @@ const stringByLocale = (locale: string, s: string, ...args: any[]): string => {
|
||||
}
|
||||
};
|
||||
|
||||
export { _, _n, supportedLocales, languageName, currentLocale, localesFromLanguageCode, languageCodeOnly, countryDisplayName, localeStrings, setLocale, supportedLocalesToLanguages, defaultLocale, closestSupportedLocale, languageCode, countryCodeOnly };
|
||||
export { _, _n, supportedLocales, currentLocale, localesFromLanguageCode, languageCodeOnly, countryDisplayName, localeStrings, setLocale, supportedLocalesToLanguages, defaultLocale, closestSupportedLocale, languageCode, countryCodeOnly };
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"jest-environment-jsdom": "29.5.0",
|
||||
"style-loader": "3.3.3",
|
||||
"ts-jest": "29.1.0",
|
||||
"ts-loader": "9.4.3",
|
||||
"ts-loader": "9.4.2",
|
||||
"typescript": "5.0.2",
|
||||
"webpack": "5.74.0",
|
||||
"webpack-cli": "4.10.0"
|
||||
@@ -44,6 +44,6 @@
|
||||
"pdfjs-dist": "2.16.105",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"styled-components": "5.3.11"
|
||||
"styled-components": "5.3.10"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ describe('linkReplacement', () => {
|
||||
|
||||
test('should handle non-resource links', () => {
|
||||
const r = linkReplacement('https://example.com/test').html;
|
||||
expect(r).toBe('<a data-from-md href=\'https://example.com/test\' onclick=\'postMessage("https://example.com/test", { resourceId: "" }); return false;\'>');
|
||||
expect(r).toBe('<a data-from-md href=\'https://example.com/test\' onclick=\'postMessage("https://example.com/test", { resourceId: "" }); return false;\'>');
|
||||
});
|
||||
|
||||
test('should handle non-resource links - simple rendering', () => {
|
||||
@@ -17,7 +17,7 @@ describe('linkReplacement', () => {
|
||||
// Handles a link such as:
|
||||
// [Google](https://www.goo'onclick=javascript:alert(/1/);f=')
|
||||
const r = linkReplacement('https://www.goo\'onclick=javascript:alert(/1/);f=\'', { linkRenderingType: 1 }).html;
|
||||
expect(r).toBe('<a data-from-md href=\'https://www.goo'onclick=javascript:alert(/1/);f='\' onclick=\'postMessage("https://www.goo%27onclick=javascript:alert(/1/);f=%27", { resourceId: "" }); return false;\'>');
|
||||
expect(r).toBe('<a data-from-md href=\'https://www.goo'onclick=javascript:alert(/1/);f='\' onclick=\'postMessage("https://www.goo%27onclick=javascript:alert(/1/);f=%27", { resourceId: "" }); return false;\'>');
|
||||
});
|
||||
|
||||
test('should handle resource links - downloaded status', () => {
|
||||
@@ -35,7 +35,7 @@ describe('linkReplacement', () => {
|
||||
},
|
||||
}).html;
|
||||
|
||||
expect(r).toBe(`<a data-from-md data-resource-id='${resourceId}' href='#' onclick='postMessage("joplin://${resourceId}", { resourceId: "${resourceId}" }); return false;'><span class="resource-icon fa-joplin"></span>`);
|
||||
expect(r).toBe(`<a data-from-md data-resource-id='${resourceId}' href='#' onclick='postMessage("joplin://${resourceId}", { resourceId: "${resourceId}" }); return false;'><span class="resource-icon fa-joplin"></span>`);
|
||||
});
|
||||
|
||||
test('should handle resource links - idle status', () => {
|
||||
|
||||
@@ -99,7 +99,7 @@ export default function(href: string, options: Options = null): LinkReplacementR
|
||||
postMessageSyntax: options.postMessageSyntax ?? 'void',
|
||||
}, onClick);
|
||||
} else {
|
||||
js = `onclick='${htmlentities(js)}'`;
|
||||
js = `onclick='${js}'`;
|
||||
}
|
||||
|
||||
if (hrefAttr.indexOf('#') === 0 && href.indexOf('#') === 0) js = ''; // If it's an internal anchor, don't add any JS since the webview is going to handle navigating to the right place
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/server",
|
||||
"version": "2.11.2",
|
||||
"version": "2.11.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start-dev": "yarn run build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",
|
||||
@@ -25,17 +25,17 @@
|
||||
"@fortawesome/fontawesome-free": "5.15.4",
|
||||
"@joplin/lib": "~2.11",
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@koa/cors": "3.4.3",
|
||||
"@koa/cors": "3.1.0",
|
||||
"@types/uuid": "9.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bulma": "0.9.4",
|
||||
"bulma-prefers-dark": "0.1.0-beta.1",
|
||||
"compare-versions": "3.6.0",
|
||||
"dayjs": "1.11.8",
|
||||
"formidable": "2.1.2",
|
||||
"dayjs": "1.11.7",
|
||||
"formidable": "2.1.1",
|
||||
"fs-extra": "11.1.1",
|
||||
"html-entities": "1.4.0",
|
||||
"jquery": "3.7.0",
|
||||
"jquery": "3.6.4",
|
||||
"knex": "2.4.2",
|
||||
"koa": "2.14.2",
|
||||
"markdown-it": "13.0.1",
|
||||
@@ -43,7 +43,7 @@
|
||||
"nanoid": "2.1.11",
|
||||
"node-cron": "3.0.2",
|
||||
"node-env-file": "0.1.8",
|
||||
"nodemailer": "6.9.3",
|
||||
"nodemailer": "6.9.2",
|
||||
"nodemon": "2.0.22",
|
||||
"pg": "8.10.0",
|
||||
"pretty-bytes": "5.6.0",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DbConnection, defaultAdminEmail, defaultAdminPassword } from '../db';
|
||||
import { hashPassword } from '../utils/auth';
|
||||
import uuidgen from '../utils/uuidgen';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.text('email', 'mediumtext').unique().notNullable();
|
||||
@@ -123,13 +123,13 @@ export const up = async (db: DbConnection) => {
|
||||
updated_time: now,
|
||||
created_time: now,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('users');
|
||||
await db.schema.dropTable('sessions');
|
||||
await db.schema.dropTable('permissions');
|
||||
await db.schema.dropTable('files');
|
||||
await db.schema.dropTable('api_clients');
|
||||
await db.schema.dropTable('changes');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('notifications', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('owner_id', 32).notNullable();
|
||||
@@ -17,8 +17,8 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('notifications', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['owner_id', 'key']);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('notifications');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('owner_id', 32).notNullable();
|
||||
@@ -10,8 +10,8 @@ export const up = async (db: DbConnection) => {
|
||||
table.bigInteger('updated_time').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('shares');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('share_users', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('share_id', 32).notNullable();
|
||||
@@ -38,8 +38,8 @@ export const up = async (db: DbConnection) => {
|
||||
table.bigInteger('updated_time').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('share_users');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('joplin_file_contents', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.string('owner_id', 32).notNullable();
|
||||
@@ -18,8 +18,8 @@ export const up = async (db: DbConnection) => {
|
||||
table.integer('content_type', 2).defaultTo(1).notNullable();
|
||||
table.string('content_id', 32).defaultTo('').notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('joplin_file_contents');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('folder_id', 32).defaultTo('').notNullable();
|
||||
table.integer('is_auto', 1).defaultTo(0).notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('joplin_items');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { DbConnection } from '../db';
|
||||
// is_shared: 1
|
||||
// type_: 1`;
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('id', 32).unique().primary().notNullable();
|
||||
table.text('name').notNullable();
|
||||
@@ -109,8 +109,8 @@ export const up = async (db: DbConnection) => {
|
||||
|
||||
await db.schema.dropTable('permissions');
|
||||
await db.schema.dropTable('joplin_file_contents');
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('items');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('max_item_size').defaultTo(0).notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('can_share').defaultTo(1).notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('email_confirmed').defaultTo(0).notNullable();
|
||||
table.integer('must_set_password').defaultTo(0).notNullable();
|
||||
@@ -40,8 +40,8 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('tokens', (table: Knex.CreateTableBuilder) => {
|
||||
table.index(['value', 'user_id']);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('account_type').defaultTo(0).notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('can_upload').defaultTo(1).notNullable();
|
||||
});
|
||||
|
||||
await db('users').update({ can_upload: 1 });
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('subscriptions', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.string('user_id', 32).notNullable();
|
||||
@@ -12,8 +12,8 @@ export const up = async (db: DbConnection) => {
|
||||
table.bigInteger('updated_time').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.bigInteger('jop_updated_time').defaultTo(0).notNullable();
|
||||
});
|
||||
@@ -22,8 +22,8 @@ export const up = async (db: DbConnection) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.renameColumn('can_share', 'can_share_folder');
|
||||
table.integer('can_share_note').defaultTo(1).notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import { DbConnection } from '../db';
|
||||
// recreate it in the same migration. So this is split into two migrations.
|
||||
// https://github.com/knex/knex/issues/2581
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('max_item_size');
|
||||
table.dropColumn('can_share_folder');
|
||||
table.dropColumn('can_share_note');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('max_item_size').defaultTo(null).nullable();
|
||||
table.specificType('can_share_folder', 'smallint').defaultTo(null).nullable();
|
||||
@@ -12,8 +12,8 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.integer('total_item_size').defaultTo(0).notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db('users').update({ email: db.raw('LOWER(email)') });
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('total_item_size');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.bigInteger('total_item_size').defaultTo(0).notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.specificType('enabled', 'smallint').defaultTo(1).nullable();
|
||||
});
|
||||
@@ -9,8 +9,8 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('subscriptions', (table: Knex.CreateTableBuilder) => {
|
||||
table.specificType('is_deleted', 'smallint').defaultTo(0).nullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
try {
|
||||
await db.schema.alterTable('emails', (table: Knex.CreateTableBuilder) => {
|
||||
table.text('key', 'mediumtext').defaultTo('').notNullable();
|
||||
@@ -13,8 +13,8 @@ export const up = async (db: DbConnection) => {
|
||||
// await db.schema.alterTable('emails', function(table: Knex.CreateTableBuilder) {
|
||||
// table.unique(['recipient_email', 'key']);
|
||||
// });
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (_db: DbConnection) => {
|
||||
export async function up(_db: DbConnection): Promise<any> {
|
||||
// try {
|
||||
// await db.schema.alterTable('emails', function(table: Knex.CreateTableBuilder) {
|
||||
// table.dropUnique(['recipient_email', 'key']);
|
||||
@@ -9,8 +9,8 @@ export const up = async (_db: DbConnection) => {
|
||||
// } catch (error) {
|
||||
// // console.warn('Could not drop unique constraint - this is not an error.', error);
|
||||
// }
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (_db: DbConnection) => {
|
||||
export async function down(_db: DbConnection): Promise<any> {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('user_flags', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.string('user_id', 32).notNullable();
|
||||
@@ -13,8 +13,8 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('user_flags', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['user_id', 'type']);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('user_flags');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('share_users', (table: Knex.CreateTableBuilder) => {
|
||||
table.text('master_key', 'mediumtext').defaultTo('').notNullable();
|
||||
});
|
||||
@@ -9,9 +9,9 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('master_key_id', 32).defaultTo('').notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('share_users', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('master_key');
|
||||
});
|
||||
@@ -19,4 +19,4 @@ export const down = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('master_key_id');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('events', (table: Knex.CreateTableBuilder) => {
|
||||
table.uuid('id').unique().notNullable();
|
||||
table.increments('counter').unique().primary().notNullable();
|
||||
@@ -14,8 +14,8 @@ export const up = async (db: DbConnection) => {
|
||||
table.index('type');
|
||||
table.index('name');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('events');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
import { msleep } from '../utils/time';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
if (!(await db.schema.hasColumn('items', 'owner_id'))) {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('owner_id', 32).defaultTo('').notNullable();
|
||||
@@ -58,10 +58,10 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('owner_id', 32).notNullable().alter();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('owner_id');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['name', 'owner_id']);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropUnique(['name', 'owner_id']);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('storages', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.text('connection_string').notNullable();
|
||||
@@ -31,12 +31,12 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('storages', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['connection_string']);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('storages');
|
||||
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('content_storage_id');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.index('content_storage_id');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropIndex('content_storage_id');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('user_deletions', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.string('user_id', 32).notNullable();
|
||||
@@ -19,8 +19,8 @@ export const up = async (db: DbConnection) => {
|
||||
await db.schema.alterTable('user_deletions', (table: Knex.CreateTableBuilder) => {
|
||||
table.unique(['user_id']);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('user_deletions');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,16 +5,16 @@ import { DbConnection } from '../db';
|
||||
// it to an empty string by default, and update all rows that have "0" as
|
||||
// recipient_id.
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('emails', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('recipient_id', 32).defaultTo('').notNullable().alter();
|
||||
});
|
||||
|
||||
await db('emails').update({ recipient_id: '' }).where('recipient_id', '=', '0');
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('emails', (table: Knex.CreateTableBuilder) => {
|
||||
table.string('recipient_id', 32).defaultTo(0).notNullable().alter();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,17 +38,17 @@ export const disabledUserIds = async (db: DbConnection): Promise<string[]> => {
|
||||
return users.map(u => u.id);
|
||||
};
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.bigInteger('disabled_time').defaultTo(0).notNullable();
|
||||
});
|
||||
|
||||
const userIds = await disabledUserIds(db);
|
||||
await setUserAccountDisabledTimes(db, userIds);
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('users', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('disabled_time');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('backup_items', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.integer('type').notNullable();
|
||||
@@ -10,8 +10,8 @@ export const up = async (db: DbConnection) => {
|
||||
table.binary('content').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('backup_items');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.specificType('recursive', 'smallint').defaultTo(0).nullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.alterTable('shares', (table: Knex.CreateTableBuilder) => {
|
||||
table.dropColumn('recursive');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { DbConnection } from '../db';
|
||||
|
||||
export const up = async (db: DbConnection) => {
|
||||
export async function up(db: DbConnection): Promise<any> {
|
||||
await db.schema.createTable('task_states', (table: Knex.CreateTableBuilder) => {
|
||||
table.increments('id').unique().primary().notNullable();
|
||||
table.integer('task_id').unique().notNullable();
|
||||
@@ -10,8 +10,8 @@ export const up = async (db: DbConnection) => {
|
||||
table.bigInteger('updated_time').notNullable();
|
||||
table.bigInteger('created_time').notNullable();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const down = async (db: DbConnection) => {
|
||||
export async function down(db: DbConnection): Promise<any> {
|
||||
await db.schema.dropTable('task_states');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ItemType, databaseSchema, Uuid, Item, ShareType, Share, ChangeType, Use
|
||||
import { defaultPagination, paginateDbQuery, PaginatedResults, Pagination } from './utils/pagination';
|
||||
import { isJoplinItemName, isJoplinResourceBlobPath, linkedResourceIds, serializeJoplinItem, unserializeJoplinItem } from '../utils/joplinUtils';
|
||||
import { ModelType } from '@joplin/lib/BaseModel';
|
||||
import { ApiError, CustomErrorCode, ErrorConflict, ErrorForbidden, ErrorPayloadTooLarge, ErrorUnprocessableEntity, ErrorCode } from '../utils/errors';
|
||||
import { ApiError, ErrorCode, ErrorConflict, ErrorForbidden, ErrorPayloadTooLarge, ErrorUnprocessableEntity } from '../utils/errors';
|
||||
import { Knex } from 'knex';
|
||||
import { ChangePreviousItem } from './ChangeModel';
|
||||
import { unique } from '../utils/array';
|
||||
@@ -311,7 +311,7 @@ export default class ItemModel extends BaseModel<Item> {
|
||||
try {
|
||||
content = await fromDriver.read(item.id, { models: this.models() });
|
||||
} catch (error) {
|
||||
if (error.code === CustomErrorCode.NotFound) {
|
||||
if (error.code === ErrorCode.NotFound) {
|
||||
logger.info(`Could not process item, because content was deleted: ${item.id}`);
|
||||
return;
|
||||
}
|
||||
@@ -537,10 +537,10 @@ export default class ItemModel extends BaseModel<Item> {
|
||||
return this.itemToJoplinItem(raw);
|
||||
}
|
||||
|
||||
public async saveFromRawContent(user: User, rawContentItemOrItems: SaveFromRawContentItem[] | SaveFromRawContentItem, options: ItemSaveOption = null): Promise<SaveFromRawContentResult> {
|
||||
public async saveFromRawContent(user: User, rawContentItems: SaveFromRawContentItem[] | SaveFromRawContentItem, options: ItemSaveOption = null): Promise<SaveFromRawContentResult> {
|
||||
options = options || {};
|
||||
|
||||
const rawContentItems = !Array.isArray(rawContentItemOrItems) ? [rawContentItemOrItems] : rawContentItemOrItems;
|
||||
if (!Array.isArray(rawContentItems)) rawContentItems = [rawContentItems];
|
||||
|
||||
// In this function, first we process the input items, which may be
|
||||
// serialized Joplin items or actual buffers (for resources) and convert
|
||||
@@ -555,78 +555,73 @@ export default class ItemModel extends BaseModel<Item> {
|
||||
joplinItem?: any;
|
||||
}
|
||||
|
||||
interface ExistingItem {
|
||||
id: Uuid;
|
||||
name: string;
|
||||
const existingItems = await this.loadByNames(user.id, rawContentItems.map(i => i.name));
|
||||
const itemsToProcess: Record<string, ItemToProcess> = {};
|
||||
|
||||
for (const rawItem of rawContentItems) {
|
||||
try {
|
||||
const isJoplinItem = isJoplinItemName(rawItem.name);
|
||||
let isNote = false;
|
||||
|
||||
const item: Item = {
|
||||
name: rawItem.name,
|
||||
};
|
||||
|
||||
let joplinItem: any = null;
|
||||
|
||||
let resourceIds: string[] = [];
|
||||
|
||||
if (isJoplinItem) {
|
||||
joplinItem = await unserializeJoplinItem(rawItem.body.toString());
|
||||
isNote = joplinItem.type_ === ModelType.Note;
|
||||
resourceIds = isNote ? linkedResourceIds(joplinItem.body) : [];
|
||||
|
||||
item.jop_id = joplinItem.id;
|
||||
item.jop_parent_id = joplinItem.parent_id || '';
|
||||
item.jop_type = joplinItem.type_;
|
||||
item.jop_encryption_applied = joplinItem.encryption_applied || 0;
|
||||
item.jop_share_id = joplinItem.share_id || '';
|
||||
item.jop_updated_time = joplinItem.updated_time;
|
||||
|
||||
const joplinItemToSave = { ...joplinItem };
|
||||
|
||||
delete joplinItemToSave.id;
|
||||
delete joplinItemToSave.parent_id;
|
||||
delete joplinItemToSave.share_id;
|
||||
delete joplinItemToSave.type_;
|
||||
delete joplinItemToSave.encryption_applied;
|
||||
delete joplinItemToSave.updated_time;
|
||||
|
||||
item.content = Buffer.from(JSON.stringify(joplinItemToSave));
|
||||
} else {
|
||||
item.content = rawItem.body;
|
||||
}
|
||||
|
||||
const existingItem = existingItems.find(i => i.name === rawItem.name);
|
||||
if (existingItem) item.id = existingItem.id;
|
||||
|
||||
if (options.shareId) item.jop_share_id = options.shareId;
|
||||
|
||||
await this.models().user().checkMaxItemSizeLimit(user, rawItem.body, item, joplinItem);
|
||||
|
||||
itemsToProcess[rawItem.name] = {
|
||||
item: item,
|
||||
error: null,
|
||||
resourceIds,
|
||||
isNote,
|
||||
joplinItem,
|
||||
};
|
||||
} catch (error) {
|
||||
itemsToProcess[rawItem.name] = {
|
||||
item: null,
|
||||
error: error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return this.withTransaction(async () => {
|
||||
const existingItems = await this.loadByNames(user.id, rawContentItems.map(i => i.name), { fields: ['id', 'name'] }) as ExistingItem[];
|
||||
const itemsToProcess: Record<string, ItemToProcess> = {};
|
||||
|
||||
for (const rawItem of rawContentItems) {
|
||||
try {
|
||||
const isJoplinItem = isJoplinItemName(rawItem.name);
|
||||
let isNote = false;
|
||||
|
||||
const item: Item = {
|
||||
name: rawItem.name,
|
||||
};
|
||||
|
||||
let joplinItem: any = null;
|
||||
|
||||
let resourceIds: string[] = [];
|
||||
|
||||
if (isJoplinItem) {
|
||||
joplinItem = await unserializeJoplinItem(rawItem.body.toString());
|
||||
isNote = joplinItem.type_ === ModelType.Note;
|
||||
resourceIds = isNote ? linkedResourceIds(joplinItem.body) : [];
|
||||
|
||||
item.jop_id = joplinItem.id;
|
||||
item.jop_parent_id = joplinItem.parent_id || '';
|
||||
item.jop_type = joplinItem.type_;
|
||||
item.jop_encryption_applied = joplinItem.encryption_applied || 0;
|
||||
item.jop_share_id = joplinItem.share_id || '';
|
||||
item.jop_updated_time = joplinItem.updated_time;
|
||||
|
||||
const joplinItemToSave = { ...joplinItem };
|
||||
|
||||
delete joplinItemToSave.id;
|
||||
delete joplinItemToSave.parent_id;
|
||||
delete joplinItemToSave.share_id;
|
||||
delete joplinItemToSave.type_;
|
||||
delete joplinItemToSave.encryption_applied;
|
||||
delete joplinItemToSave.updated_time;
|
||||
|
||||
item.content = Buffer.from(JSON.stringify(joplinItemToSave));
|
||||
} else {
|
||||
item.content = rawItem.body;
|
||||
}
|
||||
|
||||
const existingItem = existingItems.find(i => i.name === rawItem.name);
|
||||
if (existingItem) item.id = existingItem.id;
|
||||
|
||||
if (options.shareId) item.jop_share_id = options.shareId;
|
||||
|
||||
await this.models().user().checkMaxItemSizeLimit(user, rawItem.body, item, joplinItem);
|
||||
|
||||
itemsToProcess[rawItem.name] = {
|
||||
item: item,
|
||||
error: null,
|
||||
resourceIds,
|
||||
isNote,
|
||||
joplinItem,
|
||||
};
|
||||
} catch (error) {
|
||||
itemsToProcess[rawItem.name] = {
|
||||
item: null,
|
||||
error: error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const output: SaveFromRawContentResult = {};
|
||||
const output: SaveFromRawContentResult = {};
|
||||
|
||||
await this.withTransaction(async () => {
|
||||
for (const name of Object.keys(itemsToProcess)) {
|
||||
const o = itemsToProcess[name];
|
||||
|
||||
@@ -695,9 +690,9 @@ export default class ItemModel extends BaseModel<Item> {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}, 'ItemModel::saveFromRawContent');
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
protected async validate(item: Item, options: ValidateOptions = {}): Promise<Item> {
|
||||
@@ -789,7 +784,7 @@ export default class ItemModel extends BaseModel<Item> {
|
||||
// that shared folder. It returns null otherwise.
|
||||
public async joplinItemSharedRootInfo(jopId: string): Promise<SharedRootInfo | null> {
|
||||
const path = await this.joplinItemPath(jopId);
|
||||
if (!path.length) throw new ApiError(`Cannot retrieve path for item: ${jopId}`, null, ErrorCode.NoPathForItem);
|
||||
if (!path.length) throw new ApiError(`Cannot retrieve path for item: ${jopId}`, null, 'noPathForItem');
|
||||
const rootFolderItem = path[path.length - 1];
|
||||
const share = await this.models().share().itemShare(ShareType.Folder, rootFolderItem.id);
|
||||
if (!share) return null;
|
||||
|
||||
@@ -2,7 +2,7 @@ import BaseModel, { UuidType } from './BaseModel';
|
||||
import { Uuid } from '../services/database/types';
|
||||
import { LockType, Lock, LockClientType, defaultLockTtl, activeLock } from '@joplin/lib/services/synchronizer/LockHandler';
|
||||
import { Value } from './KeyValueModel';
|
||||
import { ErrorConflict, ErrorUnprocessableEntity, ErrorCode } from '../utils/errors';
|
||||
import { ErrorConflict, ErrorUnprocessableEntity } from '../utils/errors';
|
||||
import uuidgen from '../utils/uuidgen';
|
||||
|
||||
export default class LockModel extends BaseModel<Lock> {
|
||||
@@ -59,7 +59,7 @@ export default class LockModel extends BaseModel<Lock> {
|
||||
const exclusiveLock = activeLock(locks, new Date(), this.lockTtl, LockType.Exclusive);
|
||||
|
||||
if (exclusiveLock) {
|
||||
throw new ErrorConflict(`Cannot acquire lock because there is already an exclusive lock for client: ${exclusiveLock.clientType} #${exclusiveLock.clientId}`, ErrorCode.HasExclusiveSyncLock);
|
||||
throw new ErrorConflict(`Cannot acquire lock because there is already an exclusive lock for client: ${exclusiveLock.clientType} #${exclusiveLock.clientId}`, 'hasExclusiveLock');
|
||||
}
|
||||
|
||||
const syncLock = activeLock(locks, new Date(), this.lockTtl, LockType.Sync, clientType, clientId);
|
||||
@@ -111,7 +111,7 @@ export default class LockModel extends BaseModel<Lock> {
|
||||
|
||||
return JSON.stringify(locks);
|
||||
} else {
|
||||
throw new ErrorConflict(`Cannot acquire lock because there is already an exclusive lock for client: ${exclusiveLock.clientType} #${exclusiveLock.clientId}`, ErrorCode.HasExclusiveSyncLock);
|
||||
throw new ErrorConflict(`Cannot acquire lock because there is already an exclusive lock for client: ${exclusiveLock.clientType} #${exclusiveLock.clientId}`, 'hasExclusiveLock');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ export default class LockModel extends BaseModel<Lock> {
|
||||
if (syncLock.clientId === clientId) {
|
||||
locks = locks.filter(l => l.id !== syncLock.id);
|
||||
} else {
|
||||
throw new ErrorConflict(`Cannot acquire exclusive lock because there is an active sync lock for client: ${syncLock.clientType} #${syncLock.clientId}`, ErrorCode.HasSyncLock);
|
||||
throw new ErrorConflict(`Cannot acquire exclusive lock because there is an active sync lock for client: ${syncLock.clientType} #${syncLock.clientId}`, 'hasSyncLock');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// database (as a binary blob). For now the driver expects that the content is
|
||||
// stored in the same table as the items, as it originally was.
|
||||
|
||||
import { CustomError, CustomErrorCode } from '../../../utils/errors';
|
||||
import { CustomError, ErrorCode } from '../../../utils/errors';
|
||||
import { DatabaseConfigClient, StorageDriverConfig, StorageDriverType } from '../../../utils/types';
|
||||
import StorageDriverBase, { Context } from './StorageDriverBase';
|
||||
|
||||
@@ -41,7 +41,7 @@ export default class StorageDriverDatabase extends StorageDriverBase {
|
||||
|
||||
// Calling code should only call this handler if the row exists, so if
|
||||
// we find it doesn't, it's an error.
|
||||
if (!row) throw new CustomError(`No such row: ${itemId}`, CustomErrorCode.NotFound);
|
||||
if (!row) throw new CustomError(`No such row: ${itemId}`, ErrorCode.NotFound);
|
||||
|
||||
return row.content;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { mkdirp, pathExists, readFile, remove, writeFile } from 'fs-extra';
|
||||
import { CustomError, CustomErrorCode } from '../../../utils/errors';
|
||||
import { CustomError, ErrorCode } from '../../../utils/errors';
|
||||
import { StorageDriverConfig, StorageDriverType } from '../../../utils/types';
|
||||
import StorageDriverBase from './StorageDriverBase';
|
||||
|
||||
@@ -36,7 +36,7 @@ export default class StorageDriverFs extends StorageDriverBase {
|
||||
const result = await readFile(this.itemPath(itemId));
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') throw new CustomError(`Not found: ${itemId}`, CustomErrorCode.NotFound);
|
||||
if (error.code === 'ENOENT') throw new CustomError(`Not found: ${itemId}`, ErrorCode.NotFound);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export default class StorageDriverFs extends StorageDriverBase {
|
||||
try {
|
||||
await remove(this.itemPath(id));
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') throw new CustomError(`Not found: ${itemId}`, CustomErrorCode.NotFound);
|
||||
if (error.code === 'ENOENT') throw new CustomError(`Not found: ${itemId}`, ErrorCode.NotFound);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CustomError, CustomErrorCode } from '../../../utils/errors';
|
||||
import { CustomError, ErrorCode } from '../../../utils/errors';
|
||||
import { StorageDriverConfig, StorageDriverType } from '../../../utils/types';
|
||||
import StorageDriverBase from './StorageDriverBase';
|
||||
|
||||
@@ -15,7 +15,7 @@ export default class StorageDriverMemory extends StorageDriverBase {
|
||||
}
|
||||
|
||||
public async read(itemId: string): Promise<Buffer> {
|
||||
if (!(itemId in this.data_)) throw new CustomError(`No such item: ${itemId}`, CustomErrorCode.NotFound);
|
||||
if (!(itemId in this.data_)) throw new CustomError(`No such item: ${itemId}`, ErrorCode.NotFound);
|
||||
return this.data_[itemId];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectsCommand, ObjectIdentifier, HeadObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { CustomError, CustomErrorCode } from '../../../utils/errors';
|
||||
import { CustomError, ErrorCode } from '../../../utils/errors';
|
||||
import { StorageDriverConfig, StorageDriverType } from '../../../utils/types';
|
||||
import StorageDriverBase from './StorageDriverBase';
|
||||
|
||||
@@ -60,7 +60,7 @@ export default class StorageDriverS3 extends StorageDriverBase {
|
||||
|
||||
return stream2buffer(response.Body);
|
||||
} catch (error) {
|
||||
if (error?.$metadata?.httpStatusCode === 404) throw new CustomError(`No such item: ${itemId}`, CustomErrorCode.NotFound);
|
||||
if (error?.$metadata?.httpStatusCode === 404) throw new CustomError(`No such item: ${itemId}`, ErrorCode.NotFound);
|
||||
error.message = `Could not get item "${itemId}": ${error.message}`;
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import config from '../../../config';
|
||||
import { Item } from '../../../services/database/types';
|
||||
import { CustomErrorCode } from '../../../utils/errors';
|
||||
import { ErrorCode } from '../../../utils/errors';
|
||||
import { createUserAndSession, db, makeNoteSerializedBody, models } from '../../../utils/testing/testUtils';
|
||||
import { Config, StorageDriverConfig, StorageDriverMode } from '../../../utils/types';
|
||||
import newModelFactory from '../../factory';
|
||||
@@ -291,6 +291,6 @@ export function shouldThrowNotFoundIfNotExist(driverConfig: StorageDriverConfig)
|
||||
}
|
||||
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.code).toBe(CustomErrorCode.NotFound);
|
||||
expect(error.code).toBe(ErrorCode.NotFound);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
export enum ErrorCode {
|
||||
ResyncRequired = 'resyncRequired',
|
||||
NoPathForItem = 'noPathForItem',
|
||||
HasExclusiveSyncLock = 'hasExclusiveLock',
|
||||
HasSyncLock = 'hasSyncLock',
|
||||
NoSub = 'no_sub',
|
||||
NoStripeSub = 'no_stripe_sub',
|
||||
InvalidOrigin = 'invalidOrigin',
|
||||
}
|
||||
|
||||
export interface ErrorOptions {
|
||||
details?: any;
|
||||
code?: ErrorCode;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
// For explanation of the setPrototypeOf call, see:
|
||||
@@ -19,10 +9,10 @@ export class ApiError extends Error {
|
||||
public static httpCode: number = 400;
|
||||
|
||||
public httpCode: number;
|
||||
public code: ErrorCode;
|
||||
public code: string;
|
||||
public details: any;
|
||||
|
||||
public constructor(message: string, httpCode: number = null, code: ErrorCode | ErrorOptions = undefined) {
|
||||
public constructor(message: string, httpCode: number = null, code: string | ErrorOptions = undefined) {
|
||||
super(message);
|
||||
|
||||
this.httpCode = httpCode === null ? 400 : httpCode;
|
||||
@@ -40,7 +30,7 @@ export class ApiError extends Error {
|
||||
}
|
||||
|
||||
export class ErrorWithCode extends ApiError {
|
||||
public constructor(message: string, code: ErrorCode) {
|
||||
public constructor(message: string, code: string) {
|
||||
super(message, null, code);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +47,7 @@ export class ErrorMethodNotAllowed extends ApiError {
|
||||
export class ErrorNotFound extends ApiError {
|
||||
public static httpCode: number = 404;
|
||||
|
||||
public constructor(message: string = 'Not Found', code: ErrorCode = undefined) {
|
||||
public constructor(message: string = 'Not Found', code: string = undefined) {
|
||||
super(message, ErrorNotFound.httpCode, code);
|
||||
Object.setPrototypeOf(this, ErrorNotFound.prototype);
|
||||
}
|
||||
@@ -104,7 +94,7 @@ export class ErrorUnprocessableEntity extends ApiError {
|
||||
export class ErrorConflict extends ApiError {
|
||||
public static httpCode: number = 409;
|
||||
|
||||
public constructor(message: string = 'Conflict', code: ErrorCode = undefined) {
|
||||
public constructor(message: string = 'Conflict', code: string = undefined) {
|
||||
super(message, ErrorConflict.httpCode, code);
|
||||
Object.setPrototypeOf(this, ErrorConflict.prototype);
|
||||
}
|
||||
@@ -114,7 +104,7 @@ export class ErrorResyncRequired extends ApiError {
|
||||
public static httpCode: number = 400;
|
||||
|
||||
public constructor(message: string = 'Delta cursor is invalid and the complete data should be resynced') {
|
||||
super(message, ErrorResyncRequired.httpCode, ErrorCode.ResyncRequired);
|
||||
super(message, ErrorResyncRequired.httpCode, 'resyncRequired');
|
||||
Object.setPrototypeOf(this, ErrorResyncRequired.prototype);
|
||||
}
|
||||
}
|
||||
@@ -166,13 +156,13 @@ export function errorToPlainObject(error: any): PlainObjectError {
|
||||
return output;
|
||||
}
|
||||
|
||||
export enum CustomErrorCode {
|
||||
export enum ErrorCode {
|
||||
NotFound,
|
||||
}
|
||||
|
||||
export class CustomError extends Error {
|
||||
public code: CustomErrorCode;
|
||||
public constructor(message: string, code: CustomErrorCode) {
|
||||
public code: ErrorCode;
|
||||
public constructor(message: string, code: ErrorCode) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
Object.setPrototypeOf(this, CustomError.prototype);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import config, { baseUrl } from '../config';
|
||||
import { Item, ItemAddressingType, User, Uuid } from '../services/database/types';
|
||||
import { ErrorBadRequest, ErrorCode, ErrorForbidden, ErrorNotFound } from './errors';
|
||||
import { ErrorBadRequest, ErrorForbidden, ErrorNotFound } from './errors';
|
||||
import Router from './Router';
|
||||
import { AppContext, HttpMethod, RouteType } from './types';
|
||||
import { URL } from 'url';
|
||||
@@ -206,7 +206,7 @@ export async function execRequest(routes: Routers, ctx: AppContext): Promise<Exe
|
||||
if (!match) throw new ErrorNotFound();
|
||||
|
||||
const endPoint = match.route.findEndPoint(ctx.request.method as HttpMethod, match.subPath.schema);
|
||||
if (ctx.URL && !isValidOrigin(ctx.URL.origin, baseUrl(endPoint.type), endPoint.type)) throw new ErrorNotFound(`Invalid origin: ${ctx.URL.origin}`, ErrorCode.InvalidOrigin);
|
||||
if (ctx.URL && !isValidOrigin(ctx.URL.origin, baseUrl(endPoint.type), endPoint.type)) throw new ErrorNotFound(`Invalid origin: ${ctx.URL.origin}`, 'invalidOrigin');
|
||||
|
||||
const isPublicRoute = match.route.isPublic(match.subPath.schema);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Subscription, Uuid } from '../services/database/types';
|
||||
import { Models } from '../models/factory';
|
||||
import { AccountType } from '../models/UserModel';
|
||||
import { findPrice, PricePeriod } from '@joplin/lib/utils/joplinCloud';
|
||||
import { ErrorWithCode, ErrorCode } from './errors';
|
||||
import { ErrorWithCode } from './errors';
|
||||
const stripeLib = require('stripe');
|
||||
|
||||
export interface SubscriptionInfo {
|
||||
@@ -33,11 +33,11 @@ export function accountTypeToPriceId(accountType: AccountType): string {
|
||||
|
||||
export async function subscriptionInfoByUserId(models: Models, userId: Uuid): Promise<SubscriptionInfo> {
|
||||
const sub = await models.subscription().byUserId(userId);
|
||||
if (!sub) throw new ErrorWithCode('Could not retrieve subscription info', ErrorCode.NoSub);
|
||||
if (!sub) throw new ErrorWithCode('Could not retrieve subscription info', 'no_sub');
|
||||
|
||||
const stripe = initStripe();
|
||||
const stripeSub = await stripe.subscriptions.retrieve(sub.stripe_subscription_id);
|
||||
if (!stripeSub) throw new ErrorWithCode('Could not retrieve Stripe subscription', ErrorCode.NoStripeSub);
|
||||
if (!stripeSub) throw new ErrorWithCode('Could not retrieve Stripe subscription', 'no_stripe_sub');
|
||||
|
||||
return { sub, stripeSub };
|
||||
}
|
||||
|
||||
@@ -466,7 +466,7 @@ export async function expectThrow(asyncFn: Function, errorCode: any = undefined)
|
||||
return thrownError;
|
||||
}
|
||||
|
||||
export async function expectHttpError(asyncFn: Function, expectedHttpCode: number, expectedErrorCode: string = null): Promise<void> {
|
||||
export async function expectHttpError(asyncFn: Function, expectedHttpCode: number): Promise<void> {
|
||||
let thrownError = null;
|
||||
|
||||
try {
|
||||
@@ -479,10 +479,6 @@ export async function expectHttpError(asyncFn: Function, expectedHttpCode: numbe
|
||||
expect('not throw').toBe('throw');
|
||||
} else {
|
||||
expect(thrownError.httpCode).toBe(expectedHttpCode);
|
||||
|
||||
if (expectedErrorCode !== null) {
|
||||
expect(thrownError.code).toBe(expectedErrorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,7 +529,6 @@ is_shared: 1
|
||||
share_id: ${note.share_id || ''}
|
||||
conflict_original_id:
|
||||
master_key_id:
|
||||
user_data:
|
||||
type_: 1`;
|
||||
}
|
||||
|
||||
@@ -550,7 +545,6 @@ encryption_applied: 0
|
||||
parent_id: ${folder.parent_id || ''}
|
||||
is_shared: 0
|
||||
share_id: ${folder.share_id || ''}
|
||||
user_data:
|
||||
type_: 2`;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"@joplin/renderer": "~2.11",
|
||||
"@joplin/utils": "~2.11",
|
||||
"compare-versions": "3.6.0",
|
||||
"dayjs": "1.11.8",
|
||||
"dayjs": "1.11.7",
|
||||
"execa": "4.1.0",
|
||||
"fs-extra": "11.1.1",
|
||||
"gettext-parser": "6.0.0",
|
||||
|
||||
@@ -101,32 +101,34 @@ async function createRelease(projectName: string, name: string, tagName: string,
|
||||
|
||||
console.info(`Creating release: ${suffix}`);
|
||||
|
||||
// if (name === '32bit') {
|
||||
// await patcher.updateFileContent(`${rnDir}/android/app/build.gradle`, async (content: string) => {
|
||||
// content = content.replace(/abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"/, 'abiFilters "armeabi-v7a", "x86"');
|
||||
// content = content.replace(/include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"/, 'include "armeabi-v7a", "x86"');
|
||||
// return content;
|
||||
// });
|
||||
// }
|
||||
if (name === '32bit') {
|
||||
await patcher.updateFileContent(`${rnDir}/android/app/build.gradle`, async (content: string) => {
|
||||
content = content.replace(/abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"/, 'abiFilters "armeabi-v7a", "x86"');
|
||||
content = content.replace(/include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"/, 'include "armeabi-v7a", "x86"');
|
||||
return content;
|
||||
});
|
||||
}
|
||||
|
||||
// if (name !== 'vosk') {
|
||||
// await patcher.updateFileContent(`${rnDir}/services/voiceTyping/vosk.android.ts`, async (_content: string) => {
|
||||
// return readFile(`${rnDir}/services/voiceTyping/vosk.ios.ts`, 'utf8');
|
||||
// });
|
||||
if (name !== 'vosk') {
|
||||
await patcher.updateFileContent(`${rnDir}/services/voiceTyping/vosk.android.ts`, async (_content: string) => {
|
||||
return readFile(`${rnDir}/services/voiceTyping/vosk.ios.ts`, 'utf8');
|
||||
});
|
||||
|
||||
// await patcher.updateFileContent(`${rnDir}/android/app/build.gradle`, async (content: string) => {
|
||||
// content = content.replace(/\s+"react-native-vosk": ".*",/, '');
|
||||
// return content;
|
||||
// });
|
||||
// }
|
||||
await patcher.updateFileContent(`${rnDir}/android/app/build.gradle`, async (content: string) => {
|
||||
content = content.replace(/\s+"react-native-vosk": ".*",/, '');
|
||||
return content;
|
||||
});
|
||||
|
||||
// if (name === 'vosk') {
|
||||
// await patcher.updateFileContent(`${rnDir}/android/app/build.gradle`, async (content: string) => {
|
||||
// content = content.replace(/(\s+)applicationId "net.cozic.joplin"/, '$1applicationId "net.cozic.joplin.mod"');
|
||||
// content = content.replace(/(\s+)versionName "(\d+\.\d+\.\d+)"/, '$1versionName "$2-mod"');
|
||||
// return content;
|
||||
// });
|
||||
// }
|
||||
await patcher.removeFile(`${rnDir}/android/app/src/main/assets/model-fr-fr`);
|
||||
}
|
||||
|
||||
if (name === 'vosk') {
|
||||
await patcher.updateFileContent(`${rnDir}/android/app/build.gradle`, async (content: string) => {
|
||||
content = content.replace(/(\s+)applicationId "net.cozic.joplin"/, '$1applicationId "net.cozic.joplin.mod"');
|
||||
content = content.replace(/(\s+)versionName "(\d+\.\d+\.\d+)"/, '$1versionName "$2-mod"');
|
||||
return content;
|
||||
});
|
||||
}
|
||||
|
||||
const apkFilename = `joplin-v${suffix}.apk`;
|
||||
const apkFilePath = `${releaseDir}/${apkFilename}`;
|
||||
@@ -242,7 +244,7 @@ async function main() {
|
||||
const version = gradleVersionName(newContent);
|
||||
const tagName = `android-v${version}`;
|
||||
// const releaseNames = ['main', '32bit', 'vosk'];
|
||||
const releaseNames = ['main'];
|
||||
const releaseNames = ['main', 'vosk'];
|
||||
const releaseFiles: Record<string, Release> = {};
|
||||
const mainProjectName = 'joplin-android';
|
||||
const modProjectName = 'joplin-android-mod';
|
||||
|
||||
@@ -181,7 +181,6 @@ command | 16
|
||||
| share_id | text | |
|
||||
| conflict_original_id | text | |
|
||||
| master_key_id | text | |
|
||||
| user_data | text | |
|
||||
| body_html | text | Note body, in HTML format |
|
||||
| base_url | text | If `body_html` is provided and contains relative URLs, provide the `base_url` parameter too so that all the URLs can be converted to absolute ones. The base URL is basically where the HTML was fetched from, minus the query (everything after the '?'). For example if the original page was `https://stackoverflow.com/search?q=%5Bjava%5D+test`, the base URL is `https://stackoverflow.com/search`. |
|
||||
| image_data_url | text | An image to attach to the note, in [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format. |
|
||||
@@ -258,7 +257,6 @@ This is actually a notebook. Internally notebooks are called "folders".
|
||||
| share_id | text | |
|
||||
| master_key_id | text | |
|
||||
| icon | text | |
|
||||
| user_data | text | |
|
||||
|
||||
## GET /folders
|
||||
|
||||
@@ -308,7 +306,6 @@ Deletes the folder with ID :id
|
||||
| is_shared | int | |
|
||||
| share_id | text | |
|
||||
| master_key_id | text | |
|
||||
| user_data | text | |
|
||||
|
||||
## GET /resources
|
||||
|
||||
@@ -384,7 +381,6 @@ Deletes the resource with ID :id
|
||||
| encryption_applied | int | |
|
||||
| is_shared | int | |
|
||||
| parent_id | text | |
|
||||
| user_data | text | |
|
||||
|
||||
## GET /tags
|
||||
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
# Joplin Server Changelog
|
||||
|
||||
## [server-v2.11.2](https://github.com/laurent22/joplin/releases/tag/server-v2.11.2) - 2023-06-20T08:40:54Z
|
||||
|
||||
- Improved: Allow giving a different version number to forks (091eff9)
|
||||
- Improved: Improve performance and reliability when adding an item (17888a2)
|
||||
- Improved: Process orphaned items (84b130e)
|
||||
- Improved: Updated packages @koa/cors (v4), aws, buildTools, domhandler (v5), domutils (v3.1.0), formidable (v3), highlight.js (v11.8.0), jsdom (v21.1.2), markdown-it-multimd-table (v4.2.2), nodemailer (v6.9.3), sass (v1.62.1), sharp (v0.32.1), tar (v6.1.15), yargs (v17.7.2)
|
||||
- Fixed: Fixed copyright year (a7e185e)
|
||||
|
||||
## [server-v2.11.1](https://github.com/laurent22/joplin/releases/tag/server-v2.11.1) - 2023-05-15T17:16:13Z
|
||||
|
||||
- Improved: Allow setting NTP server using NTP_SERVER env variable (#8153)
|
||||
|
||||
@@ -24,7 +24,7 @@ The overall architecture for each application is as such:
|
||||
|
||||
- Configuration: The application is configured using a `settings.json` file. Its schema is available online: https://joplinapp.org/schema/settings.json
|
||||
|
||||
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/architecture/Application.png" style="max-width: 100%;"/>
|
||||
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/architecture/Application.png" style="max-width: 100%;"></div>
|
||||
|
||||
### Desktop application
|
||||
|
||||
@@ -56,7 +56,7 @@ A typical Joplin Server installation will use the following elements:
|
||||
|
||||
This is a typical Joplin Server installation, but many of its components can be configured - for example it is possible to use a different database engine, or to use the filesystem instead of AWS S3. Any reverse proxy would also work - using Nginx is not required.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/architecture/JoplinServer.png" style="max-width: 100%;"/>
|
||||
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/architecture/JoplinServer.png" style="max-width: 100%;"></div>
|
||||
|
||||
## Web Clipper
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# Debugging Server project with vscode
|
||||
|
||||
Using a debugger sometimes is much easier than trying to just print things to understand a bug,
|
||||
for the server project we have a configuration that makes it easy for everyone to run in debug mode inside vscode.
|
||||
|
||||
In the debug screen you can select "Server" and hit the play button to start the process.
|
||||
|
||||

|
||||
|
||||
Before running the server there is a task called `transpile-server` that runs `yarn tsc` to make sure that the
|
||||
latest changes in the `package/server` are being executed.
|
||||
|
||||
https://github.com/laurent22/joplin/blob/4f37e6073ad549fe72206e2a125c27174b5d96a9/joplin.code-workspace#L360-L365
|
||||
|
||||
In a optimal solution we would be doing this `transpile-server` task in the `tasks.json` file
|
||||
(inside the `tasks.json` we can use a `type` `npm` for the task that is more ergonomic)
|
||||
|
||||
If there are any new environment variables that need to be included before execution, there is a place where they can be added:
|
||||
|
||||
https://github.com/laurent22/joplin/blob/4f37e6073ad549fe72206e2a125c27174b5d96a9/joplin.code-workspace#L387-L391
|
||||
|
||||
Something that we could do to improve the experience is adding a build process to other projects that are used by the server project,
|
||||
but this still can be done with other terminals open.
|
||||
|
||||
### Modifying the configuration:
|
||||
|
||||
To modify the configuration, for now, it is all in the `joplin.code-workspace` file, but if needed we could also break
|
||||
the configuration into two files, one for the `launch.json` and other for the `tasks.json`.
|
||||
|
||||
|
||||
### References:
|
||||
[vscode debugger](https://code.visualstudio.com/docs/editor/debugging)
|
||||
|
||||
[Launch option to vscode workspaces](https://code.visualstudio.com/docs/editor/multi-root-workspaces#_debugging)
|
||||
|
||||
[vscode tasks](https://code.visualstudio.com/docs/editor/tasks)
|
||||
|
||||
|
||||
### More images:
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"browserify",
|
||||
"codemirror",
|
||||
"cspell",
|
||||
"electron",
|
||||
"file-loader",
|
||||
"gradle",
|
||||
"html-webpack-plugin",
|
||||
@@ -71,10 +72,6 @@
|
||||
"webpack-cli",
|
||||
"webpack",
|
||||
|
||||
// Electron and dependencies should be updated manually.
|
||||
"electron",
|
||||
"electron-builder",
|
||||
|
||||
// pdfjs-dist requires the canvas package, which cannot be built in
|
||||
// Windows.
|
||||
//
|
||||
@@ -120,18 +117,6 @@
|
||||
"node-fetch",
|
||||
"execa",
|
||||
"open",
|
||||
"pretty-bytes",
|
||||
"strip-ansi",
|
||||
"formidable",
|
||||
|
||||
// @koa/cors has undocumented breaking changes, and the package is not
|
||||
// well supported so we're stuck with latest v3 for now
|
||||
"@koa/cors",
|
||||
|
||||
// Can't upgrade beyond 2.x because it doesn't work with Electron. If trying to
|
||||
// upgrade again, check that adding a link from the CodeMirror editor works.
|
||||
// See /packages/app-desktop/gui/dialogs.ts
|
||||
"smalltalk",
|
||||
|
||||
// Don't think we can trust this lib because they don't release a
|
||||
// changelog and the latest version appears to have breaking changes
|
||||
|
||||
219
yarn.lock
219
yarn.lock
@@ -2722,7 +2722,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
|
||||
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
|
||||
version: 7.22.5
|
||||
resolution: "@babel/runtime@npm:7.22.5"
|
||||
dependencies:
|
||||
@@ -3408,16 +3408,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@electron/notarize@npm:1.2.4":
|
||||
version: 1.2.4
|
||||
resolution: "@electron/notarize@npm:1.2.4"
|
||||
dependencies:
|
||||
debug: ^4.1.1
|
||||
fs-extra: ^9.0.1
|
||||
checksum: 3aa19fb247f9297b96a25f1a082f552e0c78a726ddfc98de9cdd4e4b092fc36fe07d680b762dd5a2bceda97b1044d3a0e6d9eadc5022f7c329a1fcf081133c9b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@electron/remote@npm:2.0.9":
|
||||
version: 2.0.9
|
||||
resolution: "@electron/remote@npm:2.0.9"
|
||||
@@ -4274,7 +4264,6 @@ __metadata:
|
||||
7zip-bin-linux: ^1.0.1
|
||||
7zip-bin-mac: ^1.0.1
|
||||
7zip-bin-win: ^2.1.1
|
||||
"@electron/notarize": 1.2.4
|
||||
"@electron/remote": 2.0.9
|
||||
"@fortawesome/fontawesome-free": 5.15.4
|
||||
"@joeattardi/emoji-button": 4.6.4
|
||||
@@ -4295,6 +4284,7 @@ __metadata:
|
||||
debounce: 1.2.1
|
||||
electron: 19.1.4
|
||||
electron-builder: 22.11.7
|
||||
electron-notarize: 1.2.2
|
||||
electron-rebuild: 3.2.9
|
||||
electron-window-state: 5.0.3
|
||||
formatcoords: 1.1.3
|
||||
@@ -4319,7 +4309,7 @@ __metadata:
|
||||
react: 18.2.0
|
||||
react-datetime: 3.2.0
|
||||
react-dom: 18.2.0
|
||||
react-redux: 8.0.7
|
||||
react-redux: 8.0.5
|
||||
react-select: 5.7.3
|
||||
react-test-renderer: 18.2.0
|
||||
react-toggle-button: 2.2.0
|
||||
@@ -4329,7 +4319,7 @@ __metadata:
|
||||
roboto-fontface: 0.10.0
|
||||
smalltalk: 2.5.1
|
||||
sqlite3: 5.1.6
|
||||
styled-components: 5.3.11
|
||||
styled-components: 5.3.10
|
||||
styled-system: 5.1.5
|
||||
taboverride: 4.0.3
|
||||
tinymce: 5.10.6
|
||||
@@ -4371,8 +4361,8 @@ __metadata:
|
||||
"@joplin/tools": ~2.11
|
||||
"@lezer/highlight": 1.1.4
|
||||
"@react-native-community/clipboard": 1.5.1
|
||||
"@react-native-community/datetimepicker": 7.1.0
|
||||
"@react-native-community/geolocation": 3.0.6
|
||||
"@react-native-community/datetimepicker": 7.0.1
|
||||
"@react-native-community/geolocation": 2.1.0
|
||||
"@react-native-community/netinfo": 9.3.10
|
||||
"@react-native-community/push-notification-ios": 1.11.0
|
||||
"@react-native-community/slider": 4.4.2
|
||||
@@ -4435,8 +4425,7 @@ __metadata:
|
||||
react-native-version-info: 1.1.1
|
||||
react-native-vosk: 0.1.12
|
||||
react-native-webview: 12.4.0
|
||||
react-native-zip-archive: 6.0.9
|
||||
react-redux: 8.0.7
|
||||
react-redux: 7.2.9
|
||||
redux: 4.2.1
|
||||
rn-fetch-blob: 0.12.0
|
||||
stream: 0.0.2
|
||||
@@ -4444,7 +4433,7 @@ __metadata:
|
||||
string-natural-compare: 3.0.1
|
||||
timers: 0.1.1
|
||||
ts-jest: 29.1.0
|
||||
ts-loader: 9.4.3
|
||||
ts-loader: 9.4.2
|
||||
ts-node: 10.9.1
|
||||
typescript: 5.0.2
|
||||
uglify-js: 3.17.4
|
||||
@@ -4463,7 +4452,7 @@ __metadata:
|
||||
"@typescript-eslint/parser": 5.59.0
|
||||
coveralls: 3.1.1
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
domhandler: 3.3.0
|
||||
domutils: 3.1.0
|
||||
entities: 2.2.0
|
||||
eslint: 8.39.0
|
||||
@@ -4611,9 +4600,9 @@ __metadata:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
style-loader: 3.3.3
|
||||
styled-components: 5.3.11
|
||||
styled-components: 5.3.10
|
||||
ts-jest: 29.1.0
|
||||
ts-loader: 9.4.3
|
||||
ts-loader: 9.4.2
|
||||
typescript: 5.0.2
|
||||
webpack: 5.74.0
|
||||
webpack-cli: 4.10.0
|
||||
@@ -4720,7 +4709,7 @@ __metadata:
|
||||
"@joplin/lib": ~2.11
|
||||
"@joplin/renderer": ~2.11
|
||||
"@joplin/tools": ~2.11
|
||||
"@koa/cors": 3.4.3
|
||||
"@koa/cors": 3.1.0
|
||||
"@rmp135/sql-ts": 1.16.0
|
||||
"@types/formidable": 2.0.6
|
||||
"@types/fs-extra": 11.0.1
|
||||
@@ -4738,14 +4727,14 @@ __metadata:
|
||||
bulma: 0.9.4
|
||||
bulma-prefers-dark: 0.1.0-beta.1
|
||||
compare-versions: 3.6.0
|
||||
dayjs: 1.11.8
|
||||
formidable: 2.1.2
|
||||
dayjs: 1.11.7
|
||||
formidable: 2.1.1
|
||||
fs-extra: 11.1.1
|
||||
gulp: 4.0.2
|
||||
html-entities: 1.4.0
|
||||
jest: 29.5.0
|
||||
jest-expect-message: 1.1.3
|
||||
jquery: 3.7.0
|
||||
jquery: 3.6.4
|
||||
jsdom: 21.1.2
|
||||
knex: 2.4.2
|
||||
koa: 2.14.2
|
||||
@@ -4755,7 +4744,7 @@ __metadata:
|
||||
node-cron: 3.0.2
|
||||
node-env-file: 0.1.8
|
||||
node-mocks-http: 1.12.2
|
||||
nodemailer: 6.9.3
|
||||
nodemailer: 6.9.2
|
||||
nodemon: 2.0.22
|
||||
pg: 8.10.0
|
||||
pretty-bytes: 5.6.0
|
||||
@@ -4789,7 +4778,7 @@ __metadata:
|
||||
"@types/node-fetch": 2.6.3
|
||||
"@types/yargs": 17.0.24
|
||||
compare-versions: 3.6.0
|
||||
dayjs: 1.11.8
|
||||
dayjs: 1.11.7
|
||||
execa: 4.1.0
|
||||
fs-extra: 11.1.1
|
||||
gettext-extractor: 3.7.2
|
||||
@@ -4962,12 +4951,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@koa/cors@npm:3.4.3":
|
||||
version: 3.4.3
|
||||
resolution: "@koa/cors@npm:3.4.3"
|
||||
"@koa/cors@npm:3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "@koa/cors@npm:3.1.0"
|
||||
dependencies:
|
||||
vary: ^1.1.2
|
||||
checksum: 51a5b89b4ea19078272ea2702916c90375853b6cfb9b65bf7720653e99b36950c1fd90df66a77fb17839bb130dc7c9f83ccc0bcec40f9d09769f9ed77ced5f23
|
||||
checksum: b6f18de404a967696fe19c9a8d35816e2a845be51f9aa49f1a8d31bbea095eaa20c35eceafe1b764a7e3a912052ca6eaf1965ac34b00020b1ec2823cb60a9b5d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6636,22 +6625,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native-community/datetimepicker@npm:7.1.0":
|
||||
version: 7.1.0
|
||||
resolution: "@react-native-community/datetimepicker@npm:7.1.0"
|
||||
"@react-native-community/datetimepicker@npm:7.0.1":
|
||||
version: 7.0.1
|
||||
resolution: "@react-native-community/datetimepicker@npm:7.0.1"
|
||||
dependencies:
|
||||
invariant: ^2.2.4
|
||||
checksum: c88d19213daec1dc5c6101ad8c694386d79167087e1058c44c2699585dc97c4630c18de214d0607a5e5acd84846a9bb1401fece04fa78b8a010a0290b715040d
|
||||
checksum: 108724a239d086e165ab17fd39fac43a8daf91a852ea9fd40d5bf9a2dd984ad8a473079e6228bc7f9fed0d6cf5610b2f4438142765e228f25aef37f9c6c4f85f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-native-community/geolocation@npm:3.0.6":
|
||||
version: 3.0.6
|
||||
resolution: "@react-native-community/geolocation@npm:3.0.6"
|
||||
"@react-native-community/geolocation@npm:2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "@react-native-community/geolocation@npm:2.1.0"
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
checksum: 813df03599c064639bd5fe90922ab80d20d6224deffc8c6bfb02b7ade3d20f80e1ef6ac19c5d4394e901cca9a9fdb36eceda334a0ea6213e47c3c066921d09a9
|
||||
checksum: 43dd95a8f643af613cd4c8d0a9a557690a70d072f5985c94aa5e09e5cab41e35682a5b022080bb2f276d00029dee1341b0451fcbd8ad8b55a67bc5d98c28f8cc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7692,6 +7681,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-redux@npm:^7.1.20":
|
||||
version: 7.1.24
|
||||
resolution: "@types/react-redux@npm:7.1.24"
|
||||
dependencies:
|
||||
"@types/hoist-non-react-statics": ^3.3.0
|
||||
"@types/react": "*"
|
||||
hoist-non-react-statics: ^3.3.0
|
||||
redux: ^4.0.0
|
||||
checksum: 6582246581331ac7fbbd44aa1f1c136c8a9c8febbcf462432ac81302263308c21e1a2e7868beb7f73bbcb52a8e67935d133cb37f5bdcb6564eaff3a811805101
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-transition-group@npm:^4.4.0":
|
||||
version: 4.4.5
|
||||
resolution: "@types/react-transition-group@npm:4.4.5"
|
||||
@@ -13348,10 +13349,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dayjs@npm:1.11.8":
|
||||
version: 1.11.8
|
||||
resolution: "dayjs@npm:1.11.8"
|
||||
checksum: 4fe04b6df98ba6e5f89b49d80bba603cbf01e21a1b4a24ecb163c94c0ba5324a32ac234a139cee654f89d5277a2bcebca5347e6676c28a0a6d1a90f1d34a42b8
|
||||
"dayjs@npm:1.11.7":
|
||||
version: 1.11.7
|
||||
resolution: "dayjs@npm:1.11.7"
|
||||
checksum: 5003a7c1dd9ed51385beb658231c3548700b82d3548c0cfbe549d85f2d08e90e972510282b7506941452c58d32136d6362f009c77ca55381a09c704e9f177ebb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14263,12 +14264,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"domhandler@npm:5.0.3, domhandler@npm:^5.0.2, domhandler@npm:^5.0.3":
|
||||
version: 5.0.3
|
||||
resolution: "domhandler@npm:5.0.3"
|
||||
"domhandler@npm:3.3.0":
|
||||
version: 3.3.0
|
||||
resolution: "domhandler@npm:3.3.0"
|
||||
dependencies:
|
||||
domelementtype: ^2.3.0
|
||||
checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c
|
||||
domelementtype: ^2.0.1
|
||||
checksum: 850e5e9fee7834ab4314811e18bc1f4294d7eafbf6a79ad03cbe50cf964108935c97257ac248944d72a9312b4a18dfa8323e857d23278964dc83b1f124467fa3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14281,6 +14282,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3":
|
||||
version: 5.0.3
|
||||
resolution: "domhandler@npm:5.0.3"
|
||||
dependencies:
|
||||
domelementtype: ^2.3.0
|
||||
checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"domino@npm:^2.1.6":
|
||||
version: 2.1.6
|
||||
resolution: "domino@npm:2.1.6"
|
||||
@@ -14502,6 +14512,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"electron-notarize@npm:1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "electron-notarize@npm:1.2.2"
|
||||
dependencies:
|
||||
debug: ^4.1.1
|
||||
fs-extra: ^9.0.1
|
||||
checksum: 98909bc90f0840a4bd3da0edc6895d719eb0d17942812a8c8f5a130d323c7fbaafd819245cfe9a6c5b5abfa8dd3b0eb2bd8ee9c0b2dcf0c3b238b6845730c368
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"electron-publish@npm:22.11.7":
|
||||
version: 22.11.7
|
||||
resolution: "electron-publish@npm:22.11.7"
|
||||
@@ -16549,15 +16569,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"formidable@npm:2.1.2":
|
||||
version: 2.1.2
|
||||
resolution: "formidable@npm:2.1.2"
|
||||
"formidable@npm:2.1.1":
|
||||
version: 2.1.1
|
||||
resolution: "formidable@npm:2.1.1"
|
||||
dependencies:
|
||||
dezalgo: ^1.0.4
|
||||
hexoid: ^1.0.0
|
||||
once: ^1.4.0
|
||||
qs: ^6.11.0
|
||||
checksum: 81c8e5d89f5eb873e992893468f0de22c01678ca3d315db62be0560f9de1c77d4faefc9b1f4575098eb2263b3c81ba1024833a9fc3206297ddbac88a4f69b7a8
|
||||
checksum: b407bf89abf0dc40e00efe20edd80aa60ff7e7f4928b3a7048b630d3bb61012f316b69cd3350ccc9aab2d4c682516fea917bc31aef3479d4a652ed97cf8ba9aa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -20541,10 +20561,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jquery@npm:3.7.0":
|
||||
version: 3.7.0
|
||||
resolution: "jquery@npm:3.7.0"
|
||||
checksum: 907785e133afc427650a131af5fccef66a404885037513b3d4d7d63aee6409bcc32a39836868c60e59b05aa0fb8ace8961c18b2ee3ffdf6ffdb571d6d7cd88ff
|
||||
"jquery@npm:3.6.4":
|
||||
version: 3.6.4
|
||||
resolution: "jquery@npm:3.6.4"
|
||||
checksum: 8354f7bd0a0424aa714ee1b6b1ef74b410f834eb5c8501682289b358bc151f11677f11188b544f3bb49309d6ec4d15d1a5de175661250c206b06185a252f706f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -24272,10 +24292,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nodemailer@npm:6.9.3":
|
||||
version: 6.9.3
|
||||
resolution: "nodemailer@npm:6.9.3"
|
||||
checksum: 3bea8316652c0578515d9146d2f24660e4855807520153f061d39af76b440a4f61b4e70f10fed35f8f12f115f6aea1aeb483ea7ba0337c0e3e675f117c41c611
|
||||
"nodemailer@npm:6.9.2":
|
||||
version: 6.9.2
|
||||
resolution: "nodemailer@npm:6.9.2"
|
||||
checksum: 76a7ea0cff221914d3ebb666f26f30c9374f84dd80c1b95bb186873295ecf8dea887ed36a1e8d5d90930c36b30f85ceac062fc9efb7bc75821fe497be4103d25
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -26724,7 +26744,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:^6.10.3":
|
||||
"qs@npm:^6.10.3, qs@npm:^6.11.0":
|
||||
version: 6.11.0
|
||||
resolution: "qs@npm:6.11.0"
|
||||
dependencies:
|
||||
@@ -26733,15 +26753,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:^6.11.0":
|
||||
version: 6.11.2
|
||||
resolution: "qs@npm:6.11.2"
|
||||
dependencies:
|
||||
side-channel: ^1.0.4
|
||||
checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:^6.4.0, qs@npm:^6.9.4":
|
||||
version: 6.10.2
|
||||
resolution: "qs@npm:6.10.2"
|
||||
@@ -27020,7 +27031,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:^17.0.1":
|
||||
"react-is@npm:^17.0.1, react-is@npm:^17.0.2":
|
||||
version: 17.0.2
|
||||
resolution: "react-is@npm:17.0.2"
|
||||
checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8
|
||||
@@ -27369,11 +27380,11 @@ __metadata:
|
||||
|
||||
"react-native-vosk@patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch::locator=root%40workspace%3A.":
|
||||
version: 0.1.12
|
||||
resolution: "react-native-vosk@patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch::version=0.1.12&hash=5deb2c&locator=root%40workspace%3A."
|
||||
resolution: "react-native-vosk@patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch::version=0.1.12&hash=b82215&locator=root%40workspace%3A."
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
checksum: ca31cf6345f422b778c18bc2365f5114ab2c3e20214e684bbb77220e6476cd877bb5c256d88070b2235f01714e8cd8e5bee999b854894b066d31834b9b17dca4
|
||||
checksum: 9451534de711f28274e117087a2c27266ee60ffc46723136841669c02345fd5644333a204c98c18d82e2c4221bb65906ac20529fd63fdcd5439c8aad86710e3b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -27390,16 +27401,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-zip-archive@npm:6.0.9":
|
||||
version: 6.0.9
|
||||
resolution: "react-native-zip-archive@npm:6.0.9"
|
||||
peerDependencies:
|
||||
react: ">=16.8.6"
|
||||
react-native: ">=0.60.0"
|
||||
checksum: 96c83864a596fcd8a82f55a01fa5e97822c9e80c7cf55de6b011a27cc436fbf58371207cb61c63b19dbd22b852ee62b95935358b4b9a73686695133dffdcfe27
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native@npm:0.70.6":
|
||||
version: 0.70.6
|
||||
resolution: "react-native@npm:0.70.6"
|
||||
@@ -27503,9 +27504,30 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-redux@npm:8.0.7":
|
||||
version: 8.0.7
|
||||
resolution: "react-redux@npm:8.0.7"
|
||||
"react-redux@npm:7.2.9":
|
||||
version: 7.2.9
|
||||
resolution: "react-redux@npm:7.2.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.15.4
|
||||
"@types/react-redux": ^7.1.20
|
||||
hoist-non-react-statics: ^3.3.2
|
||||
loose-envify: ^1.4.0
|
||||
prop-types: ^15.7.2
|
||||
react-is: ^17.0.2
|
||||
peerDependencies:
|
||||
react: ^16.8.3 || ^17 || ^18
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
checksum: 369a2bdcf87915659af9e5c55abfd9f52a84e43e0d12dcc108ed17dbe6933558b7b7fc12caa9c10c1a10a8be7df89454b6c96989d8573fedec1a772c94a1f145
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-redux@npm:8.0.5":
|
||||
version: 8.0.5
|
||||
resolution: "react-redux@npm:8.0.5"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.12.1
|
||||
"@types/hoist-non-react-statics": ^3.3.1
|
||||
@@ -27514,16 +27536,13 @@ __metadata:
|
||||
react-is: ^18.0.0
|
||||
use-sync-external-store: ^1.0.0
|
||||
peerDependencies:
|
||||
"@reduxjs/toolkit": ^1 || ^2.0.0-beta.0
|
||||
"@types/react": ^16.8 || ^17.0 || ^18.0
|
||||
"@types/react-dom": ^16.8 || ^17.0 || ^18.0
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
react-native: ">=0.59"
|
||||
redux: ^4 || ^5.0.0-beta.0
|
||||
redux: ^4
|
||||
peerDependenciesMeta:
|
||||
"@reduxjs/toolkit":
|
||||
optional: true
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
@@ -27534,7 +27553,7 @@ __metadata:
|
||||
optional: true
|
||||
redux:
|
||||
optional: true
|
||||
checksum: d903aa79b12154258fd76b8e61fcf56f72123f69c31033b262805646371e23822cd0cd11d24194cda1e03569a7b1bf86e935cd57a9bab4523186804ed2742fac
|
||||
checksum: a108f4f7ead6ac005e656d46051474a2bbdb31ede481bbbb3d8d779c1a35e1940b8655577cc5021313411864d305f67fc719aa48d6e5ed8288cf9cbe8b7042e4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -30663,9 +30682,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"styled-components@npm:5.3.11":
|
||||
version: 5.3.11
|
||||
resolution: "styled-components@npm:5.3.11"
|
||||
"styled-components@npm:5.3.10":
|
||||
version: 5.3.10
|
||||
resolution: "styled-components@npm:5.3.10"
|
||||
dependencies:
|
||||
"@babel/helper-module-imports": ^7.0.0
|
||||
"@babel/traverse": ^7.4.5
|
||||
@@ -30681,7 +30700,7 @@ __metadata:
|
||||
react: ">= 16.8.0"
|
||||
react-dom: ">= 16.8.0"
|
||||
react-is: ">= 16.8.0"
|
||||
checksum: 10edd4dae3b0231ec02d86bdd09c88e894eedfa7e9d4f8e562b09fb69c67a27d586cbcf35c785002d59b3bf11e6c0940b0efce40d13ae9ed148b26b1dc8f3284
|
||||
checksum: 46dfea6c435516b22aae25798cf01f9b08423cfb517cfea9db760a18c941bddf79abaad9bedb9b3cca6faad24bd7eb4ef4dd21ae84b356ae29d279b2d571f7b7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -31728,9 +31747,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-loader@npm:9.4.3":
|
||||
version: 9.4.3
|
||||
resolution: "ts-loader@npm:9.4.3"
|
||||
"ts-loader@npm:9.4.2":
|
||||
version: 9.4.2
|
||||
resolution: "ts-loader@npm:9.4.2"
|
||||
dependencies:
|
||||
chalk: ^4.1.0
|
||||
enhanced-resolve: ^5.0.0
|
||||
@@ -31739,7 +31758,7 @@ __metadata:
|
||||
peerDependencies:
|
||||
typescript: "*"
|
||||
webpack: ^5.0.0
|
||||
checksum: 139ed53bc60717d0ca231cdffbdef7566b9feda11c72fecc697983113f1266ccca2e1cdf191f841a43afa6b87d6afe57a0caf4feecf02f30845aa7ac6f2411a4
|
||||
checksum: 6f306ee4c615c2a159fb177561e3fb86ca2cbd6c641e710d408a64b4978e1ff3f2c9733df07bff27d3f82efbfa7c287523d4306049510c7485ac2669a9c37eb0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user