1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-12-08 23:07:32 +02:00

Compare commits

...

18 Commits

Author SHA1 Message Date
Laurent Cozic
d1aec4a9f7 Plugin Generator release v3.5.1 2025-10-15 20:02:14 +01:00
Henry Heino
cab1525589 Chore: Plugin repository script: Fix certain plugins are not being published (#13443) 2025-10-15 20:00:29 +01:00
Henry Heino
a52f3fea9e Mobile: Resolves: #12823: Disable auto-search for 1-2 character searches (#13444)
Co-authored-by: pedr <pedr@users.noreply.github.com>
2025-10-15 20:00:02 +01:00
renovate[bot]
dfbd5eb8ed Update dependency expo to v53.0.20 (#13441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 14:18:13 +01:00
Laurent Cozic
3131f36033 Chore: Trying to fix random CI failure 2025-10-15 12:55:40 +01:00
renovate[bot]
dc5b2cfa21 Update dependency form-data to v4.0.4 (#13439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 09:42:15 +00:00
renovate[bot]
cad0f35fcc Update dependency expo-camera to v16.1.11 (#13438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 02:43:03 +00:00
renovate[bot]
38ea92ff57 Update dependency axios to v1.10.0 (#13431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 14:35:53 +01:00
renovate[bot]
830deada22 Update dependency @types/serviceworker to v0.0.142 (#13434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 18:47:47 +01:00
renovate[bot]
38cd4033ea Update dependency @types/node to v18.19.119 (#13435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 13:36:57 +00:00
Shania
02900752d9 Doc: Missing hashtag in rich_text_editor.md (#13418) 2025-10-11 12:56:26 +01:00
renovate[bot]
091e9813b5 Update dependency @react-native/babel-preset to v0.80.1 (#13426)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-11 01:23:33 +01:00
renovate[bot]
e61e5ac32a Update dependency @react-native/babel-preset to v0.80.0 (#13423)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-10 21:28:24 +01:00
Joplin Bot
414970c9a1 Doc: Auto-update documentation
Auto-updated using release-website.sh
2025-10-10 18:39:00 +00:00
Laurent Cozic
d4ed49ff23 Doc: Clarify how to disable spellchecking on Markdown files 2025-10-10 17:48:37 +01:00
Laurent Cozic
8751d5d152 Doc: Add documentation for LDAP and SAML support in Joplin Server 2025-10-10 17:47:28 +01:00
Laurent Cozic
2e846fe15d Desktop release v3.5.4 2025-10-10 15:48:13 +01:00
Laurent Cozic
e54b7696d9 Chore: Prevent sign tool from being added to the Windows app 2025-10-10 15:48:01 +01:00
32 changed files with 570 additions and 84 deletions

View File

@@ -844,6 +844,7 @@ packages/app-mobile/components/screens/NoteTagsDialog.js
packages/app-mobile/components/screens/Notes/NewNoteButton.test.js
packages/app-mobile/components/screens/Notes/NewNoteButton.js
packages/app-mobile/components/screens/Notes/Notes.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
packages/app-mobile/components/screens/SearchScreen/index.js
packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.js
@@ -1742,6 +1743,7 @@ packages/plugin-repo-cli/lib/gitCompareUrl.test.js
packages/plugin-repo-cli/lib/gitCompareUrl.js
packages/plugin-repo-cli/lib/overrideUtils.test.js
packages/plugin-repo-cli/lib/overrideUtils.js
packages/plugin-repo-cli/lib/searchPlugins.js
packages/plugin-repo-cli/lib/types.js
packages/plugin-repo-cli/lib/updateReadme.test.js
packages/plugin-repo-cli/lib/updateReadme.js

2
.gitignore vendored
View File

@@ -817,6 +817,7 @@ packages/app-mobile/components/screens/NoteTagsDialog.js
packages/app-mobile/components/screens/Notes/NewNoteButton.test.js
packages/app-mobile/components/screens/Notes/NewNoteButton.js
packages/app-mobile/components/screens/Notes/Notes.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.test.js
packages/app-mobile/components/screens/SearchScreen/SearchResults.js
packages/app-mobile/components/screens/SearchScreen/index.js
packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.js
@@ -1715,6 +1716,7 @@ packages/plugin-repo-cli/lib/gitCompareUrl.test.js
packages/plugin-repo-cli/lib/gitCompareUrl.js
packages/plugin-repo-cli/lib/overrideUtils.test.js
packages/plugin-repo-cli/lib/overrideUtils.js
packages/plugin-repo-cli/lib/searchPlugins.js
packages/plugin-repo-cli/lib/types.js
packages/plugin-repo-cli/lib/updateReadme.test.js
packages/plugin-repo-cli/lib/updateReadme.js

View File

@@ -73,7 +73,7 @@
"@joplin/tools": "~3.5",
"@types/fs-extra": "11.0.4",
"@types/jest": "29.5.14",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@types/proper-lockfile": "^4.1.2",
"gulp": "4.0.2",
"jest": "29.7.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/app-desktop",
"version": "3.5.3",
"version": "3.5.4",
"description": "Joplin for Desktop",
"main": "main.bundle.js",
"private": true,
@@ -148,7 +148,7 @@
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.5.14",
"@types/mustache": "4.2.6",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@types/react": "18.3.23",
"@types/react-dom": "18.3.7",
"@types/react-redux": "7.1.33",

View File

@@ -4,13 +4,25 @@ const { execSync } = require('child_process');
const { chdir, cwd } = require('process');
const { mkdirpSync, moveSync, pathExists } = require('fs-extra');
const { readdirSync, writeFileSync } = require('fs');
const { dirname } = require('path');
const signToolName = 'CodeSignTool.bat';
const getTempDir = () => {
if (process.env.RUNNER_TEMP) return process.env.RUNNER_TEMP;
if (process.env.GITHUB_WORKSPACE) return process.env.GITHUB_WORKSPACE;
const output = `${dirname(dirname(__dirname))}/temp`;
mkdirpSync(output);
return output;
};
const tempDir = getTempDir();
const downloadSignTool = async () => {
const signToolUrl = 'https://www.ssl.com/download/codesigntool-for-windows/';
const downloadDir = `${__dirname}/signToolDownloadTemp`;
const extractDir = `${__dirname}/signToolExtractTemp`;
const downloadDir = `${tempDir}/signToolDownloadTemp`;
const extractDir = `${tempDir}/signToolExtractTemp`;
if (await pathExists(`${extractDir}/${signToolName}`)) {
console.info('sign.js: Sign tool has already been downloaded - skipping');
@@ -55,6 +67,8 @@ exports.default = async (configuration) => {
console.info('sign.js: File to sign:', inputFilePath);
console.info('sign.js: Using temp dir:', tempDir);
if (SIGN_APPLICATION !== '1') {
console.info('sign.js: SIGN_APPLICATION != 1 - not signing application');
return;
@@ -63,9 +77,8 @@ exports.default = async (configuration) => {
console.info('sign.js: SIGN_APPLICATION = 1 - signing application');
const signToolDir = await downloadSignTool();
const tempDir = `${__dirname}/temp`;
mkdirpSync(tempDir);
const signToolOutDir = `${tempDir}/signedToolOutDir`;
mkdirpSync(signToolOutDir);
const previousDir = cwd();
chdir(signToolDir);
@@ -74,7 +87,7 @@ exports.default = async (configuration) => {
const cmd = [
`${signToolName} sign`,
`-input_file_path="${inputFilePath}"`,
`-output_dir_path="${tempDir}"`,
`-output_dir_path="${signToolOutDir}"`,
`-credential_id="${SSL_ESIGNER_CREDENTIAL_ID}"`,
`-username="${SSL_ESIGNER_USER_NAME}"`,
`-password="${SSL_ESIGNER_USER_PASSWORD}"`,
@@ -83,10 +96,10 @@ exports.default = async (configuration) => {
execSync(cmd.join(' '));
const createdFiles = readdirSync(tempDir);
const createdFiles = readdirSync(signToolOutDir);
console.info('sign.js: Created files:', createdFiles);
moveSync(`${tempDir}/${createdFiles[0]}`, inputFilePath, { overwrite: true });
moveSync(`${signToolOutDir}/${createdFiles[0]}`, inputFilePath, { overwrite: true });
} catch (error) {
console.error('sign.js: Could not sign file:', error);
process.exit(1);

View File

@@ -0,0 +1,50 @@
import * as React from 'react';
import { AppState } from '../../../utils/types';
import { Store } from 'redux';
import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
import createMockReduxStore from '../../../utils/testing/createMockReduxStore';
import setupGlobalStore from '../../../utils/testing/setupGlobalStore';
import Note from '@joplin/lib/models/Note';
import { render, screen } from '../../../utils/testing/testingLibrary';
import SearchResults from './SearchResults';
import SearchEngine from '@joplin/lib/services/search/SearchEngine';
import Folder from '@joplin/lib/models/Folder';
import TestProviderStack from '../../testing/TestProviderStack';
const createNotes = async (count: number) => {
const folder = await Folder.save({ title: 'Test Note' });
for (let i = 0; i < count; i++) {
await Note.save({ title: `abcd ${i}`, body: 'body', parent_id: folder.id });
}
await SearchEngine.instance().syncTables();
};
let store: Store<AppState>;
interface WrapperProps {
query: string;
paused: boolean;
}
const WrappedSearchResults: React.FC<WrapperProps> = props => (
<TestProviderStack store={store}>
<SearchResults paused={props.paused} query={props.query} onHighlightedWordsChange={() => { }} ftsEnabled={1} />
</TestProviderStack>
);
describe('SearchResult', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
store = createMockReduxStore();
setupGlobalStore(store);
});
test('should show results when unpaused', async () => {
const noteCount = 8;
await createNotes(noteCount);
render(<WrappedSearchResults query='abcd' paused={false}/>);
const items = await screen.findAllByText(/abcd \d\d?\d?/);
expect(items.length).toBe(noteCount);
});
});

View File

@@ -13,6 +13,7 @@ import shim from '@joplin/lib/shim';
interface Props {
query: string;
paused: boolean;
onHighlightedWordsChange: (highlightedWords: (ComplexTerm | string)[])=> void;
ftsEnabled: number;
@@ -28,7 +29,7 @@ const useResults = (props: Props) => {
let notes: NoteEntity[] = [];
setIsProcessing(true);
try {
if (query) {
if (query && !props.paused) {
if (ftsEnabled) {
const r = await SearchEngineUtils.notesForQuery(query, true, { appendWildCards: true });
notes = r.notes;
@@ -57,7 +58,7 @@ const useResults = (props: Props) => {
} finally {
setIsProcessing(false);
}
}, [query, ftsEnabled], { interval: 200 });
}, [query, props.paused, ftsEnabled], { interval: 200 });
return {
notes,

View File

@@ -53,11 +53,36 @@ const useStyles = (theme: ThemeStyle, visible: boolean) => {
}, [theme, visible]);
};
// Workaround for https://github.com/laurent22/joplin/issues/12823:
// Disable search-as-you-type for short 0-2 character searches that
// are likely to match the start of a large number of words.
const useSearchPaused = (query: string) => {
const [pauseDisabled, setPauseDisabled] = useState(false);
// Only disable search-as-you-type for a subset of all characters.
// This is, for example, to ensure that search-as-you-type remains
// enabled for CJK characters (e.g. U+6570 has length 1).
const paused = query.match(/^[a-z0-9]{0,2}$/i);
const onOverridePause = useCallback(() => {
setPauseDisabled(true);
}, []);
useEffect(() => {
setPauseDisabled(false);
}, [query]);
return {
paused: paused && !pauseDisabled,
onOverridePause,
};
};
const SearchScreenComponent: React.FC<Props> = props => {
const theme = themeStyle(props.themeId);
const styles = useStyles(theme, props.visible);
const [query, setQuery] = useState(props.query);
const { paused, onOverridePause } = useSearchPaused(query);
const globalQueryRef = useRef(props.query);
globalQueryRef.current = props.query;
@@ -99,6 +124,7 @@ const SearchScreenComponent: React.FC<Props> = props => {
autoFocus={props.visible}
underlineColorAndroid="#ffffff00"
onChangeText={setQuery}
onSubmitEditing={onOverridePause}
value={query}
selectionColor={theme.textSelectionColor}
keyboardAppearance={theme.keyboardAppearance}
@@ -114,6 +140,7 @@ const SearchScreenComponent: React.FC<Props> = props => {
<SearchResults
query={query}
paused={paused}
ftsEnabled={props.ftsEnabled}
onHighlightedWordsChange={onHighlightedWordsChange}
/>

View File

@@ -41,9 +41,9 @@
"crypto-browserify": "3.12.1",
"deprecated-react-native-prop-types": "5.0.0",
"events": "3.3.0",
"expo": "53.0.19",
"expo": "53.0.20",
"expo-av": "15.1.7",
"expo-camera": "16.1.10",
"expo-camera": "16.1.11",
"expo-local-authentication": "16.0.5",
"lodash": "4.17.21",
"md5": "2.3.0",
@@ -99,17 +99,17 @@
"@react-native-community/cli": "16.0.3",
"@react-native-community/cli-platform-android": "16.0.3",
"@react-native-community/cli-platform-ios": "16.0.3",
"@react-native/babel-preset": "0.79.5",
"@react-native/babel-preset": "0.80.1",
"@react-native/metro-config": "0.79.5",
"@react-native/typescript-config": "0.79.5",
"@sqlite.org/sqlite-wasm": "3.46.0-build2",
"@testing-library/react-native": "13.2.0",
"@types/fs-extra": "11.0.4",
"@types/jest": "29.5.14",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@types/react": "19.0.14",
"@types/react-redux": "7.1.33",
"@types/serviceworker": "0.0.141",
"@types/serviceworker": "0.0.142",
"@types/tar-stream": "3.1.4",
"babel-jest": "29.7.0",
"babel-loader": "9.1.3",

View File

@@ -18,7 +18,7 @@
"@joplin/utils": "~3.5",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.5.14",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@types/react": "18.3.23",
"@types/react-redux": "7.1.33",
"@types/styled-components": "5.1.32",

View File

@@ -46,7 +46,7 @@
},
"devDependencies": {
"@types/jest": "29.5.14",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"coveralls": "3.1.1",

View File

@@ -17,7 +17,7 @@
},
"devDependencies": {
"@types/jest": "29.5.14",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"jest": "29.7.0",
"typescript": "5.8.3"
},

View File

@@ -1,3 +1,4 @@
import { ClipboardContent } from './types';
export default class JoplinClipboard {
private electronClipboard_;
private electronNativeImage_;
@@ -26,4 +27,19 @@ export default class JoplinClipboard {
* For example [ 'text/plain', 'text/html' ]
*/
availableFormats(): Promise<string[]>;
/**
* Writes multiple formats to the clipboard simultaneously.
* This allows setting both text/plain and text/html at the same time.
*
* <span class="platform-desktop">desktop</span>
*
* @example
* ```typescript
* await joplin.clipboard.write({
* text: 'Plain text version',
* html: '<strong>HTML version</strong>'
* });
* ```
*/
write(content: ClipboardContent): Promise<void>;
}

View File

@@ -588,6 +588,30 @@ export interface SettingSection {
*/
export type Path = string[];
// =================================================================
// Clipboard API types
// =================================================================
/**
* Represents content that can be written to the clipboard in multiple formats.
*/
export interface ClipboardContent {
/**
* Plain text representation of the content
*/
text?: string;
/**
* HTML representation of the content
*/
html?: string;
/**
* Image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format
*/
image?: string;
}
// =================================================================
// Content Script types
// =================================================================

View File

@@ -1,6 +1,6 @@
{
"name": "generator-joplin",
"version": "3.5.0",
"version": "3.5.1",
"description": "Scaffolds out a new Joplin plugin",
"homepage": "https://github.com/laurent22/joplin/tree/dev/packages/generator-joplin",
"author": {
@@ -38,4 +38,4 @@
"repository": "https://github.com/laurent22/generator-joplin",
"license": "AGPL-3.0-or-later",
"private": true
}
}

View File

@@ -25,7 +25,7 @@
"@types/jsdom": "21.1.7",
"@types/markdown-it": "13.0.9",
"@types/mustache": "4.2.6",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@types/node-rsa": "1.1.4",
"@types/react": "18.3.23",
"@types/uuid": "10.0.0",
@@ -67,7 +67,7 @@
"fast-xml-parser": "3.21.1",
"file-type": "16.5.4",
"follow-redirects": "1.15.6",
"form-data": "4.0.3",
"form-data": "4.0.4",
"fs-extra": "11.2.0",
"hpagent": "1.2.0",
"html-entities": "1.4.0",

View File

@@ -71,6 +71,7 @@ import { Store } from 'redux';
import { dirname } from '@joplin/utils/path';
import SyncTargetJoplinServerSAML from '../SyncTargetJoplinServerSAML';
import { MarkupLanguage } from '@joplin/renderer';
import SearchEngine from '../services/search/SearchEngine';
// Each suite has its own separate data and temp directory so that multiple
// suites can be run at the same time. suiteName is what is used to
@@ -287,6 +288,7 @@ async function switchClient(id: number, options: any = null) {
currentClient_ = id;
BaseModel.setDb(databases_[id]);
KvStore.instance().setDb(databases_[id]);
SearchEngine.instance().setDb(databases_[id]);
BaseItem.encryptionService_ = encryptionServices_[id];
Resource.encryptionService_ = encryptionServices_[id];

View File

@@ -16,9 +16,9 @@ import { isJoplinPluginPackage, readJsonFile } from './lib/utils';
import { applyManifestOverrides, getObsoleteManifests, getSupersededPackages, readManifestOverrides } from './lib/overrideUtils';
import { execCommand } from '@joplin/utils';
import validateUntrustedManifest from './lib/validateUntrustedManifest';
import searchPlugins, { PackageInfo } from './lib/searchPlugins';
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
function pluginInfoFromSearchResults(results: any[]): NpmPackage[] {
function pluginInfoFromSearchResults(results: PackageInfo[]): NpmPackage[] {
const output: NpmPackage[] = [];
for (const r of results) {
@@ -245,8 +245,7 @@ async function commandBuild(args: CommandBuildArgs) {
chdir(previousDir);
const searchResults = (await execCommand('npm search keywords:joplin-plugin --searchlimit 5000 --json', { showStdout: false, showStderr: false })).trim();
const npmPackages = pluginInfoFromSearchResults(JSON.parse(searchResults));
const npmPackages = pluginInfoFromSearchResults(await searchPlugins());
for (const npmPackage of npmPackages) {
await processNpmPackage(npmPackage, repoDir, dryRun);

View File

@@ -0,0 +1,79 @@
import { URLSearchParams } from 'node:url';
export interface PackageInfo {
name: string;
version: string;
date: string;
keywords: string[];
}
interface SearchResult {
package: PackageInfo;
}
interface SearchResponse {
objects: SearchResult[];
total: number;
}
function validateResponse(response: unknown): asserts response is SearchResponse {
if (typeof response !== 'object') throw new Error('Invalid response (must be an object)');
if (!('total' in response) || typeof response.total !== 'number') {
throw new Error('Invalid response.total');
}
if (!('objects' in response) || !Array.isArray(response.objects)) {
throw new Error('response.objects must be an array');
}
for (const object of response.objects) {
if (!('package' in object)) throw new Error('Missing "package" field');
const packageField = object.package;
if (typeof packageField.name !== 'string') throw new Error('package.name: Invalid type');
if (typeof packageField.version !== 'string') throw new Error('package.version: Invalid type');
if (typeof packageField.date !== 'string') throw new Error('package.date: Invalid type');
if (!Array.isArray(packageField.keywords)) throw new Error('package.keywords: Invalid type');
}
}
const searchPlugins = async () => {
const pageSize = 100;
const makeRequest = async (start: number): Promise<SearchResponse> => {
const urlParams = new URLSearchParams({
text: 'keywords:joplin-plugin',
size: String(pageSize),
from: String(start),
});
// API documentation: https://github.com/npm/registry/blob/main/docs/REGISTRY-API.md#get-v1search
const query = `https://registry.npmjs.org/-/v1/search?${urlParams.toString()}`;
const result = await fetch(query);
const json: unknown = await result.json();
validateResponse(json);
return json;
};
const packageInfos: PackageInfo[] = [];
const addPackageInfos = (response: SearchResponse) => {
for (const object of response.objects) {
packageInfos.push(object.package);
}
};
const firstResponse = await makeRequest(0);
let total = firstResponse.total;
addPackageInfos(firstResponse);
for (let page = 1; packageInfos.length < total; page++) {
// Cap the maximum number of requests: Fail early in the case where the search query breaks
// in the future.
if (page >= 100) {
throw new Error('More requests sent than expected. Does maximumRequests need to be increased?');
}
const response = await makeRequest(page * pageSize);
total = response.total;
addPackageInfos(response);
}
return packageInfos;
};
export default searchPlugins;

View File

@@ -30,7 +30,7 @@
"devDependencies": {
"@types/fs-extra": "11.0.4",
"@types/jest": "29.5.14",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"jest": "29.7.0",
"source-map-loader": "5.0.0",
"typescript": "5.8.3",

View File

@@ -22,7 +22,7 @@
"devDependencies": {
"@types/jest": "29.5.14",
"@types/markdown-it": "13.0.9",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"mermaid": "11.6.0",

View File

@@ -72,7 +72,7 @@
"@types/koa": "2.15.0",
"@types/markdown-it": "13.0.9",
"@types/mustache": "4.2.6",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@types/node-os-utils": "1.3.4",
"@types/nodemailer": "6.4.17",
"@types/yargs": "17.0.33",

View File

@@ -205,3 +205,8 @@ Pokiesman
Gamstop
ESIGNER
TOTP
SPSSO
IDPSSO
nameid
attrname
dpkg

View File

@@ -52,7 +52,7 @@
"@types/js-yaml": "4.0.9",
"@types/markdown-it": "13.0.9",
"@types/mustache": "4.2.6",
"@types/node": "18.19.118",
"@types/node": "18.19.119",
"@types/node-fetch": "2.6.12",
"@types/yargs": "17.0.33",
"gettext-extractor": "3.8.0",

View File

@@ -179,6 +179,7 @@
"android-v3.4.6": true,
"v3.4.12": true,
"android-v3.4.7": true,
"ios-v13.4.3": true
"ios-v13.4.3": true,
"v3.5.4": true
}
}

View File

@@ -2,13 +2,17 @@ import { readFile } from 'fs/promises';
import { createTempDir } from './fs.test';
import { newHttpError, sendMessage, startServer, stopServer } from './ipc';
const getRandomPort = () => {
return Math.floor(Math.random() * (65535 - 20000 + 1)) + 20000;
};
describe('ipc', () => {
it('should send and receive messages', async () => {
const tempDir = await createTempDir();
const secretFilePath = `${tempDir}/secret.txt`;
const serverPort1 = 41110;
const serverPort2 = 41115;
const serverPort1 = getRandomPort();
const serverPort2 = serverPort1 + 5;
const server1 = await startServer(serverPort1, secretFilePath, async (request) => {
if (request.action === 'testing') {
@@ -87,7 +91,7 @@ describe('ipc', () => {
it('should not process message if secret is invalid', async () => {
const tempDir = await createTempDir();
const secretFilePath = `${tempDir}/secret.txt`;
const serverPort = 41120;
const serverPort = getRandomPort();
const server = await startServer(serverPort, secretFilePath, async (request) => {
if (request.action === 'testing') {

View File

@@ -1,5 +1,45 @@
# Joplin Desktop Changelog
## [v3.5.4](https://github.com/laurent22/joplin/releases/tag/v3.5.4) (Pre-release) - 2025-10-10T17:19:58Z
- New: Add support for mixed case tags ([#12931](https://github.com/laurent22/joplin/issues/12931) by [@mrjo118](https://github.com/mrjo118))
- New: Add write() method to Plugin Clipboard API ([#13348](https://github.com/laurent22/joplin/issues/13348) by [@bwat47](https://github.com/bwat47))
- Improved: Accessibility: Disable sync icon animation when reduce motion is enabled ([#13283](https://github.com/laurent22/joplin/issues/13283) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: Add hover + expanded arrow behavior for Notebook/Tags header ([#13190](https://github.com/laurent22/joplin/issues/13190)) ([#12292](https://github.com/laurent22/joplin/issues/12292) by [@maggie897](https://github.com/maggie897))
- Improved: Automatically retrigger the sync if there are more unsynced outgoing changes when sync completes ([#12989](https://github.com/laurent22/joplin/issues/12989) by [@mrjo118](https://github.com/mrjo118))
- Improved: Avoid excessive data usage when automatically triggering another sync ([#13261](https://github.com/laurent22/joplin/issues/13261) by [@mrjo118](https://github.com/mrjo118))
- Improved: Click on systray icon will show/hide Joplin main window ([#13299](https://github.com/laurent22/joplin/issues/13299)) ([#12572](https://github.com/laurent22/joplin/issues/12572) by [@trap000d](https://github.com/trap000d))
- Improved: Delete all note revisions when the note is permanently deleted ([#12609](https://github.com/laurent22/joplin/issues/12609)) ([#8718](https://github.com/laurent22/joplin/issues/8718) by [@pedr](https://github.com/pedr))
- Improved: Markdown editor search: Auto-scroll to the next match when the search changes ([#13242](https://github.com/laurent22/joplin/issues/13242)) ([#12343](https://github.com/laurent22/joplin/issues/12343) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: OCR: Fully disable the handwriting transcription backend when disabled in settings ([#13072](https://github.com/laurent22/joplin/issues/13072) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: OneNote importer: Simplify reporting import issues to the forum ([#13409](https://github.com/laurent22/joplin/issues/13409) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: Open the Joplin Plugin web page when clicking on a plugin name ([#13376](https://github.com/laurent22/joplin/issues/13376)) ([#13371](https://github.com/laurent22/joplin/issues/13371))
- Improved: Prefer user-specified CSS page sizing when printing to PDF ([#13130](https://github.com/laurent22/joplin/issues/13130)) ([#13096](https://github.com/laurent22/joplin/issues/13096) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: Remove Beta mention for Joplin Server ([#13367](https://github.com/laurent22/joplin/issues/13367))
- Improved: Support accepting shares with a new key format ([#12829](https://github.com/laurent22/joplin/issues/12829) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: Updated packages @axe-core/playwright (v4.10.2), @playwright/test (v1.53.2), @rollup/plugin-commonjs (v28.0.6), form-data (v4.0.3), glob (v11.0.3), react-select (v5.10.2), sass (v1.93.0), sharp (v0.34.3), style-to-js (v1.1.17)
- Improved: Upgrade tesseract.js to v6 ([#13345](https://github.com/laurent22/joplin/issues/13345)) ([#12803](https://github.com/laurent22/joplin/issues/12803) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: Upgrade to Electron 37.4.0 ([#13156](https://github.com/laurent22/joplin/issues/13156) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Improved: Use plugin repository URL when homepage URL is not available in config screen ([#13318](https://github.com/laurent22/joplin/issues/13318))
- Fixed: Accessibility: Fix dismissing the alarm dialog by pressing escape ([#13068](https://github.com/laurent22/joplin/issues/13068)) ([#12816](https://github.com/laurent22/joplin/issues/12816) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Fixed: Ensure notebook conflicts do not delete child notes and notebooks when resolved ([#13167](https://github.com/laurent22/joplin/issues/13167)) ([#11902](https://github.com/laurent22/joplin/issues/11902) by [@mrjo118](https://github.com/mrjo118))
- Fixed: Ensure the sync shows an error when the server is down, when using a local WebDAV server ([#13301](https://github.com/laurent22/joplin/issues/13301) by [@mrjo118](https://github.com/mrjo118))
- Fixed: Fix "insecure content security policy" warning ([#13288](https://github.com/laurent22/joplin/issues/13288) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Fixed: Fix error dialogs fail to appear in certain cases ([#13179](https://github.com/laurent22/joplin/issues/13179) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Fixed: Fix files without extension not being imported properly ([#12974](https://github.com/laurent22/joplin/issues/12974)) ([#12049](https://github.com/laurent22/joplin/issues/12049) by [@pedr](https://github.com/pedr))
- Fixed: Fix historic issue whereby the first revision created for a note does not contain the original contents ([#12674](https://github.com/laurent22/joplin/issues/12674) by [@mrjo118](https://github.com/mrjo118))
- Fixed: Fix images rendered in the Markdown editor don't reload when downloaded ([#13045](https://github.com/laurent22/joplin/issues/13045)) ([#12987](https://github.com/laurent22/joplin/issues/12987) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Fixed: Fix notes are moved to the conflict folder when a folder is unshared ([#12993](https://github.com/laurent22/joplin/issues/12993) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Fixed: Fix startup error when a non-English locale is selected ([#13347](https://github.com/laurent22/joplin/issues/13347)) ([#13346](https://github.com/laurent22/joplin/issues/13346) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))
- Fixed: Fix the order of attached images ([#12531](https://github.com/laurent22/joplin/issues/12531)) ([#12868](https://github.com/laurent22/joplin/issues/12868) by [@JZou-Code](https://github.com/JZou-Code))
- Fixed: Fixed image load failure when path contains '#' (13267) ([#13375](https://github.com/laurent22/joplin/issues/13375)) ([#13267](https://github.com/laurent22/joplin/issues/13267) by [@yingli-lab](https://github.com/yingli-lab))
- Fixed: Fixed red close button not working on macOS 26 ([#13311](https://github.com/laurent22/joplin/issues/13311)) ([#13196](https://github.com/laurent22/joplin/issues/13196) by [@yingli-lab](https://github.com/yingli-lab))
- Fixed: Hide 'Start application minimised' unless tray icon is enabled ([#13340](https://github.com/laurent22/joplin/issues/13340)) ([#13088](https://github.com/laurent22/joplin/issues/13088) by [@maggie897](https://github.com/maggie897))
- Fixed: Implement the config check for Joplin Server with SAML enabled ([#13360](https://github.com/laurent22/joplin/issues/13360)) ([#13328](https://github.com/laurent22/joplin/issues/13328) by [@ttcchhmm](https://github.com/ttcchhmm))
- Fixed: Prevent the default cut action handler to avoid double deletion ([#13208](https://github.com/laurent22/joplin/issues/13208)) ([#12239](https://github.com/laurent22/joplin/issues/12239) by [@JZou-Code](https://github.com/JZou-Code))
- Fixed: Skip copy event in TinyMCE if no content is selected. ([#13313](https://github.com/laurent22/joplin/issues/13313)) ([#12763](https://github.com/laurent22/joplin/issues/12763) by [@JZou-Code](https://github.com/JZou-Code))
- Fixed: Skip cut action in TinyMCE editor if no content is selected. ([#13315](https://github.com/laurent22/joplin/issues/13315)) ([#13314](https://github.com/laurent22/joplin/issues/13314) by [@JZou-Code](https://github.com/JZou-Code))
## [v3.4.12](https://github.com/laurent22/joplin/releases/tag/v3.4.12) - 2025-09-09T21:35:47Z
- Fixed: Fix error when saving in-editor rendering-related settings ([#13105](https://github.com/laurent22/joplin/issues/13105)) ([#13103](https://github.com/laurent22/joplin/issues/13103) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator))

View File

@@ -37,7 +37,7 @@ On desktop, the following patterns are replaced:
- `$math$`: Auto-formats to inline math (using KaTeX math syntax). After rendering, equations can be edited by double-clicking or with the "edit" option in the right click menu.
- `# Heading 1`: Creates a level 1 heading. The `#` should be at the start of the line.
- `## Heading 2`: Creates a level 2 heading.
- `## Heading 3`: Creates a level 3 heading.
- `### Heading 3`: Creates a level 3 heading.
- `- List`: Creates a bulleted list.
- `1. List`: Creates a numbered list.
- `---`, `___`, or `***`: Creates a horizontal rule.

View File

@@ -0,0 +1,7 @@
# Joplin Server LDAP support
Joplin Server supports authentication via LDAP (Lightweight Directory Access Protocol), allowing integration with existing directory services for centralised user management. This enables users to log in using their organisation's credentials, streamlining access control and improving security.
## Setup
To enable LDAP, you will need to set the environment variables as defined [in this file](https://github.com/laurent22/joplin/blob/2e846fe15d957873bfa6f16e44ccafc6b31e7a93/packages/server/src/env.ts#L136). You can define up to too LDAP providers.

125
readme/apps/server/saml.md Normal file
View File

@@ -0,0 +1,125 @@
# Joplin Server SAML support
Joplin Server supports authentication via SAML (Security Assertion Markup Language), allowing integration with identity providers for single sign-on (SSO). This enables users to log in securely using their existing organisational credentials, simplifying account management and enhancing security.
## Setup
To enable SAML, you will need to set the environment variables as defined [in this file](https://github.com/laurent22/joplin/blob/2e846fe15d957873bfa6f16e44ccafc6b31e7a93/packages/server/src/env.ts#L163) and provide a link to your SP and IDP config file.
An SP file would look like this:
```xml
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="Joplin">
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://localhost:22300/api/saml"
index="1" />
</md:SPSSODescriptor>
</md:EntityDescriptor>
```
While and IDP config would look like this:
<!-- cSpell:disable -->
```xml
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="saml-idp">
<md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIDIzCCAgugAwIBAgIUOGfU4onZ0So0R4L4FH2OUo7cmwcwDQYJKoZIhvcNAQELBQAwITEfMB0GA1UEAwwWVGVzdCBJZGVudGl0eSBQcm92aWRlcjAeFw0yNDEwMjUwOTI0NDBaFw00NDEwMjAwOTI0NDBaMCExHzAdBgNVBAMMFlRlc3QgSWRlbnRpdHkgUHJvdmlkZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrgUKiNwsnlCwQViTqUfTKJXtGQdFZ5ZHHupqNX3hLa2H/MqL25k00p9dw3h9ddpnpmvBsP4jaEeXF4ibU/HQ78cWiUzPkQripkTtYvAM2I/KodqyCHPJr0yJtFUCT/rDrtrCRZ1eZ+K1nvzVFBqiQwgY8IOmhVIqvK7r+sOuDoP7fFDbiZgDyD07noA/oMlcfkm/xj5O70YGX+Iqh8FMJTA8z6DyqTQKtXPBhndkchZDehCkWmKsmpvM3X9QBBl71tJoFu9WqGgtvfMWq+/WoTJ18jbcj0p2jhhEuvDsI1jmeisXzwunO0HtmbDgd17rjOP2CIXUffAV+gg7B5PFBAgMBAAGjUzBRMB0GA1UdDgQWBBSDjyS0o+Y8Sjb885BCo+bmvbwrgTAfBgNVHSMEGDAWgBSDjyS0o+Y8Sjb885BCo+bmvbwrgTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAMxqjfHu6rjnm4PeOXywpnRca8Md95tnh0YJNAu9Vb19jpqUF96psS1lZMqmZ66tnLPCi+rBAtI66BO2wClqxe5K9MeiJIZOwDHLqJ8TDGE+8LM/uEOqobtdjp1vSEuLAC2zeXba9ISqYUrXGcTic65EERGBnG3w2D/rTm7te7C0b6yYet1l4K1RqctxDaI90YV2a1aiT1wngaOQclHAJlR7c0kJP6JZaS/R56Y88S0exZo82u4CsI3GuY42M2ET74/5pllsRsYrQz6iXqnrbcpxvFAWj5D+1uq+rdqc8M0dW5CXZ7zLjJxXH9pFneOnSyX6YbuK+b6kdKUxKlQRMs</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIDIzCCAgugAwIBAgIUOGfU4onZ0So0R4L4FH2OUo7cmwcwDQYJKoZIhvcNAQELBQAwITEfMB0GA1UEAwwWVGVzdCBJZGVudGl0eSBQcm92aWRlcjAeFw0yNDEwMjUwOTI0NDBaFw00NDEwMjAwOTI0NDBaMCExHzAdBgNVBAMMFlRlc3QgSWRlbnRpdHkgUHJvdmlkZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrgUKiNwsnlCwQViTqUfTKJXtGQdFZ5ZHHupqNX3hLa2H/MqL25k00p9dw3h9ddpnpmvBsP4jaEeXF4ibU/HQ78cWiUzPkQripkTtYvAM2I/KodqyCHPJr0yJtFUCT/rDrtrCRZ1eZ+K1nvzVFBqiQwgY8IOmhVIqvK7r+sOuDoP7fFDbiZgDyD07noA/oMlcfkm/xj5O70YGX+Iqh8FMJTA8z6DyqTQKtXPBhndkchZDehCkWmKsmpvM3X9QBBl71tJoFu9WqGgtvfMWq+/WoTJ18jbcj0p2jhhEuvDsI1jmeisXzwunO0HtmbDgd17rjOP2CIXUffAV+gg7B5PFBAgMBAAGjUzBRMB0GA1UdDgQWBBSDjyS0o+Y8Sjb885BCo+bmvbwrgTAfBgNVHSMEGDAWgBSDjyS0o+Y8Sjb885BCo+bmvbwrgTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAMxqjfHu6rjnm4PeOXywpnRca8Md95tnh0YJNAu9Vb19jpqUF96psS1lZMqmZ66tnLPCi+rBAtI66BO2wClqxe5K9MeiJIZOwDHLqJ8TDGE+8LM/uEOqobtdjp1vSEuLAC2zeXba9ISqYUrXGcTic65EERGBnG3w2D/rTm7te7C0b6yYet1l4K1RqctxDaI90YV2a1aiT1wngaOQclHAJlR7c0kJP6JZaS/R56Y88S0exZo82u4CsI3GuY42M2ET74/5pllsRsYrQz6iXqnrbcpxvFAWj5D+1uq+rdqc8M0dW5CXZ7zLjJxXH9pFneOnSyX6YbuK+b6kdKUxKlQRMs</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:7000/saml/sso"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:7000/saml/sso"/>
<Attribute Name="firstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="First Name" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
<Attribute Name="lastName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Last Name" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
<Attribute Name="displayName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Display Name" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
<Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="E-Mail Address" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
<Attribute Name="mobilePhone" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Mobile Phone" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
<Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="Groups" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
<Attribute Name="userType" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="User Type" xmlns="urn:oasis:names:tc:SAML:2.0:assertion"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
```
<!-- cSpell:enable -->
## Required user attributes
Users must have the following attributes configured on your SAML provider:
- `email`: The user email.
- `displayName`: The user full name.
## Custom CA certificates
By default, the Joplin Server image does not include the `ca-certificates` which may be needed to get custom certificates for your mail server working. You can install those additional packages (and any other package), using the method below:
```yaml
# docker-compose.yml
services:
joplin-server:
image: path/to/image
ports:
- "80:80"
env_file: .env
volumes:
- ./config/data:/data:rw
- ./config/saml:/saml:ro
- ./config/certs:/tmp/certs:ro
user: root
command: >
bash -c '
# Install the missing packages
if ! dpkg -s ca-certificates >/dev/null 2>&1; then
apt update &&
apt install -y ca-certificates openssl
fi
# Create the CA folder if necessary
mkdir -p /usr/local/share/ca-certificates
# Copy the certificates only if modified
changed=false
for cert in /tmp/certs/*.crt; do
if [ -f "$cert" ]; then
target=/usr/local/share/ca-certificates/$(basename "$cert")
if [ ! -f "$target" ] || ! cmp -s "$cert" "$target"; then
cp "$cert" "$target"
changed=true
fi
fi
done
# Update the CA only if necessary
if [ "$changed" = true ]; then
update-ca-certificates
fi
# Launch the server
tini -- yarn start-server
'
```

View File

@@ -22,7 +22,7 @@ Please note that there cannot be more than 400 (maybe 500) words in those lists.
### Using comments
You can ignore a block of code by wrapping it in `// cSpell:disable` / `// cSpell:enable`.
You can ignore a block of code by wrapping it in `// cSpell:disable` / `// cSpell:enable` in JS/TS files, or in `<!-- cSpell:enable -->` / `<!-- cSpell:disable -->` in Markdown files.
Only do this when there's a large block of code that contains many words to be ignored. Otherwise prefer the word list because it means we don't pollute the code with additional comments.

179
yarn.lock
View File

@@ -9158,7 +9158,7 @@ __metadata:
"@testing-library/react-hooks": "npm:8.0.1"
"@types/jest": "npm:29.5.14"
"@types/mustache": "npm:4.2.6"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@types/react": "npm:18.3.23"
"@types/react-dom": "npm:18.3.7"
"@types/react-redux": "npm:7.1.33"
@@ -9250,17 +9250,17 @@ __metadata:
"@react-native-community/netinfo": "npm:11.4.1"
"@react-native-community/push-notification-ios": "npm:1.11.0"
"@react-native-documents/picker": "npm:10.1.5"
"@react-native/babel-preset": "npm:0.79.5"
"@react-native/babel-preset": "npm:0.80.1"
"@react-native/metro-config": "npm:0.79.5"
"@react-native/typescript-config": "npm:0.79.5"
"@sqlite.org/sqlite-wasm": "npm:3.46.0-build2"
"@testing-library/react-native": "npm:13.2.0"
"@types/fs-extra": "npm:11.0.4"
"@types/jest": "npm:29.5.14"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@types/react": "npm:19.0.14"
"@types/react-redux": "npm:7.1.33"
"@types/serviceworker": "npm:0.0.141"
"@types/serviceworker": "npm:0.0.142"
"@types/tar-stream": "npm:3.1.4"
assert-browserify: "npm:2.0.0"
babel-jest: "npm:29.7.0"
@@ -9274,9 +9274,9 @@ __metadata:
deprecated-react-native-prop-types: "npm:5.0.0"
esbuild: "npm:0.25.6"
events: "npm:3.3.0"
expo: "npm:53.0.19"
expo: "npm:53.0.20"
expo-av: "npm:15.1.7"
expo-camera: "npm:16.1.10"
expo-camera: "npm:16.1.11"
expo-local-authentication: "npm:16.0.5"
fast-deep-equal: "npm:3.1.3"
fs-extra: "npm:11.2.0"
@@ -9405,7 +9405,7 @@ __metadata:
"@replit/codemirror-vim": "npm:6.2.1"
"@testing-library/react-hooks": "npm:8.0.1"
"@types/jest": "npm:29.5.14"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@types/react": "npm:18.3.23"
"@types/react-redux": "npm:7.1.33"
"@types/styled-components": "npm:5.1.32"
@@ -9437,7 +9437,7 @@ __metadata:
resolution: "@joplin/fork-htmlparser2@workspace:packages/fork-htmlparser2"
dependencies:
"@types/jest": "npm:29.5.14"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@typescript-eslint/eslint-plugin": "npm:6.21.0"
"@typescript-eslint/parser": "npm:6.21.0"
coveralls: "npm:3.1.1"
@@ -9467,7 +9467,7 @@ __metadata:
resolution: "@joplin/fork-uslug@workspace:packages/fork-uslug"
dependencies:
"@types/jest": "npm:29.5.14"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
jest: "npm:29.7.0"
node-emoji: "npm:1.11.0"
typescript: "npm:5.8.3"
@@ -9516,7 +9516,7 @@ __metadata:
"@types/markdown-it": "npm:13.0.9"
"@types/mustache": "npm:4.2.6"
"@types/nanoid": "npm:3.0.0"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@types/node-rsa": "npm:1.1.4"
"@types/react": "npm:18.3.23"
"@types/uuid": "npm:10.0.0"
@@ -9534,7 +9534,7 @@ __metadata:
fast-xml-parser: "npm:3.21.1"
file-type: "npm:16.5.4"
follow-redirects: "npm:1.15.6"
form-data: "npm:4.0.3"
form-data: "npm:4.0.4"
fs-extra: "npm:11.2.0"
hpagent: "npm:1.2.0"
html-entities: "npm:1.4.0"
@@ -9632,7 +9632,7 @@ __metadata:
"@joplin/utils": "npm:~3.5"
"@types/fs-extra": "npm:11.0.4"
"@types/jest": "npm:29.5.14"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
fs-extra: "npm:11.2.0"
gh-release-assets: "npm:2.0.1"
jest: "npm:29.7.0"
@@ -9687,7 +9687,7 @@ __metadata:
"@joplin/utils": "npm:~3.5"
"@types/jest": "npm:29.5.14"
"@types/markdown-it": "npm:13.0.9"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
font-awesome-filetypes: "npm:2.1.0"
fs-extra: "npm:11.2.0"
highlight.js: "npm:11.11.1"
@@ -9738,7 +9738,7 @@ __metadata:
"@types/koa": "npm:2.15.0"
"@types/markdown-it": "npm:13.0.9"
"@types/mustache": "npm:4.2.6"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@types/node-os-utils": "npm:1.3.4"
"@types/nodemailer": "npm:6.4.17"
"@types/uuid": "npm:10.0.0"
@@ -9798,7 +9798,7 @@ __metadata:
"@types/js-yaml": "npm:4.0.9"
"@types/markdown-it": "npm:13.0.9"
"@types/mustache": "npm:4.2.6"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@types/node-fetch": "npm:2.6.12"
"@types/yargs": "npm:17.0.33"
compare-versions: "npm:6.1.1"
@@ -12336,6 +12336,16 @@ __metadata:
languageName: node
linkType: hard
"@react-native/babel-plugin-codegen@npm:0.80.1":
version: 0.80.1
resolution: "@react-native/babel-plugin-codegen@npm:0.80.1"
dependencies:
"@babel/traverse": "npm:^7.25.3"
"@react-native/codegen": "npm:0.80.1"
checksum: 10/42843a8b3fd4f469f60f9b23a3f3b7820d9520df0a495d878e907bd5548c7155ce65482de6c120351f50b2cd7c8373a08625efc9cc0bc3de56e0a83b9cfece08
languageName: node
linkType: hard
"@react-native/babel-preset@npm:0.79.5":
version: 0.79.5
resolution: "@react-native/babel-preset@npm:0.79.5"
@@ -12391,6 +12401,61 @@ __metadata:
languageName: node
linkType: hard
"@react-native/babel-preset@npm:0.80.1":
version: 0.80.1
resolution: "@react-native/babel-preset@npm:0.80.1"
dependencies:
"@babel/core": "npm:^7.25.2"
"@babel/plugin-proposal-export-default-from": "npm:^7.24.7"
"@babel/plugin-syntax-dynamic-import": "npm:^7.8.3"
"@babel/plugin-syntax-export-default-from": "npm:^7.24.7"
"@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3"
"@babel/plugin-syntax-optional-chaining": "npm:^7.8.3"
"@babel/plugin-transform-arrow-functions": "npm:^7.24.7"
"@babel/plugin-transform-async-generator-functions": "npm:^7.25.4"
"@babel/plugin-transform-async-to-generator": "npm:^7.24.7"
"@babel/plugin-transform-block-scoping": "npm:^7.25.0"
"@babel/plugin-transform-class-properties": "npm:^7.25.4"
"@babel/plugin-transform-classes": "npm:^7.25.4"
"@babel/plugin-transform-computed-properties": "npm:^7.24.7"
"@babel/plugin-transform-destructuring": "npm:^7.24.8"
"@babel/plugin-transform-flow-strip-types": "npm:^7.25.2"
"@babel/plugin-transform-for-of": "npm:^7.24.7"
"@babel/plugin-transform-function-name": "npm:^7.25.1"
"@babel/plugin-transform-literals": "npm:^7.25.2"
"@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.7"
"@babel/plugin-transform-modules-commonjs": "npm:^7.24.8"
"@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.7"
"@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.7"
"@babel/plugin-transform-numeric-separator": "npm:^7.24.7"
"@babel/plugin-transform-object-rest-spread": "npm:^7.24.7"
"@babel/plugin-transform-optional-catch-binding": "npm:^7.24.7"
"@babel/plugin-transform-optional-chaining": "npm:^7.24.8"
"@babel/plugin-transform-parameters": "npm:^7.24.7"
"@babel/plugin-transform-private-methods": "npm:^7.24.7"
"@babel/plugin-transform-private-property-in-object": "npm:^7.24.7"
"@babel/plugin-transform-react-display-name": "npm:^7.24.7"
"@babel/plugin-transform-react-jsx": "npm:^7.25.2"
"@babel/plugin-transform-react-jsx-self": "npm:^7.24.7"
"@babel/plugin-transform-react-jsx-source": "npm:^7.24.7"
"@babel/plugin-transform-regenerator": "npm:^7.24.7"
"@babel/plugin-transform-runtime": "npm:^7.24.7"
"@babel/plugin-transform-shorthand-properties": "npm:^7.24.7"
"@babel/plugin-transform-spread": "npm:^7.24.7"
"@babel/plugin-transform-sticky-regex": "npm:^7.24.7"
"@babel/plugin-transform-typescript": "npm:^7.25.2"
"@babel/plugin-transform-unicode-regex": "npm:^7.24.7"
"@babel/template": "npm:^7.25.0"
"@react-native/babel-plugin-codegen": "npm:0.80.1"
babel-plugin-syntax-hermes-parser: "npm:0.28.1"
babel-plugin-transform-flow-enums: "npm:^0.0.2"
react-refresh: "npm:^0.14.0"
peerDependencies:
"@babel/core": "*"
checksum: 10/c922b0a90294724d1c5056edf5473ba52c7b42b82d31995d913f69c4f8c163a9bc25bebdcf84af88ab4ca2135d9a46617a55005d73fa54254e5bc45878f022b1
languageName: node
linkType: hard
"@react-native/codegen@npm:0.79.2":
version: 0.79.2
resolution: "@react-native/codegen@npm:0.79.2"
@@ -12421,6 +12486,21 @@ __metadata:
languageName: node
linkType: hard
"@react-native/codegen@npm:0.80.1":
version: 0.80.1
resolution: "@react-native/codegen@npm:0.80.1"
dependencies:
glob: "npm:^7.1.1"
hermes-parser: "npm:0.28.1"
invariant: "npm:^2.2.4"
nullthrows: "npm:^1.1.1"
yargs: "npm:^17.6.2"
peerDependencies:
"@babel/core": "*"
checksum: 10/cd568b3721b4d52797f7eb8acfff17832db376e4b54299bf15c7db840e8e1ea7e525c7d2e58da0d3775360507ea1070a1a5f909829ed5a0fcebb88bcce8018c7
languageName: node
linkType: hard
"@react-native/community-cli-plugin@npm:0.79.2":
version: 0.79.2
resolution: "@react-native/community-cli-plugin@npm:0.79.2"
@@ -14514,12 +14594,12 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:18.19.118":
version: 18.19.118
resolution: "@types/node@npm:18.19.118"
"@types/node@npm:18.19.119":
version: 18.19.119
resolution: "@types/node@npm:18.19.119"
dependencies:
undici-types: "npm:~5.26.4"
checksum: 10/ed7a7ef22b10f463ea168f0d9a354902b1cc3af7d8df94cbbd986a60c504afab7d184ea6bf9fd2125d8e800d076f60171bb593567014a54dbf83d1645819234d
checksum: 10/d41d94e575611f0d94498e1c91fc06f4f448dd4b1e952fc8812b69b1e549874a18d510334b6e88d65d5a8ac77de07bf21e2637b297f49d80319204c43aa9fa59
languageName: node
linkType: hard
@@ -14850,10 +14930,10 @@ __metadata:
languageName: node
linkType: hard
"@types/serviceworker@npm:0.0.141":
version: 0.0.141
resolution: "@types/serviceworker@npm:0.0.141"
checksum: 10/e4f8a77dbdefdc87d06b56ef571ae5c6fe222022dfdcdea5502f18b1cdb1732be19d8f0a2a50eb4875aef1252687928881812df15cdf4dd12cb9efa6b06e5d4c
"@types/serviceworker@npm:0.0.142":
version: 0.0.142
resolution: "@types/serviceworker@npm:0.0.142"
checksum: 10/f0671243a0b91fdf66a63e1793b4d604329dbabca608c8d1e3915f03d0d315afbe97e761e575eb5327ebf0c9934c6077733e7607f8e15255b3958d4955fee044
languageName: node
linkType: hard
@@ -17687,13 +17767,13 @@ __metadata:
linkType: hard
"axios@npm:^1.7.7":
version: 1.9.0
resolution: "axios@npm:1.9.0"
version: 1.12.2
resolution: "axios@npm:1.12.2"
dependencies:
follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.0"
form-data: "npm:^4.0.4"
proxy-from-env: "npm:^1.1.0"
checksum: 10/a2f90bba56820883879f32a237e2b9ff25c250365dcafd41cec41b3406a3df334a148f90010182dfdadb4b41dc59f6f0b3e8898ff41b666d1157b5f3f4523497
checksum: 10/886a79770594eaad76493fecf90344b567bd956240609b5dcd09bd0afe8d3e6f1ad6d3257a93a483b6192b409d4b673d9515a34619e3e3ed1b2c0ec2a83b20ba
languageName: node
linkType: hard
@@ -18004,6 +18084,15 @@ __metadata:
languageName: node
linkType: hard
"babel-plugin-syntax-hermes-parser@npm:0.28.1":
version: 0.28.1
resolution: "babel-plugin-syntax-hermes-parser@npm:0.28.1"
dependencies:
hermes-parser: "npm:0.28.1"
checksum: 10/2cbc921e663463480ead9ccc8bb229a5196032367ba2b5ccb18a44faa3afa84b4dc493297749983b9a837a3d76b0b123664aecc06f9122618c3246f03e076a9d
languageName: node
linkType: hard
"babel-plugin-syntax-jsx@npm:^6.18.0":
version: 6.18.0
resolution: "babel-plugin-syntax-jsx@npm:6.18.0"
@@ -26133,9 +26222,9 @@ __metadata:
languageName: node
linkType: hard
"expo-camera@npm:16.1.10":
version: 16.1.10
resolution: "expo-camera@npm:16.1.10"
"expo-camera@npm:16.1.11":
version: 16.1.11
resolution: "expo-camera@npm:16.1.11"
dependencies:
invariant: "npm:^2.2.4"
peerDependencies:
@@ -26146,7 +26235,7 @@ __metadata:
peerDependenciesMeta:
react-native-web:
optional: true
checksum: 10/40cabe31c6567fe4e97aa9420a7958a0103bb35a9563c70a27052a1674aba3c2e21ec9605df7d77e6fe9af49adafe0d09a71b2513c8ae8e1e4a347ab21cbacbb
checksum: 10/8e44f73a4239b52ba9a5784288d3d2c1d53882b85afad0b75947984929f9a25cea997c99e44e81751122c8b1fd7e65dccd43c3609065c5944067ce6ba50a71f0
languageName: node
linkType: hard
@@ -26223,18 +26312,18 @@ __metadata:
languageName: node
linkType: hard
"expo-modules-core@npm:2.4.2":
version: 2.4.2
resolution: "expo-modules-core@npm:2.4.2"
"expo-modules-core@npm:2.5.0":
version: 2.5.0
resolution: "expo-modules-core@npm:2.5.0"
dependencies:
invariant: "npm:^2.2.4"
checksum: 10/c8992dcd7e9a3124c245beb65333add2c1955200724ac5b0a3fc5214f8da2b7779f6f88474b284be5dc9bc4030369c2189ea14200b97854758e086c0ee10c6bf
checksum: 10/ad34d71571bcfbff166da47fa3847ab03886b691b80079d9a3d111e5061cccbaa785c55eb48451ce7d300ce725d32f844492b0109d069dc89f70864b9de2c1c6
languageName: node
linkType: hard
"expo@npm:53.0.19":
version: 53.0.19
resolution: "expo@npm:53.0.19"
"expo@npm:53.0.20":
version: 53.0.20
resolution: "expo@npm:53.0.20"
dependencies:
"@babel/runtime": "npm:^7.20.0"
"@expo/cli": "npm:0.24.20"
@@ -26250,7 +26339,7 @@ __metadata:
expo-font: "npm:~13.3.2"
expo-keep-awake: "npm:~14.1.4"
expo-modules-autolinking: "npm:2.1.14"
expo-modules-core: "npm:2.4.2"
expo-modules-core: "npm:2.5.0"
react-native-edge-to-edge: "npm:1.6.0"
whatwg-url-without-unicode: "npm:8.0.0-3"
peerDependencies:
@@ -26270,7 +26359,7 @@ __metadata:
expo: bin/cli
expo-modules-autolinking: bin/autolinking
fingerprint: bin/fingerprint
checksum: 10/e48538498158176e2af9ed3105cd7547f47dffd50045c3ac8d61181cd93cafc44d56107e7bfdcc0de849ce44b0155fd91949989151805d03ae4ad6c2e66c7561
checksum: 10/73cb5ad2e3eb8927390ff685b3f53b0a496fdaa99ec73f6cc3faa732534ad5ec0b5378abdf3da2d0c692397b758eadeed1eabad7f412f0b7576c29f2518e6f93
languageName: node
linkType: hard
@@ -27318,16 +27407,16 @@ __metadata:
languageName: node
linkType: hard
"form-data@npm:4.0.3":
version: 4.0.3
resolution: "form-data@npm:4.0.3"
"form-data@npm:4.0.4, form-data@npm:^4.0.4":
version: 4.0.4
resolution: "form-data@npm:4.0.4"
dependencies:
asynckit: "npm:^0.4.0"
combined-stream: "npm:^1.0.8"
es-set-tostringtag: "npm:^2.1.0"
hasown: "npm:^2.0.2"
mime-types: "npm:^2.1.12"
checksum: 10/22f6e55e6f32a5797a500ed7ca5aa9d690c4de6e1b3308f25f0d83a27d08d91a265ab59a190db2305b15144f8f07df08e8117bad6a93fc93de1baa838bfcc0b5
checksum: 10/a4b62e21932f48702bc468cc26fb276d186e6b07b557e3dd7cc455872bdbb82db7db066844a64ad3cf40eaf3a753c830538183570462d3649fdfd705601cbcfb
languageName: node
linkType: hard
@@ -32695,7 +32784,7 @@ __metadata:
"@joplin/utils": "npm:~3.5"
"@types/fs-extra": "npm:11.0.4"
"@types/jest": "npm:29.5.14"
"@types/node": "npm:18.19.118"
"@types/node": "npm:18.19.119"
"@types/proper-lockfile": "npm:^4.1.2"
aws-sdk: "npm:2.1340.0"
chalk: "npm:4.1.2"