mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Merge remote-tracking branch 'origin/dev' into issue-8408
This commit is contained in:
commit
c88e147343
@ -0,0 +1,25 @@
|
||||
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
|
||||
index 0f52b73c61625db2a3081c0950b6bdd2b06e3d40..b0fc3de4be0b3a26b638683613c63c783c2739bb 100644
|
||||
--- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
|
||||
+++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
|
||||
@@ -38,7 +38,7 @@ import com.facebook.react.uimanager.common.ViewUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
-import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
+import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -151,7 +151,10 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
}
|
||||
|
||||
private class ConcurrentOperationQueue {
|
||||
- private final Queue<UIThreadOperation> mQueue = new ConcurrentLinkedQueue<>();
|
||||
+ // Patch: Use LinkedBlockingQueue instead of ConcurrentLinkedQueue.
|
||||
+ // In some versions of Android, ConcurrentLinkedQueue is known to drop
|
||||
+ // items, causing crashing. See https://github.com/laurent22/joplin/issues/8425
|
||||
+ private final Queue<UIThreadOperation> mQueue = new LinkedBlockingQueue<>();
|
||||
@Nullable private UIThreadOperation mPeekedOperation = null;
|
||||
|
||||
@AnyThread
|
@ -0,0 +1,27 @@
|
||||
diff --git a/android/src/main/java/com/swmansion/reanimated/NodesManager.java b/android/src/main/java/com/swmansion/reanimated/NodesManager.java
|
||||
index e974f8eb827a35be4d7e5fa9b096af9387c595dd..bc9e5ff566c9484274e8eacefc88327a5ff30def 100644
|
||||
--- a/android/src/main/java/com/swmansion/reanimated/NodesManager.java
|
||||
+++ b/android/src/main/java/com/swmansion/reanimated/NodesManager.java
|
||||
@@ -34,7 +34,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
-import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
+import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -80,7 +80,12 @@ public class NodesManager implements EventDispatcherListener {
|
||||
private ReactApplicationContext mReactApplicationContext;
|
||||
private RCTEventEmitter mCustomEventHandler;
|
||||
private List<OnAnimationFrame> mFrameCallbacks = new ArrayList<>();
|
||||
- private ConcurrentLinkedQueue<CopiedEvent> mEventQueue = new ConcurrentLinkedQueue<>();
|
||||
+
|
||||
+ // Patch: On some versions of Android, ConcurrentLinkedQueue is known to
|
||||
+ // drop items. LinkedBlockingQueue is a potentially-slower alternative that
|
||||
+ // should not drop items.
|
||||
+ // See https://github.com/laurent22/joplin/issues/8425
|
||||
+ private LinkedBlockingQueue<CopiedEvent> mEventQueue = new LinkedBlockingQueue<>();
|
||||
public double currentFrameTimeMs;
|
||||
public Set<String> uiProps = Collections.emptySet();
|
||||
public Set<String> nativeProps = Collections.emptySet();
|
@ -90,7 +90,7 @@
|
||||
"@types/fs-extra": "11.0.1",
|
||||
"eslint-plugin-github": "4.8.0",
|
||||
"http-server": "14.1.1",
|
||||
"node-gyp": "9.3.1",
|
||||
"node-gyp": "9.4.0",
|
||||
"nodemon": "2.0.22"
|
||||
},
|
||||
"packageManager": "yarn@3.5.0",
|
||||
@ -99,6 +99,8 @@
|
||||
"react-native-vosk@0.1.12": "patch:react-native-vosk@npm%3A0.1.12#./.yarn/patches/react-native-vosk-npm-0.1.12-76b1caaae8.patch",
|
||||
"eslint@8.39.0": "patch:eslint@npm%3A8.39.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
|
||||
"eslint@^8.13.0": "patch:eslint@npm%3A8.39.0#./.yarn/patches/eslint-npm-8.39.0-d92bace04d.patch",
|
||||
"app-builder-lib@24.4.0": "patch:app-builder-lib@npm%3A24.4.0#./.yarn/patches/app-builder-lib-npm-24.4.0-05322ff057.patch"
|
||||
"app-builder-lib@24.4.0": "patch:app-builder-lib@npm%3A24.4.0#./.yarn/patches/app-builder-lib-npm-24.4.0-05322ff057.patch",
|
||||
"react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch",
|
||||
"react-native-reanimated@3.3.0": "patch:react-native-reanimated@npm%3A3.3.0#./.yarn/patches/react-native-animation-fix/react-native-reanimated-npm-3.3.0-fb4272741c.patch"
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
**A test...** Test
|
||||
**A test...** Test
|
@ -66,8 +66,7 @@ import syncDebugLog from '@joplin/lib/services/synchronizer/syncDebugLog';
|
||||
import eventManager from '@joplin/lib/eventManager';
|
||||
import path = require('path');
|
||||
import { checkPreInstalledDefaultPlugins, installDefaultPlugins, setSettingsForDefaultPlugins } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils';
|
||||
// import { runIntegrationTests } from '@joplin/lib/services/e2ee/ppkTestUtils';
|
||||
import { initializeInboxFetcher, inboxFetcher } from '@joplin/lib/utils/inboxFetcher';
|
||||
import userFetcher, { initializeUserFetcher } from '@joplin/lib/utils/userFetcher';
|
||||
|
||||
const pluginClasses = [
|
||||
require('./plugins/GotoAnything').default,
|
||||
@ -488,8 +487,8 @@ class Application extends BaseApplication {
|
||||
shim.setInterval(() => { runAutoUpdateCheck(); }, 12 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
initializeInboxFetcher();
|
||||
shim.setInterval(() => { void inboxFetcher(); }, 1000 * 60 * 60);
|
||||
initializeUserFetcher();
|
||||
shim.setInterval(() => { void userFetcher(); }, 1000 * 60 * 60);
|
||||
|
||||
this.updateTray();
|
||||
|
||||
|
@ -25,7 +25,7 @@ const JoplinCloudConfigScreen = (props: JoplinCloudConfigScreenProps) => {
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
inboxEmail: state.settings['emailToNote.inboxEmail'],
|
||||
inboxEmail: state.settings['sync.10.inboxEmail'],
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -18,7 +18,7 @@ export const runtime = (): CommandRuntime => {
|
||||
if (!folder) throw new Error(`No such folder: ${folderId}`);
|
||||
|
||||
let deleteMessage = _('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', substrWithEllipsis(folder.title, 0, 32));
|
||||
if (folderId === context.state.settings['emailToNote.inboxJopId']) {
|
||||
if (folderId === context.state.settings['sync.10.inboxId']) {
|
||||
deleteMessage = _('Delete the Inbox notebook?\n\nIf you delete the inbox notebook, any email that\'s recently been sent to it may be lost.');
|
||||
}
|
||||
|
||||
|
@ -599,6 +599,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
joplinInsert: { inline: 'ins', remove: 'all' },
|
||||
joplinSub: { inline: 'sub', remove: 'all' },
|
||||
joplinSup: { inline: 'sup', remove: 'all' },
|
||||
code: { inline: 'code', remove: 'all', attributes: { spellcheck: false } },
|
||||
},
|
||||
setup: (editor: Editor) => {
|
||||
editor.addCommand('joplinAttach', () => {
|
||||
@ -697,7 +698,17 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
setEditorReady(true);
|
||||
});
|
||||
|
||||
const preprocessContent = () => {
|
||||
// Disable spellcheck for all inline code blocks.
|
||||
const codeElements = editor.dom.doc.querySelectorAll('code.inline-code');
|
||||
for (const code of codeElements) {
|
||||
code.setAttribute('spellcheck', 'false');
|
||||
}
|
||||
};
|
||||
|
||||
editor.on('SetContent', () => {
|
||||
preprocessContent();
|
||||
|
||||
props_onMessage.current({ channel: 'noteRenderComplete' });
|
||||
});
|
||||
},
|
||||
@ -714,18 +725,10 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
// Set the initial content and load the plugin CSS and JS files
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
const loadDocumentAssets = (editor: any, pluginAssets: any[]) => {
|
||||
// Note: The way files are cached is not correct because it assumes there's only one version
|
||||
// of each file. However, when the theme change, a new CSS file, specific to the theme, is
|
||||
// created. That file should not be loaded on top of the previous one, but as a replacement.
|
||||
// Otherwise it would do this:
|
||||
// - Try to load CSS for theme 1 => OK
|
||||
// - Try to load CSS for theme 2 => OK
|
||||
// - Try to load CSS for theme 1 => Skip because the file is in cache. As a result, theme 2
|
||||
// incorrectly stay.
|
||||
// The fix would be to make allAssets() return a name and a version for each asset. Then the loading
|
||||
// code would check this and either append the CSS or replace.
|
||||
const documentCssElements: Record<string, HTMLLinkElement> = {};
|
||||
const documentScriptElements: Record<string, HTMLScriptElement> = {};
|
||||
|
||||
const loadDocumentAssets = (editor: any, pluginAssets: any[]) => {
|
||||
const theme = themeStyle(props.themeId);
|
||||
|
||||
let docHead_: any = null;
|
||||
@ -736,49 +739,72 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
return docHead_;
|
||||
}
|
||||
|
||||
const cssFiles = [
|
||||
const allCssFiles = [
|
||||
`${bridge().vendorDir()}/lib/@fortawesome/fontawesome-free/css/all.min.css`,
|
||||
`gui/note-viewer/pluginAssets/highlight.js/${theme.codeThemeCss}`,
|
||||
].concat(
|
||||
pluginAssets
|
||||
.filter((a: any) => a.mime === 'text/css')
|
||||
.map((a: any) => a.path)
|
||||
).filter((path: string) => !loadedCssFiles_.includes(path));
|
||||
);
|
||||
|
||||
const jsFiles = [].concat(
|
||||
const allJsFiles = [].concat(
|
||||
pluginAssets
|
||||
.filter((a: any) => a.mime === 'application/javascript')
|
||||
.map((a: any) => a.path)
|
||||
).filter((path: string) => !loadedJsFiles_.includes(path));
|
||||
);
|
||||
|
||||
for (const cssFile of cssFiles) loadedCssFiles_.push(cssFile);
|
||||
for (const jsFile of jsFiles) loadedJsFiles_.push(jsFile);
|
||||
|
||||
// Remove all previously loaded files that aren't in the assets this time.
|
||||
// Note: This is important to ensure that we properly change themes.
|
||||
// See https://github.com/laurent22/joplin/issues/8520
|
||||
for (const cssFile of loadedCssFiles_) {
|
||||
if (!allCssFiles.includes(cssFile)) {
|
||||
documentCssElements[cssFile]?.remove();
|
||||
delete documentCssElements[cssFile];
|
||||
}
|
||||
}
|
||||
|
||||
for (const jsFile of loadedJsFiles_) {
|
||||
if (!allJsFiles.includes(jsFile)) {
|
||||
documentScriptElements[jsFile]?.remove();
|
||||
delete documentScriptElements[jsFile];
|
||||
}
|
||||
}
|
||||
|
||||
const newCssFiles = allCssFiles.filter((path: string) => !loadedCssFiles_.includes(path));
|
||||
const newJsFiles = allJsFiles.filter((path: string) => !loadedJsFiles_.includes(path));
|
||||
|
||||
loadedCssFiles_ = allCssFiles;
|
||||
loadedJsFiles_ = allJsFiles;
|
||||
|
||||
// console.info('loadDocumentAssets: files to load', cssFiles, jsFiles);
|
||||
|
||||
if (cssFiles.length) {
|
||||
for (const cssFile of cssFiles) {
|
||||
const script = editor.dom.create('link', {
|
||||
if (newCssFiles.length) {
|
||||
for (const cssFile of newCssFiles) {
|
||||
const style = editor.dom.create('link', {
|
||||
rel: 'stylesheet',
|
||||
type: 'text/css',
|
||||
href: cssFile,
|
||||
class: 'jop-tinymce-css',
|
||||
});
|
||||
|
||||
docHead().appendChild(script);
|
||||
documentCssElements[cssFile] = style;
|
||||
docHead().appendChild(style);
|
||||
}
|
||||
}
|
||||
|
||||
if (jsFiles.length) {
|
||||
if (newJsFiles.length) {
|
||||
const editorElementId = editor.dom.uniqueId();
|
||||
|
||||
for (const jsFile of jsFiles) {
|
||||
for (const jsFile of newJsFiles) {
|
||||
const script = editor.dom.create('script', {
|
||||
id: editorElementId,
|
||||
type: 'text/javascript',
|
||||
src: jsFile,
|
||||
});
|
||||
|
||||
documentScriptElements[jsFile] = script;
|
||||
docHead().appendChild(script);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ interface Props {
|
||||
onClose(): void;
|
||||
shares: StateShare[];
|
||||
shareUsers: Record<string, StateShareUser[]>;
|
||||
isJoplinCloud: boolean;
|
||||
canUseSharePermissions: boolean;
|
||||
}
|
||||
|
||||
interface RecipientDeleteEvent {
|
||||
@ -261,7 +261,7 @@ function ShareFolderDialog(props: Props) {
|
||||
function renderAddRecipient() {
|
||||
const disabled = shareState !== ShareState.Idle;
|
||||
|
||||
const dropdown = !props.isJoplinCloud ? null : <Dropdown className="permission-dropdown" options={permissionOptions} value={recipientPermissions} onChange={recipientPermissions_change}/>;
|
||||
const dropdown = !props.canUseSharePermissions ? null : <Dropdown className="permission-dropdown" options={permissionOptions} value={recipientPermissions} onChange={recipientPermissions_change}/>;
|
||||
|
||||
return (
|
||||
<StyledAddRecipient>
|
||||
@ -306,7 +306,7 @@ function ShareFolderDialog(props: Props) {
|
||||
|
||||
const permission = shareUser.can_write ? 'can_read_and_write' : 'can_read';
|
||||
const enabled = !recipientsBeingUpdated[shareUser.id];
|
||||
const dropdown = !props.isJoplinCloud ? null : <Dropdown disabled={!enabled} className="permission-dropdown" value={permission} options={permissionOptions} variant={DropdownVariant.NoBorder} onChange={event => recipient_permissionChange(shareUser.id, event.value)}/>;
|
||||
const dropdown = !props.canUseSharePermissions ? null : <Dropdown disabled={!enabled} className="permission-dropdown" value={permission} options={permissionOptions} variant={DropdownVariant.NoBorder} onChange={event => recipient_permissionChange(shareUser.id, event.value)}/>;
|
||||
|
||||
return (
|
||||
<StyledRecipient key={shareUser.user.email} index={index}>
|
||||
@ -407,7 +407,7 @@ const mapStateToProps = (state: State) => {
|
||||
return {
|
||||
shares: state.shareService.shares,
|
||||
shareUsers: state.shareService.shareUsers,
|
||||
isJoplinCloud: state.settings['sync.target'] === 10,
|
||||
canUseSharePermissions: state.settings['sync.target'] === 10 && state.settings['sync.10.canUseSharePermissions'],
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@joplin/app-desktop",
|
||||
"version": "2.12.8",
|
||||
"version": "2.12.9",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"private": true,
|
||||
@ -161,7 +161,7 @@
|
||||
"react": "18.2.0",
|
||||
"react-datetime": "3.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-redux": "8.0.7",
|
||||
"react-redux": "8.1.1",
|
||||
"react-select": "5.7.3",
|
||||
"react-toggle-button": "2.2.0",
|
||||
"react-tooltip": "4.5.1",
|
||||
|
@ -31,6 +31,12 @@
|
||||
# ./runForTesting.sh 1 createUsers,createData,reset,sync && ./runForTesting.sh 1a reset,sync && ./runForTesting.sh 1
|
||||
# ./runForTesting.sh 1a
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
# Team accounts:
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
# ./runForTesting.sh 1 createTeams,createData,resetTeam,sync && ./runForTesting.sh 2 resetTeam,sync && ./runForTesting.sh 1
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
@ -54,6 +60,16 @@ if [ "$USER_NUM" = "1b" ]; then
|
||||
USER_PROFILE_NUM=1b
|
||||
fi
|
||||
|
||||
if [ "$USER_NUM" = "2a" ]; then
|
||||
USER_NUM=2
|
||||
USER_PROFILE_NUM=2a
|
||||
fi
|
||||
|
||||
if [ "$USER_NUM" = "2b" ]; then
|
||||
USER_NUM=2
|
||||
USER_PROFILE_NUM=2b
|
||||
fi
|
||||
|
||||
COMMANDS=($(echo $2 | tr "," "\n"))
|
||||
PROFILE_DIR=~/.config/joplindev-desktop-$USER_PROFILE_NUM
|
||||
SYNC_TARGET=10
|
||||
@ -74,6 +90,10 @@ do
|
||||
|
||||
curl --data '{"action": "createUserDeletions"}' -H 'Content-Type: application/json' http://api.joplincloud.local:22300/api/debug
|
||||
|
||||
elif [[ $CMD == "createTeams" ]]; then
|
||||
|
||||
curl --data '{"action": "createTeams"}' -H 'Content-Type: application/json' http://api.joplincloud.local:22300/api/debug
|
||||
|
||||
elif [[ $CMD == "createData" ]]; then
|
||||
|
||||
echo 'mkbook "shared"' >> "$CMD_FILE"
|
||||
@ -96,6 +116,16 @@ do
|
||||
echo "config sync.$SYNC_TARGET.path http://api.joplincloud.local:22300" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.userContentPath http://joplinusercontent.local:22300" >> "$CMD_FILE"
|
||||
fi
|
||||
|
||||
elif [[ $CMD == "resetTeam" ]]; then
|
||||
|
||||
USER_EMAIL="teamuser1-$USER_NUM@example.com"
|
||||
rm -rf "$PROFILE_DIR"
|
||||
|
||||
echo "config keychain.supported 0" >> "$CMD_FILE"
|
||||
echo "config sync.target $SYNC_TARGET" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.username $USER_EMAIL" >> "$CMD_FILE"
|
||||
echo "config sync.$SYNC_TARGET.password 111111" >> "$CMD_FILE"
|
||||
|
||||
elif [[ $CMD == "e2ee" ]]; then
|
||||
|
||||
|
@ -362,13 +362,13 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
||||
<View key="joplinCloud">
|
||||
<View style={this.styles().settingContainerNoBottomBorder}>
|
||||
<Text style={this.styles().settingText}>{_('Email to note')}</Text>
|
||||
<Text style={{ fontWeight: 'bold' }}>{this.props.settings['emailToNote.inboxEmail']}</Text>
|
||||
<Text style={{ fontWeight: 'bold' }}>{this.props.settings['sync.10.inboxEmail']}</Text>
|
||||
</View>
|
||||
{
|
||||
this.renderButton(
|
||||
'emailToNote.inboxEmail',
|
||||
'sync.10.inboxEmail',
|
||||
_('Copy to clipboard'),
|
||||
() => Clipboard.setString(this.props.settings['emailToNote.inboxEmail']),
|
||||
() => Clipboard.setString(this.props.settings['sync.10.inboxEmail']),
|
||||
{ description }
|
||||
)
|
||||
}
|
||||
|
@ -528,6 +528,6 @@ export default connect((state: AppState) => {
|
||||
isOnMobileData: state.isOnMobileData,
|
||||
syncOnlyOverWifi: state.settings['sync.mobileWifiOnly'],
|
||||
profileConfig: state.profileConfig,
|
||||
inboxJopId: state.settings['emailToNote.inboxJopId'],
|
||||
inboxJopId: state.settings['sync.10.inboxId'],
|
||||
};
|
||||
})(SideMenuContentComponent);
|
||||
|
@ -467,7 +467,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNDateTimePicker (7.1.0):
|
||||
- React-Core
|
||||
- RNDeviceInfo (10.6.0):
|
||||
- RNDeviceInfo (10.6.1):
|
||||
- React-Core
|
||||
- RNExitApp (1.1.0):
|
||||
- React
|
||||
@ -850,7 +850,7 @@ SPEC CHECKSUMS:
|
||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||
RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8
|
||||
RNDateTimePicker: 7ecd54a97fc3749f38c3c89a171f6cbd52f3c142
|
||||
RNDeviceInfo: 475a4c447168d0ad4c807e48ef5e0963a0f4eb1b
|
||||
RNDeviceInfo: ab292735ad4fccc5f2aec0c773f7a7f03c7073ae
|
||||
RNExitApp: c4e052df2568b43bec8a37c7cd61194d4cfee2c3
|
||||
RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592
|
||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||
|
@ -53,11 +53,11 @@
|
||||
"react-native-file-viewer": "2.1.5",
|
||||
"react-native-fingerprint-scanner": "6.0.0",
|
||||
"react-native-fs": "2.20.0",
|
||||
"react-native-gesture-handler": "2.11.0",
|
||||
"react-native-gesture-handler": "2.12.0",
|
||||
"react-native-get-random-values": "1.9.0",
|
||||
"react-native-image-picker": "5.4.2",
|
||||
"react-native-image-resizer": "1.4.5",
|
||||
"react-native-localize": "3.0.1",
|
||||
"react-native-localize": "3.0.2",
|
||||
"react-native-modal-datetime-picker": "15.0.1",
|
||||
"react-native-paper": "5.8.0",
|
||||
"react-native-popup-menu": "0.16.1",
|
||||
@ -74,7 +74,7 @@
|
||||
"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": "8.1.1",
|
||||
"redux": "4.2.1",
|
||||
"rn-fetch-blob": "0.12.0",
|
||||
"stream": "0.0.2",
|
||||
|
@ -117,7 +117,7 @@ import sensorInfo, { SensorInfo } from './components/biometrics/sensorInfo';
|
||||
import { getCurrentProfile } from '@joplin/lib/services/profileConfig';
|
||||
import { getDatabaseName, getProfilesRootDir, getResourceDir, setDispatch } from './services/profiles';
|
||||
import { ReactNode } from 'react';
|
||||
import { initializeInboxFetcher, inboxFetcher } from '@joplin/lib/utils/inboxFetcher';
|
||||
import userFetcher, { initializeUserFetcher } from '@joplin/lib/utils/userFetcher';
|
||||
import { parseShareCache } from '@joplin/lib/services/share/reducer';
|
||||
import autodetectTheme, { onSystemColorSchemeChange } from './utils/autodetectTheme';
|
||||
|
||||
@ -665,8 +665,8 @@ async function initialize(dispatch: Function) {
|
||||
|
||||
reg.setupRecurrentSync();
|
||||
|
||||
initializeInboxFetcher();
|
||||
PoorManIntervals.setInterval(() => { void inboxFetcher(); }, 1000 * 60 * 60);
|
||||
initializeUserFetcher();
|
||||
PoorManIntervals.setInterval(() => { void userFetcher(); }, 1000 * 60 * 60);
|
||||
|
||||
PoorManIntervals.setTimeout(() => {
|
||||
void AlarmService.garbageCollect();
|
||||
|
@ -38,6 +38,8 @@ export interface DeleteOptions {
|
||||
// sync, we don't need to track the deletion, because the operation doesn't
|
||||
// need to applied again on next sync.
|
||||
trackDeleted?: boolean;
|
||||
|
||||
disableReadOnlyCheck?: boolean;
|
||||
}
|
||||
|
||||
class BaseModel {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ModelType, DeleteOptions } from '../BaseModel';
|
||||
import { BaseItemEntity, NoteEntity } from '../services/database/types';
|
||||
import { BaseItemEntity, DeletedItemEntity, NoteEntity } from '../services/database/types';
|
||||
import Setting from './Setting';
|
||||
import BaseModel from '../BaseModel';
|
||||
import time from '../time';
|
||||
@ -285,7 +285,7 @@ export default class BaseItem extends BaseModel {
|
||||
});
|
||||
}
|
||||
|
||||
if (needsReadOnlyChecks(this.modelType(), options.changeSource, this.syncShareCache)) {
|
||||
if (needsReadOnlyChecks(this.modelType(), options.changeSource, this.syncShareCache, options.disableReadOnlyCheck)) {
|
||||
const previousItems = await this.loadItemsByTypeAndIds(this.modelType(), ids, { fields: ['share_id', 'id'] });
|
||||
checkIfItemsCanBeChanged(this.modelType(), options.changeSource, previousItems, this.syncShareCache);
|
||||
}
|
||||
@ -321,7 +321,7 @@ export default class BaseItem extends BaseModel {
|
||||
// - Client 1 syncs with target 2 only => the note is *not* deleted from target 2 because no information
|
||||
// that it was previously deleted exist (deleted_items entry has been deleted).
|
||||
// The solution would be to permanently store the list of deleted items on each client.
|
||||
public static deletedItems(syncTarget: number) {
|
||||
public static deletedItems(syncTarget: number): Promise<DeletedItemEntity[]> {
|
||||
return this.db().selectAll('SELECT * FROM deleted_items WHERE sync_target = ?', [syncTarget]);
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,21 @@ export default class Folder extends BaseItem {
|
||||
return this.db().exec(query);
|
||||
}
|
||||
|
||||
public static async deleteAllByShareId(shareId: string, deleteOptions: DeleteOptions = null) {
|
||||
const tableNameToClasses: Record<string, any> = {
|
||||
'folders': Folder,
|
||||
'notes': Note,
|
||||
'resources': Resource,
|
||||
};
|
||||
|
||||
for (const tableName of ['folders', 'notes', 'resources']) {
|
||||
const ItemClass = tableNameToClasses[tableName];
|
||||
const rows = await this.db().selectAll(`SELECT id FROM ${tableName} WHERE share_id = ?`, [shareId]);
|
||||
const ids: string[] = rows.map(r => r.id);
|
||||
await ItemClass.batchDelete(ids, deleteOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public static async delete(folderId: string, options: DeleteOptions = null) {
|
||||
options = {
|
||||
deleteChildren: true,
|
||||
@ -90,12 +105,16 @@ export default class Folder extends BaseItem {
|
||||
if (!folder) return; // noop
|
||||
|
||||
if (options.deleteChildren) {
|
||||
const childrenDeleteOptions: DeleteOptions = {
|
||||
disableReadOnlyCheck: options.disableReadOnlyCheck,
|
||||
};
|
||||
|
||||
const noteIds = await Folder.noteIds(folderId);
|
||||
await Note.batchDelete(noteIds);
|
||||
await Note.batchDelete(noteIds, childrenDeleteOptions);
|
||||
|
||||
const subFolderIds = await Folder.subFolderIds(folderId);
|
||||
for (let i = 0; i < subFolderIds.length; i++) {
|
||||
await Folder.delete(subFolderIds[i]);
|
||||
await Folder.delete(subFolderIds[i], childrenDeleteOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,7 +781,14 @@ export default class Folder extends BaseItem {
|
||||
|
||||
syncDebugLog.info('Folder Save:', o);
|
||||
|
||||
const savedFolder: FolderEntity = await super.save(o, options);
|
||||
let savedFolder: FolderEntity = await super.save(o, options);
|
||||
|
||||
// Ensures that any folder added to the state has all the required
|
||||
// properties, in particular "share_id" and "parent_id', which are
|
||||
// required in various parts of the code.
|
||||
if (!('share_id' in savedFolder) || !('parent_id' in savedFolder)) {
|
||||
savedFolder = await this.load(savedFolder.id);
|
||||
}
|
||||
|
||||
this.dispatch({
|
||||
type: 'FOLDER_UPDATE_ONE',
|
||||
|
@ -21,6 +21,7 @@ export default class ItemChange extends BaseModel {
|
||||
public static SOURCE_UNSPECIFIED = 1;
|
||||
public static SOURCE_SYNC = 2;
|
||||
public static SOURCE_DECRYPTION = 2; // CAREFUL - SAME ID AS SOURCE_SYNC!
|
||||
public static SOURCE_SHARE_SERVICE = 4;
|
||||
|
||||
public static tableName() {
|
||||
return 'item_changes';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import BaseModel, { ModelType } from '../BaseModel';
|
||||
import BaseModel, { DeleteOptions, ModelType } from '../BaseModel';
|
||||
import BaseItem from './BaseItem';
|
||||
import ItemChange from './ItemChange';
|
||||
import Setting from './Setting';
|
||||
@ -744,7 +744,7 @@ export default class Note extends BaseItem {
|
||||
return note;
|
||||
}
|
||||
|
||||
public static async batchDelete(ids: string[], options: any = null) {
|
||||
public static async batchDelete(ids: string[], options: DeleteOptions = null) {
|
||||
ids = ids.slice();
|
||||
|
||||
while (ids.length) {
|
||||
|
@ -717,6 +717,12 @@ class Setting extends BaseModel {
|
||||
secure: true,
|
||||
},
|
||||
|
||||
'sync.10.inboxEmail': { value: '', type: SettingItemType.String, public: false },
|
||||
|
||||
'sync.10.inboxId': { value: '', type: SettingItemType.String, public: false },
|
||||
|
||||
'sync.10.canUseSharePermissions': { value: false, type: SettingItemType.Bool, public: false },
|
||||
|
||||
'sync.5.syncTargets': { value: {}, type: SettingItemType.Object, public: false },
|
||||
|
||||
'sync.resourceDownloadMode': {
|
||||
@ -1714,10 +1720,6 @@ class Setting extends BaseModel {
|
||||
label: () => _('Voice typing language files (URL)'),
|
||||
section: 'note',
|
||||
},
|
||||
|
||||
'emailToNote.inboxEmail': { value: '', type: SettingItemType.String, public: false },
|
||||
|
||||
'emailToNote.inboxJopId': { value: '', type: SettingItemType.String, public: false },
|
||||
};
|
||||
|
||||
this.metadata_ = { ...this.buildInMetadata_ };
|
||||
|
@ -13,7 +13,8 @@ export interface ItemSlice {
|
||||
// This function can be called to wrap any read-only-related code. It should be
|
||||
// fast and allows an early exit for cases that don't apply, for example if not
|
||||
// synchronising with Joplin Cloud or if not sharing any notebook.
|
||||
export const needsReadOnlyChecks = (itemType: ModelType, changeSource: number, shareState: ShareState) => {
|
||||
export const needsReadOnlyChecks = (itemType: ModelType, changeSource: number, shareState: ShareState, disableReadOnlyCheck = false) => {
|
||||
if (disableReadOnlyCheck) return false;
|
||||
if (Setting.value('sync.target') !== 10) return false;
|
||||
if (changeSource === ItemChange.SOURCE_SYNC) return false;
|
||||
if (!Setting.value('sync.userId')) return false;
|
||||
|
@ -33,4 +33,5 @@ export interface SaveOptions {
|
||||
ignoreProvisionalFlag?: boolean;
|
||||
dispatchUpdateAction?: boolean;
|
||||
changeSource?: number;
|
||||
disableReadOnlyCheck?: boolean;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Note from '../../models/Note';
|
||||
import { encryptionService, loadEncryptionMasterKey, msleep, resourceService, setupDatabaseAndSynchronizer, supportDir, switchClient } from '../../testing/test-utils';
|
||||
import { createFolderTree, encryptionService, loadEncryptionMasterKey, msleep, resourceService, setupDatabaseAndSynchronizer, simulateReadOnlyShareEnv, supportDir, switchClient } from '../../testing/test-utils';
|
||||
import ShareService from './ShareService';
|
||||
import reducer, { defaultState } from '../../reducer';
|
||||
import { createStore } from 'redux';
|
||||
@ -15,6 +15,9 @@ import shim from '../../shim';
|
||||
import Resource from '../../models/Resource';
|
||||
import { readFile } from 'fs-extra';
|
||||
import BaseItem from '../../models/BaseItem';
|
||||
import ResourceService from '../ResourceService';
|
||||
import Setting from '../../models/Setting';
|
||||
import { ModelType } from '../../BaseModel';
|
||||
|
||||
interface TestShareFolderServiceOptions {
|
||||
master_key_id?: string;
|
||||
@ -239,5 +242,40 @@ describe('ShareService', () => {
|
||||
Logger.globalLogger.setLevel(previousLogLevel);
|
||||
});
|
||||
|
||||
it('should leave a shared folder', async () => {
|
||||
const folder1 = await createFolderTree('', [
|
||||
{
|
||||
title: 'folder 1',
|
||||
children: [
|
||||
{
|
||||
title: 'note 1',
|
||||
},
|
||||
{
|
||||
title: 'note 2',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const resourceService = new ResourceService();
|
||||
await Folder.save({ id: folder1.id, share_id: '123456789' });
|
||||
await Folder.updateAllShareIds(resourceService);
|
||||
|
||||
const cleanup = simulateReadOnlyShareEnv('123456789');
|
||||
|
||||
const shareService = testShareFolderService();
|
||||
await shareService.leaveSharedFolder(folder1.id, 'somethingrandom');
|
||||
|
||||
expect(await Folder.count()).toBe(0);
|
||||
expect(await Note.count()).toBe(0);
|
||||
|
||||
const deletedItems = await BaseItem.deletedItems(Setting.value('sync.target'));
|
||||
|
||||
expect(deletedItems.length).toBe(1);
|
||||
expect(deletedItems[0].item_type).toBe(ModelType.Folder);
|
||||
expect(deletedItems[0].item_id).toBe(folder1.id);
|
||||
|
||||
cleanup();
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -173,14 +173,21 @@ export default class ShareService {
|
||||
|
||||
// This is when a share recipient decides to leave the shared folder.
|
||||
//
|
||||
// In that case, we should only delete the folder but none of its children.
|
||||
// Deleting the folder tells the server that we want to leave the share. The
|
||||
// server will then proceed to delete all associated user_items. So
|
||||
// eventually all the notebook content will also be deleted for the current
|
||||
// user.
|
||||
// In that case we delete the root folder. Deleting the folder tells the
|
||||
// server that we want to leave the share.
|
||||
//
|
||||
// We don't delete the children here because that would delete them for the
|
||||
// other share participants too.
|
||||
// We also immediately delete the children, but we do not sync the changes
|
||||
// otherwise it would delete the items for other users too.
|
||||
//
|
||||
// If we do not delete them now it would also cause all kind of issues with
|
||||
// read-only shares, because the read-only status will be lost after the
|
||||
// deletion of the root folder, which means various services may modify the
|
||||
// data. The changes will then be rejected by the sync target and cause
|
||||
// conflicts.
|
||||
//
|
||||
// We do not need to sync the children deletion, because the server will
|
||||
// take care of deleting all associated user_items. So eventually all the
|
||||
// notebook content will also be deleted for the current user.
|
||||
//
|
||||
// If `folderShareUserId` is provided, the function will check that the user
|
||||
// does not own the share. It would be an error to leave such a folder
|
||||
@ -191,7 +198,14 @@ export default class ShareService {
|
||||
if (folderShareUserId === userId) throw new Error('Cannot leave own notebook');
|
||||
}
|
||||
|
||||
await Folder.delete(folderId, { deleteChildren: false });
|
||||
const folder = await Folder.load(folderId);
|
||||
|
||||
// We call this to make sure all items are correctly linked before we
|
||||
// call deleteAllByShareId()
|
||||
await Folder.updateAllShareIds(ResourceService.instance());
|
||||
|
||||
await Folder.delete(folderId, { deleteChildren: false, disableReadOnlyCheck: true });
|
||||
await Folder.deleteAllByShareId(folder.share_id, { disableReadOnlyCheck: true, trackDeleted: false });
|
||||
}
|
||||
|
||||
// Finds any folder that is associated with a share, but the user no longer
|
||||
|
@ -94,6 +94,11 @@ export function isSharedFolderOwner(state: RootState, folderId: string): boolean
|
||||
}
|
||||
|
||||
export function isRootSharedFolder(folder: FolderEntity): boolean {
|
||||
if (!('share_id' in folder) || !('parent_id' in folder)) {
|
||||
logger.warn('Calling isRootSharedFolder without specifying share_id and parent_id:', folder);
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!folder.share_id && !folder.parent_id;
|
||||
}
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
import SyncTargetRegistry from '../SyncTargetRegistry';
|
||||
import eventManager from '../eventManager';
|
||||
import Setting from '../models/Setting';
|
||||
import { reg } from '../registry';
|
||||
|
||||
export const inboxFetcher = async () => {
|
||||
|
||||
if (Setting.value('sync.target') !== SyncTargetRegistry.nameToId('joplinCloud')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const syncTarget = reg.syncTarget();
|
||||
const fileApi = await syncTarget.fileApi();
|
||||
const api = fileApi.driver().api();
|
||||
|
||||
const owner = await api.exec('GET', `api/users/${api.userId}`);
|
||||
|
||||
if (owner.inbox) {
|
||||
Setting.setValue('emailToNote.inboxJopId', owner.inbox.jop_id);
|
||||
}
|
||||
|
||||
if (owner.inbox_email) {
|
||||
Setting.setValue('emailToNote.inboxEmail', owner.inbox_email);
|
||||
}
|
||||
};
|
||||
|
||||
// Listen to the event only once
|
||||
export const initializeInboxFetcher = () => {
|
||||
eventManager.once('sessionEstablished', inboxFetcher);
|
||||
};
|
41
packages/lib/utils/userFetcher.ts
Normal file
41
packages/lib/utils/userFetcher.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import SyncTargetRegistry from '../SyncTargetRegistry';
|
||||
import eventManager from '../eventManager';
|
||||
import Setting from '../models/Setting';
|
||||
import { reg } from '../registry';
|
||||
import Logger from '../Logger';
|
||||
|
||||
const logger = Logger.create('userFetcher');
|
||||
|
||||
interface UserApiResponse {
|
||||
inbox?: {
|
||||
jop_id: string;
|
||||
};
|
||||
inbox_email?: string;
|
||||
can_use_share_permissions?: number;
|
||||
}
|
||||
|
||||
const userFetcher = async () => {
|
||||
|
||||
if (Setting.value('sync.target') !== SyncTargetRegistry.nameToId('joplinCloud')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const syncTarget = reg.syncTarget();
|
||||
const fileApi = await syncTarget.fileApi();
|
||||
const api = fileApi.driver().api();
|
||||
|
||||
const owner: UserApiResponse = await api.exec('GET', `api/users/${api.userId}`);
|
||||
|
||||
logger.info('Got user:', owner);
|
||||
|
||||
Setting.setValue('sync.10.inboxId', owner.inbox ? owner.inbox.jop_id : '');
|
||||
Setting.setValue('sync.10.inboxEmail', owner.inbox_email ? owner.inbox_email : '');
|
||||
Setting.setValue('sync.10.canUseSharePermissions', !!owner.can_use_share_permissions);
|
||||
};
|
||||
|
||||
// Listen to the event only once
|
||||
export const initializeUserFetcher = () => {
|
||||
eventManager.once('sessionEstablished', userFetcher);
|
||||
};
|
||||
|
||||
export default userFetcher;
|
@ -1,6 +1,6 @@
|
||||
const utils = require('../utils');
|
||||
const glob = require('glob');
|
||||
const rootDir = utils.rootDir();
|
||||
const { globSync } = require('@joplin/utils/fs');
|
||||
|
||||
module.exports = {
|
||||
src: '',
|
||||
@ -11,7 +11,7 @@ module.exports = {
|
||||
//
|
||||
// https://github.com/isaacs/node-glob/issues/371
|
||||
|
||||
const tsFiles = glob.sync('{**/*.ts,**/*.tsx}', {
|
||||
const tsFiles = globSync('{**/*.ts,**/*.tsx}', {
|
||||
cwd: rootDir,
|
||||
ignore: [
|
||||
'**/.git/**',
|
||||
@ -32,7 +32,6 @@ module.exports = {
|
||||
'packages/app-desktop/dist/**',
|
||||
'packages/app-mobile/android/**',
|
||||
'packages/app-mobile/ios/**',
|
||||
// 'packages/fork-htmlparser2/**',
|
||||
'packages/fork-sax/**',
|
||||
'packages/lib/plugin_types/**',
|
||||
'packages/server/**',
|
||||
@ -52,29 +51,12 @@ module.exports = {
|
||||
return `${s.join('.')}.js`;
|
||||
});
|
||||
|
||||
// const ignoredMapFiles = tsFiles.map(f => {
|
||||
// const s = f.split('.');
|
||||
// s.pop();
|
||||
// return `${s.join('.')}.js.map`;
|
||||
// });
|
||||
|
||||
// const ignoredDefFiles = tsFiles.map(f => {
|
||||
// const s = f.split('.');
|
||||
// s.pop();
|
||||
// return `${s.join('.')}.d.ts`;
|
||||
// });
|
||||
|
||||
// const ignoredFiles = ignoredJsFiles.concat(ignoredMapFiles).concat(ignoredDefFiles);
|
||||
const ignoredFiles = ignoredJsFiles;
|
||||
ignoredFiles.sort();
|
||||
|
||||
const regex = /(# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD)[\s\S]*(# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD)/;
|
||||
const replacement = `$1\n${ignoredFiles.join('\n')}\n$2`;
|
||||
const replacement = `$1\n${ignoredJsFiles.join('\n')}\n$2`;
|
||||
|
||||
await Promise.all([
|
||||
utils.replaceFileText(`${rootDir}/.gitignore`, regex, replacement),
|
||||
utils.replaceFileText(`${rootDir}/.eslintignore`, regex, replacement),
|
||||
// utils.replaceFileText(`${rootDir}/.ignore`, regex, replacement),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
@ -27,7 +27,7 @@
|
||||
"dayjs": "1.11.9",
|
||||
"execa": "4.1.0",
|
||||
"fs-extra": "11.1.1",
|
||||
"gettext-parser": "6.0.0",
|
||||
"gettext-parser": "7.0.1",
|
||||
"glob": "10.2.7",
|
||||
"markdown-it": "13.0.1",
|
||||
"md5-file": "5.0.0",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { repeat, isCodeBlockSpecialCase1, isCodeBlockSpecialCase2, isCodeBlock, getStyleProp } from './utilities'
|
||||
import { repeat, isCodeBlockSpecialCase1, isCodeBlockSpecialCase2, isCodeBlock, getStyleProp, htmlEscapeLeadingNonbreakingSpace } from './utilities'
|
||||
const Entities = require('html-entities').AllHtmlEntities;
|
||||
const htmlentities = (new Entities()).encode;
|
||||
|
||||
@ -25,6 +25,13 @@ rules.paragraph = {
|
||||
filter: 'p',
|
||||
|
||||
replacement: function (content) {
|
||||
// If the line starts with a nonbreaking space, replace it. By default, the
|
||||
// markdown renderer removes leading non-HTML-escaped nonbreaking spaces. However,
|
||||
// because the space is nonbreaking, we want to keep it.
|
||||
// \u00A0 is a nonbreaking space.
|
||||
const leadingNonbreakingSpace = /^\u{00A0}/ug;
|
||||
content = content.replace(leadingNonbreakingSpace, ' ');
|
||||
|
||||
return '\n\n' + content + '\n\n'
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ export default function TurndownService (options) {
|
||||
linkReferenceStyle: 'full',
|
||||
anchorNames: [],
|
||||
br: ' ',
|
||||
nonbreakingSpace: ' ',
|
||||
disableEscapeContent: false,
|
||||
preformattedCode: false,
|
||||
blankReplacement: function (content, node) {
|
||||
@ -216,15 +215,10 @@ function replacementForNode (node) {
|
||||
var whitespace = node.flankingWhitespace
|
||||
if (whitespace.leading || whitespace.trailing) content = content.trim()
|
||||
|
||||
const replaceNonbreakingSpaces = space => {
|
||||
// \u{00A0} is a nonbreaking space
|
||||
return space.replace(/\u{00A0}/ug, this.options.nonbreakingSpace);
|
||||
};
|
||||
|
||||
return (
|
||||
replaceNonbreakingSpaces(whitespace.leading) +
|
||||
replaceNonbreakingSpaces(rule.replacement(content, node, this.options)) +
|
||||
replaceNonbreakingSpaces(whitespace.trailing)
|
||||
whitespace.leading +
|
||||
rule.replacement(content, node, this.options) +
|
||||
whitespace.trailing
|
||||
)
|
||||
}
|
||||
|
||||
|
12
packages/utils/fs.ts
Normal file
12
packages/utils/fs.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
import { GlobOptionsWithFileTypesFalse, sync } from 'glob';
|
||||
|
||||
// Wraps glob.sync but with good default options so that it works across
|
||||
// platforms and with consistent sorting.
|
||||
export const globSync = (pattern: string | string[], options: GlobOptionsWithFileTypesFalse) => {
|
||||
let output = sync(pattern, options);
|
||||
output = output.map(f => f.replace(/\\/g, '/'));
|
||||
output.sort();
|
||||
return output;
|
||||
};
|
@ -5,7 +5,8 @@
|
||||
"repository": "https://github.com/laurent22/joplin/tree/dev/packages/utils",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./net": "./dist/net.js"
|
||||
"./net": "./dist/net.js",
|
||||
"./fs": "./dist/fs.js"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@ -21,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"execa": "5.1.1",
|
||||
"fs-extra": "11.1.1",
|
||||
"glob": "10.2.7",
|
||||
"node-fetch": "2.6.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
294
yarn.lock
294
yarn.lock
@ -3966,13 +3966,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@gar/promisify@npm:^1.1.3":
|
||||
version: 1.1.3
|
||||
resolution: "@gar/promisify@npm:1.1.3"
|
||||
checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@github/browserslist-config@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "@github/browserslist-config@npm:1.0.0"
|
||||
@ -4487,7 +4480,7 @@ __metadata:
|
||||
react: 18.2.0
|
||||
react-datetime: 3.2.0
|
||||
react-dom: 18.2.0
|
||||
react-redux: 8.0.7
|
||||
react-redux: 8.1.1
|
||||
react-select: 5.7.3
|
||||
react-test-renderer: 18.2.0
|
||||
react-toggle-button: 2.2.0
|
||||
@ -4590,11 +4583,11 @@ __metadata:
|
||||
react-native-file-viewer: 2.1.5
|
||||
react-native-fingerprint-scanner: 6.0.0
|
||||
react-native-fs: 2.20.0
|
||||
react-native-gesture-handler: 2.11.0
|
||||
react-native-gesture-handler: 2.12.0
|
||||
react-native-get-random-values: 1.9.0
|
||||
react-native-image-picker: 5.4.2
|
||||
react-native-image-resizer: 1.4.5
|
||||
react-native-localize: 3.0.1
|
||||
react-native-localize: 3.0.2
|
||||
react-native-modal-datetime-picker: 15.0.1
|
||||
react-native-paper: 5.8.0
|
||||
react-native-popup-menu: 0.16.1
|
||||
@ -4611,7 +4604,7 @@ __metadata:
|
||||
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: 8.1.1
|
||||
react-test-renderer: 18.2.0
|
||||
redux: 4.2.1
|
||||
rn-fetch-blob: 0.12.0
|
||||
@ -4970,7 +4963,7 @@ __metadata:
|
||||
execa: 4.1.0
|
||||
fs-extra: 11.1.1
|
||||
gettext-extractor: 3.7.2
|
||||
gettext-parser: 6.0.0
|
||||
gettext-parser: 7.0.1
|
||||
glob: 10.2.7
|
||||
gulp: 4.0.2
|
||||
html-entities: 1.4.0
|
||||
@ -5042,6 +5035,7 @@ __metadata:
|
||||
"@types/node-fetch": 2.6.3
|
||||
execa: 5.1.1
|
||||
fs-extra: 11.1.1
|
||||
glob: 10.2.7
|
||||
jest: 29.5.0
|
||||
node-fetch: 2.6.7
|
||||
ts-jest: 29.1.0
|
||||
@ -6172,16 +6166,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@npmcli/fs@npm:^2.1.0":
|
||||
version: 2.1.2
|
||||
resolution: "@npmcli/fs@npm:2.1.2"
|
||||
dependencies:
|
||||
"@gar/promisify": ^1.1.3
|
||||
semver: ^7.3.5
|
||||
checksum: 405074965e72d4c9d728931b64d2d38e6ea12066d4fad651ac253d175e413c06fe4350970c783db0d749181da8fe49c42d3880bd1cbc12cd68e3a7964d820225
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@npmcli/fs@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "@npmcli/fs@npm:3.1.0"
|
||||
@ -6229,16 +6213,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@npmcli/move-file@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "@npmcli/move-file@npm:2.0.1"
|
||||
dependencies:
|
||||
mkdirp: ^1.0.4
|
||||
rimraf: ^3.0.2
|
||||
checksum: 52dc02259d98da517fae4cb3a0a3850227bdae4939dda1980b788a7670636ca2b4a01b58df03dd5f65c1e3cb70c50fa8ce5762b582b3f499ec30ee5ce1fd9380
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@npmcli/node-gyp@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "@npmcli/node-gyp@npm:3.0.0"
|
||||
@ -11098,32 +11072,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cacache@npm:^16.1.0":
|
||||
version: 16.1.3
|
||||
resolution: "cacache@npm:16.1.3"
|
||||
dependencies:
|
||||
"@npmcli/fs": ^2.1.0
|
||||
"@npmcli/move-file": ^2.0.0
|
||||
chownr: ^2.0.0
|
||||
fs-minipass: ^2.1.0
|
||||
glob: ^8.0.1
|
||||
infer-owner: ^1.0.4
|
||||
lru-cache: ^7.7.1
|
||||
minipass: ^3.1.6
|
||||
minipass-collect: ^1.0.2
|
||||
minipass-flush: ^1.0.5
|
||||
minipass-pipeline: ^1.2.4
|
||||
mkdirp: ^1.0.4
|
||||
p-map: ^4.0.0
|
||||
promise-inflight: ^1.0.1
|
||||
rimraf: ^3.0.2
|
||||
ssri: ^9.0.0
|
||||
tar: ^6.1.11
|
||||
unique-filename: ^2.0.0
|
||||
checksum: d91409e6e57d7d9a3a25e5dcc589c84e75b178ae8ea7de05cbf6b783f77a5fae938f6e8fda6f5257ed70000be27a681e1e44829251bfffe4c10216002f8f14e6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cacache@npm:^17.0.0":
|
||||
version: 17.1.3
|
||||
resolution: "cacache@npm:17.1.3"
|
||||
@ -12440,6 +12388,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"content-type@npm:^1.0.5":
|
||||
version: 1.0.5
|
||||
resolution: "content-type@npm:1.0.5"
|
||||
checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"conventional-changelog-angular@npm:^5.0.3":
|
||||
version: 5.0.13
|
||||
resolution: "conventional-changelog-angular@npm:5.0.13"
|
||||
@ -17274,7 +17229,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0":
|
||||
"fs-minipass@npm:^2.0.0":
|
||||
version: 2.1.0
|
||||
resolution: "fs-minipass@npm:2.1.0"
|
||||
dependencies:
|
||||
@ -17707,15 +17662,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"gettext-parser@npm:6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "gettext-parser@npm:6.0.0"
|
||||
"gettext-parser@npm:7.0.1":
|
||||
version: 7.0.1
|
||||
resolution: "gettext-parser@npm:7.0.1"
|
||||
dependencies:
|
||||
content-type: ^1.0.4
|
||||
content-type: ^1.0.5
|
||||
encoding: ^0.1.13
|
||||
readable-stream: ^4.1.0
|
||||
readable-stream: ^4.3.0
|
||||
safe-buffer: ^5.2.1
|
||||
checksum: e6938755d914e886c780a71e58390af0a5ea5698aab2777654733da4c4b96e02fcc9d40c50df0987e4d4a12bd6b99291a268805edb8c99a83a639606ab73e40e
|
||||
checksum: 251174700e4c7a4b9d868acf3b0e233211724a40f779bd9869357f782b004abd1f0a587f6c9f4219fd24f468bbfc18ca654cdd6e375f19610bd99f1587046ffa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -17961,20 +17916,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:^8.0.1":
|
||||
version: 8.0.1
|
||||
resolution: "glob@npm:8.0.1"
|
||||
dependencies:
|
||||
fs.realpath: ^1.0.0
|
||||
inflight: ^1.0.4
|
||||
inherits: 2
|
||||
minimatch: ^5.0.1
|
||||
once: ^1.3.0
|
||||
path-is-absolute: ^1.0.0
|
||||
checksum: 7ac782f3ef1c08005884447479e68ceb0ad56997eb2003e1e9aefae71bad3cb48eb7c49190d3d6736f2ffcd8af4985d53a46831b3d5e0052cc5756822a38b61a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:^8.0.3":
|
||||
version: 8.0.3
|
||||
resolution: "glob@npm:8.0.3"
|
||||
@ -22605,30 +22546,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"make-fetch-happen@npm:^10.0.3":
|
||||
version: 10.2.1
|
||||
resolution: "make-fetch-happen@npm:10.2.1"
|
||||
dependencies:
|
||||
agentkeepalive: ^4.2.1
|
||||
cacache: ^16.1.0
|
||||
http-cache-semantics: ^4.1.0
|
||||
http-proxy-agent: ^5.0.0
|
||||
https-proxy-agent: ^5.0.0
|
||||
is-lambda: ^1.0.1
|
||||
lru-cache: ^7.7.1
|
||||
minipass: ^3.1.6
|
||||
minipass-collect: ^1.0.2
|
||||
minipass-fetch: ^2.0.3
|
||||
minipass-flush: ^1.0.5
|
||||
minipass-pipeline: ^1.2.4
|
||||
negotiator: ^0.6.3
|
||||
promise-retry: ^2.0.1
|
||||
socks-proxy-agent: ^7.0.0
|
||||
ssri: ^9.0.0
|
||||
checksum: 2332eb9a8ec96f1ffeeea56ccefabcb4193693597b132cd110734d50f2928842e22b84cfa1508e921b8385cdfd06dda9ad68645fed62b50fff629a580f5fb72c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"make-fetch-happen@npm:^11.0.0, make-fetch-happen@npm:^11.0.1, make-fetch-happen@npm:^11.0.3, make-fetch-happen@npm:^11.1.1":
|
||||
version: 11.1.1
|
||||
resolution: "make-fetch-happen@npm:11.1.1"
|
||||
@ -24030,21 +23947,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minipass-fetch@npm:^2.0.3":
|
||||
version: 2.1.2
|
||||
resolution: "minipass-fetch@npm:2.1.2"
|
||||
dependencies:
|
||||
encoding: ^0.1.13
|
||||
minipass: ^3.1.6
|
||||
minipass-sized: ^1.0.3
|
||||
minizlib: ^2.1.2
|
||||
dependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
checksum: 3f216be79164e915fc91210cea1850e488793c740534985da017a4cbc7a5ff50506956d0f73bb0cb60e4fe91be08b6b61ef35101706d3ef5da2c8709b5f08f91
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minipass-fetch@npm:^3.0.0":
|
||||
version: 3.0.3
|
||||
resolution: "minipass-fetch@npm:3.0.3"
|
||||
@ -24790,27 +24692,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp@npm:9.3.1":
|
||||
version: 9.3.1
|
||||
resolution: "node-gyp@npm:9.3.1"
|
||||
dependencies:
|
||||
env-paths: ^2.2.0
|
||||
glob: ^7.1.4
|
||||
graceful-fs: ^4.2.6
|
||||
make-fetch-happen: ^10.0.3
|
||||
nopt: ^6.0.0
|
||||
npmlog: ^6.0.0
|
||||
rimraf: ^3.0.2
|
||||
semver: ^7.3.5
|
||||
tar: ^6.1.2
|
||||
which: ^2.0.2
|
||||
bin:
|
||||
node-gyp: bin/node-gyp.js
|
||||
checksum: b860e9976fa645ca0789c69e25387401b4396b93c8375489b5151a6c55cf2640a3b6183c212b38625ef7c508994930b72198338e3d09b9d7ade5acc4aaf51ea7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp@npm:^9.0.0, node-gyp@npm:latest":
|
||||
"node-gyp@npm:9.4.0, node-gyp@npm:^9.0.0, node-gyp@npm:latest":
|
||||
version: 9.4.0
|
||||
resolution: "node-gyp@npm:9.4.0"
|
||||
dependencies:
|
||||
@ -27952,9 +27834,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-gesture-handler@npm:2.11.0":
|
||||
version: 2.11.0
|
||||
resolution: "react-native-gesture-handler@npm:2.11.0"
|
||||
"react-native-gesture-handler@npm:2.12.0":
|
||||
version: 2.12.0
|
||||
resolution: "react-native-gesture-handler@npm:2.12.0"
|
||||
dependencies:
|
||||
"@egjs/hammerjs": ^2.0.17
|
||||
hoist-non-react-statics: ^3.3.0
|
||||
@ -27964,7 +27846,7 @@ __metadata:
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
checksum: 2f1e5ab3e96473c034f90e7aecce7d66fca992b791317b16a951928a42487598d3d3237e6e711bcf3cdb065f5b37415d3a8f8872f9df17993c614b852e350cd5
|
||||
checksum: 5147357b3212e269d0b8003e1be9e0993d0770f4880f1a8f52d2d61512c4569c48ec7b866d0a9ee44038785c29e0f84fbb99fd18a8e09552a25910c71602d788
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -28012,9 +27894,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-localize@npm:3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "react-native-localize@npm:3.0.1"
|
||||
"react-native-localize@npm:3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "react-native-localize@npm:3.0.2"
|
||||
peerDependencies:
|
||||
react: ">=18.1.0"
|
||||
react-native: ">=0.70.0"
|
||||
@ -28022,7 +27904,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
react-native-macos:
|
||||
optional: true
|
||||
checksum: f8703405ea5cf3fcc04fbfb255853832d730e6bedfc4a758254888bd4fb0b5edfa17350dff0b51e5cf804c00819bba1be86c05c496cc2a1d1a1a005a19bb0b9d
|
||||
checksum: 46abd6046dfb1fb5426f9e51971894e893556646206b7fa387c5eb9394a3f3b9ddce190bc94ffc9c51c65326f60bbad57219d8330b4a1dcfaf46dd2eb4ef43ae
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -28089,6 +27971,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-reanimated@patch:react-native-reanimated@npm%3A3.3.0#./.yarn/patches/react-native-animation-fix/react-native-reanimated-npm-3.3.0-fb4272741c.patch::locator=root%40workspace%3A.":
|
||||
version: 3.3.0
|
||||
resolution: "react-native-reanimated@patch:react-native-reanimated@npm%3A3.3.0#./.yarn/patches/react-native-animation-fix/react-native-reanimated-npm-3.3.0-fb4272741c.patch::version=3.3.0&hash=13daee&locator=root%40workspace%3A."
|
||||
dependencies:
|
||||
"@babel/plugin-transform-object-assign": ^7.16.7
|
||||
"@babel/preset-typescript": ^7.16.7
|
||||
convert-source-map: ^2.0.0
|
||||
invariant: ^2.2.4
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.0.0-0
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": ^7.0.0-0
|
||||
"@babel/plugin-proposal-optional-chaining": ^7.0.0-0
|
||||
"@babel/plugin-transform-arrow-functions": ^7.0.0-0
|
||||
"@babel/plugin-transform-shorthand-properties": ^7.0.0-0
|
||||
"@babel/plugin-transform-template-literals": ^7.0.0-0
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
checksum: 5d73a35e694ab6c37b5f12530e1acdac822f2cceef7d04dcc060cc4c9221f51cf6bb68ed16737b25e79086de9dca6cd322819c6d04d668c9b97526408e97db68
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-rsa-native@npm:2.0.5":
|
||||
version: 2.0.5
|
||||
resolution: "react-native-rsa-native@npm:2.0.5"
|
||||
@ -28299,6 +28202,52 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native@patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch::locator=root%40workspace%3A.":
|
||||
version: 0.71.10
|
||||
resolution: "react-native@patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch::version=0.71.10&hash=d4015e&locator=root%40workspace%3A."
|
||||
dependencies:
|
||||
"@jest/create-cache-key-function": ^29.2.1
|
||||
"@react-native-community/cli": 10.2.2
|
||||
"@react-native-community/cli-platform-android": 10.2.0
|
||||
"@react-native-community/cli-platform-ios": 10.2.1
|
||||
"@react-native/assets": 1.0.0
|
||||
"@react-native/normalize-color": 2.1.0
|
||||
"@react-native/polyfills": 2.0.0
|
||||
abort-controller: ^3.0.0
|
||||
anser: ^1.4.9
|
||||
base64-js: ^1.1.2
|
||||
deprecated-react-native-prop-types: ^3.0.1
|
||||
event-target-shim: ^5.0.1
|
||||
invariant: ^2.2.4
|
||||
jest-environment-node: ^29.2.1
|
||||
jsc-android: ^250231.0.0
|
||||
memoize-one: ^5.0.0
|
||||
metro-react-native-babel-transformer: 0.73.9
|
||||
metro-runtime: 0.73.9
|
||||
metro-source-map: 0.73.9
|
||||
mkdirp: ^0.5.1
|
||||
nullthrows: ^1.1.1
|
||||
pretty-format: ^26.5.2
|
||||
promise: ^8.3.0
|
||||
react-devtools-core: ^4.26.1
|
||||
react-native-codegen: ^0.71.5
|
||||
react-native-gradle-plugin: ^0.71.19
|
||||
react-refresh: ^0.4.0
|
||||
react-shallow-renderer: ^16.15.0
|
||||
regenerator-runtime: ^0.13.2
|
||||
scheduler: ^0.23.0
|
||||
stacktrace-parser: ^0.1.3
|
||||
use-sync-external-store: ^1.0.0
|
||||
whatwg-fetch: ^3.0.0
|
||||
ws: ^6.2.2
|
||||
peerDependencies:
|
||||
react: 18.2.0
|
||||
bin:
|
||||
react-native: cli.js
|
||||
checksum: c8c3cd4abfe4031f2c91baa6b26e2a43421dc3a3b221fec408d67c788e477b90dc4c0b206c1a24f82d5d7dae319b5da8ce6a472e346b48936813001d8276a279
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-reconciler@npm:^0.26.2":
|
||||
version: 0.26.2
|
||||
resolution: "react-reconciler@npm:0.26.2"
|
||||
@ -28312,9 +28261,9 @@ __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:8.1.1":
|
||||
version: 8.1.1
|
||||
resolution: "react-redux@npm:8.1.1"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.12.1
|
||||
"@types/hoist-non-react-statics": ^3.3.1
|
||||
@ -28323,7 +28272,6 @@ __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
|
||||
@ -28331,8 +28279,6 @@ __metadata:
|
||||
react-native: ">=0.59"
|
||||
redux: ^4 || ^5.0.0-beta.0
|
||||
peerDependenciesMeta:
|
||||
"@reduxjs/toolkit":
|
||||
optional: true
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
@ -28343,7 +28289,7 @@ __metadata:
|
||||
optional: true
|
||||
redux:
|
||||
optional: true
|
||||
checksum: d903aa79b12154258fd76b8e61fcf56f72123f69c31033b262805646371e23822cd0cd11d24194cda1e03569a7b1bf86e935cd57a9bab4523186804ed2742fac
|
||||
checksum: 370676330727764d78f35e9c5a0ed0591d79482fe9b70fffcab4aa6bcccc6194e4f1ebd818b4b390351dea5557e70d3bd4d95d7a0ac9baa1f45d6bf2230ee713
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -28645,15 +28591,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"readable-stream@npm:^4.1.0":
|
||||
version: 4.2.0
|
||||
resolution: "readable-stream@npm:4.2.0"
|
||||
"readable-stream@npm:^4.3.0":
|
||||
version: 4.4.2
|
||||
resolution: "readable-stream@npm:4.4.2"
|
||||
dependencies:
|
||||
abort-controller: ^3.0.0
|
||||
buffer: ^6.0.3
|
||||
events: ^3.3.0
|
||||
process: ^0.11.10
|
||||
checksum: aa8447f781e6df90af78f6b0b9b9a77da2816dcf6c8220e7021c4de36e04f8129fed7ead81eac0baad2f42098209f9e7d7cd43169e1c156efcd2613828a37439
|
||||
string_decoder: ^1.3.0
|
||||
checksum: 6f4063763dbdb52658d22d3f49ca976420e1fbe16bbd241f744383715845350b196a2f08b8d6330f8e219153dff34b140aeefd6296da828e1041a7eab1f20d5e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -29545,7 +29492,7 @@ __metadata:
|
||||
lerna: 3.22.1
|
||||
lint-staged: 13.2.3
|
||||
madge: 6.1.0
|
||||
node-gyp: 9.3.1
|
||||
node-gyp: 9.4.0
|
||||
nodemon: 2.0.22
|
||||
npm-package-json-lint: 6.4.0
|
||||
typescript: 5.0.2
|
||||
@ -30837,15 +30784,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ssri@npm:^9.0.0":
|
||||
version: 9.0.1
|
||||
resolution: "ssri@npm:9.0.1"
|
||||
dependencies:
|
||||
minipass: ^3.1.1
|
||||
checksum: fb58f5e46b6923ae67b87ad5ef1c5ab6d427a17db0bead84570c2df3cd50b4ceb880ebdba2d60726588272890bae842a744e1ecce5bd2a2a582fccd5068309eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"stack-trace@npm:0.0.10":
|
||||
version: 0.0.10
|
||||
resolution: "stack-trace@npm:0.0.10"
|
||||
@ -31238,7 +31176,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"string_decoder@npm:^1.1.1":
|
||||
"string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "string_decoder@npm:1.3.0"
|
||||
dependencies:
|
||||
@ -33264,15 +33202,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unique-filename@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "unique-filename@npm:2.0.1"
|
||||
dependencies:
|
||||
unique-slug: ^3.0.0
|
||||
checksum: 807acf3381aff319086b64dc7125a9a37c09c44af7620bd4f7f3247fcd5565660ac12d8b80534dcbfd067e6fe88a67e621386dd796a8af828d1337a8420a255f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unique-filename@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "unique-filename@npm:3.0.0"
|
||||
@ -33291,15 +33220,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unique-slug@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "unique-slug@npm:3.0.0"
|
||||
dependencies:
|
||||
imurmurhash: ^0.1.4
|
||||
checksum: 49f8d915ba7f0101801b922062ee46b7953256c93ceca74303bd8e6413ae10aa7e8216556b54dc5382895e8221d04f1efaf75f945c2e4a515b4139f77aa6640c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unique-slug@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "unique-slug@npm:4.0.0"
|
||||
|
Loading…
Reference in New Issue
Block a user