From 1688dff25920423382c7ea073205bebc1b23d924 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 17 Mar 2026 23:10:30 +0100 Subject: [PATCH] fix(files_external): properly handle API errors Signed-off-by: Ferdinand Thiessen --- .../AddExternalStorageDialog.vue | 8 +- .../AddExternalStorageDialog/MountOptions.vue | 9 +- apps/files_external/src/store/storages.ts | 54 ++++- .../src/views/ExternalStoragesSection.vue | 5 +- package-lock.json | 184 +++++++++--------- package.json | 2 +- 6 files changed, 151 insertions(+), 111 deletions(-) diff --git a/apps/files_external/src/components/AddExternalStorageDialog/AddExternalStorageDialog.vue b/apps/files_external/src/components/AddExternalStorageDialog/AddExternalStorageDialog.vue index c1d68549bcd..7e5613bb9a3 100644 --- a/apps/files_external/src/components/AddExternalStorageDialog/AddExternalStorageDialog.vue +++ b/apps/files_external/src/components/AddExternalStorageDialog/AddExternalStorageDialog.vue @@ -33,7 +33,7 @@ const open = defineModel('open', { default: true }) const { storage = { backendOptions: {}, mountOptions: {}, type: isAdmin ? 'system' : 'personal' }, } = defineProps<{ - storage?: Partial & { backendOptions: IStorage['backendOptions'] } + storage?: Partial }>() defineEmits<{ @@ -88,7 +88,7 @@ watch(authMechanisms, () => { :label="t('files_external', 'Folder name')" required /> - + { required /> diff --git a/apps/files_external/src/components/AddExternalStorageDialog/MountOptions.vue b/apps/files_external/src/components/AddExternalStorageDialog/MountOptions.vue index c7f538e6e06..eb05f2ee720 100644 --- a/apps/files_external/src/components/AddExternalStorageDialog/MountOptions.vue +++ b/apps/files_external/src/components/AddExternalStorageDialog/MountOptions.vue @@ -14,17 +14,14 @@ import NcButton from '@nextcloud/vue/components/NcButton' import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import NcSelect from '@nextcloud/vue/components/NcSelect' +import { parseMountOptions } from '../../store/storages.ts' import { MountOptionsCheckFilesystem } from '../../types.ts' const mountOptions = defineModel>({ required: true }) watchEffect(() => { if (Object.keys(mountOptions.value).length === 0) { - mountOptions.value.encrypt = true - mountOptions.value.previews = true - mountOptions.value.enable_sharing = false - mountOptions.value.filesystem_check_changes = MountOptionsCheckFilesystem.OncePerRequest - mountOptions.value.encoding_compatibility = false - mountOptions.value.readonly = false + // parse and initialize with defaults if needed + mountOptions.value = parseMountOptions(mountOptions.value) } }) diff --git a/apps/files_external/src/store/storages.ts b/apps/files_external/src/store/storages.ts index d73c7d7857b..f2d7437c3ea 100644 --- a/apps/files_external/src/store/storages.ts +++ b/apps/files_external/src/store/storages.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import type { IStorage } from '../types.d.ts' +import type { IStorage } from '../types.ts' import axios from '@nextcloud/axios' import { loadState } from '@nextcloud/initial-state' @@ -11,6 +11,7 @@ import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextc import { generateUrl } from '@nextcloud/router' import { defineStore } from 'pinia' import { ref, toRaw } from 'vue' +import { MountOptionsCheckFilesystem } from '../types.ts' const { isAdmin } = loadState<{ isAdmin: boolean }>('files_external', 'settings') @@ -30,7 +31,7 @@ export const useStorages = defineStore('files_external--storages', () => { toRaw(storage), { confirmPassword: PwdConfirmationMode.Strict }, ) - globalStorages.value.push(data) + globalStorages.value.push(parseStorage(data)) } /** @@ -45,7 +46,7 @@ export const useStorages = defineStore('files_external--storages', () => { toRaw(storage), { confirmPassword: PwdConfirmationMode.Strict }, ) - userStorages.value.push(data) + userStorages.value.push(parseStorage(data)) } /** @@ -77,7 +78,7 @@ export const useStorages = defineStore('files_external--storages', () => { { confirmPassword: PwdConfirmationMode.Strict }, ) - overrideStorage(data) + overrideStorage(parseStorage(data)) } /** @@ -87,7 +88,7 @@ export const useStorages = defineStore('files_external--storages', () => { */ async function reloadStorage(storage: IStorage) { const { data } = await axios.get(getUrl(storage)) - overrideStorage(data) + overrideStorage(parseStorage(data)) } // initialize the store @@ -111,6 +112,7 @@ export const useStorages = defineStore('files_external--storages', () => { const url = `apps/files_external/${type}` const { data } = await axios.get>(generateUrl(url)) return Object.values(data) + .map(parseStorage) } /** @@ -150,3 +152,45 @@ export const useStorages = defineStore('files_external--storages', () => { } } }) + +/** + * @param storage - The storage from API + */ +function parseStorage(storage: IStorage) { + return { + ...storage, + mountOptions: parseMountOptions(storage.mountOptions), + } +} + +/** + * Parse the mount options and convert string boolean values to + * actual booleans and numeric strings to numbers + * + * @param options - The mount options to parse + */ +export function parseMountOptions(options: IStorage['mountOptions']) { + const mountOptions = { ...options } + mountOptions.encrypt = convertBooleanOptions(mountOptions.encrypt, true) + mountOptions.previews = convertBooleanOptions(mountOptions.previews, true) + mountOptions.enable_sharing = convertBooleanOptions(mountOptions.enable_sharing, false) + mountOptions.filesystem_check_changes = typeof mountOptions.filesystem_check_changes === 'string' + ? Number.parseInt(mountOptions.filesystem_check_changes) + : (mountOptions.filesystem_check_changes ?? MountOptionsCheckFilesystem.OncePerRequest) + mountOptions.encoding_compatibility = convertBooleanOptions(mountOptions.encoding_compatibility, false) + mountOptions.readonly = convertBooleanOptions(mountOptions.readonly, false) + return mountOptions +} + +/** + * Convert backend encoding of boolean options + * + * @param option - The option value from API + * @param fallback - The fallback (default) value + */ +function convertBooleanOptions(option: unknown, fallback = false) { + if (option === undefined) { + return fallback + } + return option === true || option === 'true' || option === '1' +} diff --git a/apps/files_external/src/views/ExternalStoragesSection.vue b/apps/files_external/src/views/ExternalStoragesSection.vue index 484aa5cf110..617db37389e 100644 --- a/apps/files_external/src/views/ExternalStoragesSection.vue +++ b/apps/files_external/src/views/ExternalStoragesSection.vue @@ -59,7 +59,8 @@ async function addStorage(storage?: Partial) { } newStorage.value = undefined } catch (error) { - logger.error('Failed to add external storage', { error }) + logger.error('Failed to add external storage', { error, storage }) + newStorage.value = { ...storage } showDialog.value = true } } @@ -134,8 +135,8 @@ async function addStorage(storage?: Partial) { diff --git a/package-lock.json b/package-lock.json index 854d51edeb5..dcd8782f802 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@nextcloud/initial-state": "^3.0.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/logger": "^3.0.3", - "@nextcloud/password-confirmation": "^6.0.3", + "@nextcloud/password-confirmation": "^6.1.0", "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0", "@nextcloud/sharing": "^0.4.0", @@ -1509,28 +1509,28 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", - "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.10" + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", - "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.4", - "@floating-ui/utils": "^0.2.10" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, "node_modules/@grpc/grpc-js": { @@ -2522,9 +2522,9 @@ } }, "node_modules/@nextcloud/password-confirmation": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-6.0.3.tgz", - "integrity": "sha512-tgbzwfhlXXd9Eq8ZnYrTeH8bEkdyIgybN45Tkip01b3xABUlr0tMGGj8+ZNp2pozytcK+k1l6fyvRPc09g0rIw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-6.1.0.tgz", + "integrity": "sha512-N2ChXDbPcUcQCoAjj1yc65zfc61yiKpdM3qm/y3Y/y//NG7XWNNINwBg85lqJ2SISgmVStpsQ1d0blpFCoQXkQ==", "license": "MIT", "dependencies": { "@nextcloud/auth": "^2.5.3", @@ -2532,8 +2532,8 @@ "@nextcloud/l10n": "^3.4.1", "@nextcloud/logger": "^3.0.3", "@nextcloud/router": "^3.1.0", - "@nextcloud/vue": "^9.5.0", - "vue": "^3.5.29" + "@nextcloud/vue": "^9.6.0", + "vue": "^3.5.30" }, "engines": { "node": "^20.0.0 || ^22.0.0 || ^24.0.0" @@ -2636,13 +2636,13 @@ } }, "node_modules/@nextcloud/vue": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-9.5.0.tgz", - "integrity": "sha512-CQxBfHhF+Q+2r7RXd+l/eSjttJU8A2JFUyq5VpvjfpIql355kejc8bbNnM1pKgGRGSBuW9qw5Ohx0puzHge10w==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-9.6.0.tgz", + "integrity": "sha512-RZuMnrNwzajx3AbJcGHC49NUORSPHMRbzhHCBlR0Z5N3BvUmy5d7MPVTqsmJXiO5emSCTanJ+rwDeo6HTAX3ng==", "license": "AGPL-3.0-or-later", "dependencies": { "@ckpack/vue-color": "^1.6.0", - "@floating-ui/dom": "^1.7.5", + "@floating-ui/dom": "^1.7.6", "@nextcloud/auth": "^2.5.3", "@nextcloud/axios": "^2.5.2", "@nextcloud/browser-storage": "^0.5.0", @@ -2652,14 +2652,14 @@ "@nextcloud/l10n": "^3.4.1", "@nextcloud/logger": "^3.0.3", "@nextcloud/router": "^3.1.0", - "@nextcloud/sharing": "^0.3.0", + "@nextcloud/sharing": "^0.4.0", "@vuepic/vue-datepicker": "^11.0.3", - "@vueuse/components": "^14.2.0", - "@vueuse/core": "^14.0.0", + "@vueuse/components": "^14.2.1", + "@vueuse/core": "^14.2.1", "blurhash": "^2.0.5", "clone": "^2.1.2", "debounce": "^3.0.0", - "dompurify": "^3.3.1", + "dompurify": "^3.3.3", "emoji-mart-vue-fast": "^15.0.5", "escape-html": "^1.0.3", "floating-vue": "^5.2.2", @@ -2672,6 +2672,7 @@ "remark-breaks": "^4.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", + "remark-stringify": "^11.0.0", "remark-unlink-protocols": "^1.0.0", "splitpanes": "^4.0.4", "striptags": "^3.2.0", @@ -2682,50 +2683,49 @@ "unist-builder": "^4.0.0", "unist-util-visit": "^5.1.0", "vue": "^3.5.18", - "vue-router": "^5.0.2", + "vue-router": "^5.0.3", "vue-select": "^4.0.0-beta.6" }, "engines": { "node": "^20.11.0 || ^22 || ^24" } }, - "node_modules/@nextcloud/vue/node_modules/@nextcloud/files": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz", - "integrity": "sha512-vBo8tf3Xh6efiF8CrEo3pKj9AtvAF6RdDGO1XKL65IxV8+UUd9Uxl2lUExHlzoDRRczCqfGfaWfRRaFhYqce5Q==", - "license": "AGPL-3.0-or-later", - "optional": true, + "node_modules/@nextcloud/vue/node_modules/@vueuse/core": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz", + "integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==", + "license": "MIT", "dependencies": { - "@nextcloud/auth": "^2.5.3", - "@nextcloud/capabilities": "^1.2.1", - "@nextcloud/l10n": "^3.4.1", - "@nextcloud/logger": "^3.0.3", - "@nextcloud/paths": "^3.0.0", - "@nextcloud/router": "^3.1.0", - "@nextcloud/sharing": "^0.3.0", - "cancelable-promise": "^4.3.1", - "is-svg": "^6.1.0", - "typescript-event-target": "^1.1.1", - "webdav": "^5.8.0" + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.2.1", + "@vueuse/shared": "14.2.1" }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" } }, - "node_modules/@nextcloud/vue/node_modules/@nextcloud/sharing": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.3.0.tgz", - "integrity": "sha512-kV7qeUZvd1fTKeFyH+W5Qq5rNOqG9rLATZM3U9MBxWXHJs3OxMqYQb8UQ3NYONzsX3zDGJmdQECIGHm1ei2sCA==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/initial-state": "^3.0.0", - "is-svg": "^6.1.0" + "node_modules/@nextcloud/vue/node_modules/@vueuse/metadata": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.2.1.tgz", + "integrity": "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@nextcloud/vue/node_modules/@vueuse/shared": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.2.1.tgz", + "integrity": "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - }, - "optionalDependencies": { - "@nextcloud/files": "^3.12.0" + "peerDependencies": { + "vue": "^3.5.0" } }, "node_modules/@nextcloud/vue/node_modules/focus-trap": { @@ -9021,17 +9021,6 @@ "@floating-ui/core": "^1.1.0" } }, - "node_modules/focus-trap": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.6.tgz", - "integrity": "sha512-v/Z8bvMCajtx4mEXmOo7QEsIzlIOqRXTIwgUfsFOF9gEsespdbD0AkPIka1bSXZ8Y8oZ+2IVDQZePkTfEHZl7Q==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tabbable": "^6.3.0" - } - }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -14074,6 +14063,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-unlink-protocols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/remark-unlink-protocols/-/remark-unlink-protocols-1.0.0.tgz", @@ -17758,14 +17762,14 @@ } }, "node_modules/vue-router": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.2.tgz", - "integrity": "sha512-YFhwaE5c5JcJpNB1arpkl4/GnO32wiUWRB+OEj1T0DlDxEZoOfbltl2xEwktNU/9o1sGcGburIXSpbLpPFe/6w==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.3.tgz", + "integrity": "sha512-nG1c7aAFac7NYj8Hluo68WyWfc41xkEjaR0ViLHCa3oDvTQ/nIuLJlXJX1NUPw/DXzx/8+OKMng045HHQKQKWw==", "license": "MIT", "dependencies": { "@babel/generator": "^7.28.6", "@vue-macros/common": "^3.1.1", - "@vue/devtools-api": "^8.0.0", + "@vue/devtools-api": "^8.0.6", "ast-walker-scope": "^0.8.3", "chokidar": "^5.0.0", "json5": "^2.2.3", @@ -17803,37 +17807,31 @@ } }, "node_modules/vue-router/node_modules/@vue/devtools-api": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.0.6.tgz", - "integrity": "sha512-+lGBI+WTvJmnU2FZqHhEB8J1DXcvNlDeEalz77iYgOdY1jTj1ipSBaKj3sRhYcy+kqA8v/BSuvOz1XJucfQmUA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.0.tgz", + "integrity": "sha512-O44X57jjkLKbLEc4OgL/6fEPOOanRJU8kYpCE8qfKlV96RQZcdzrcLI5mxMuVRUeXhHKIHGhCpHacyCk0HyO4w==", "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^8.0.6" + "@vue/devtools-kit": "^8.1.0" } }, "node_modules/vue-router/node_modules/@vue/devtools-kit": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.6.tgz", - "integrity": "sha512-9zXZPTJW72OteDXeSa5RVML3zWDCRcO5t77aJqSs228mdopYj5AiTpihozbsfFJ0IodfNs7pSgOGO3qfCuxDtw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.0.tgz", + "integrity": "sha512-/NZlS4WtGIB54DA/z10gzk+n/V7zaqSzYZOVlg2CfdnpIKdB61bd7JDIMxf/zrtX41zod8E2/bbEBoW/d7x70Q==", "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^8.0.6", + "@vue/devtools-shared": "^8.1.0", "birpc": "^2.6.1", "hookable": "^5.5.3", - "mitt": "^3.0.1", - "perfect-debounce": "^2.0.0", - "speakingurl": "^14.0.1", - "superjson": "^2.2.2" + "perfect-debounce": "^2.0.0" } }, "node_modules/vue-router/node_modules/@vue/devtools-shared": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.6.tgz", - "integrity": "sha512-Pp1JylTqlgMJvxW6MGyfTF8vGvlBSCAvMFaDCYa82Mgw7TT5eE5kkHgDvmOGHWeJE4zIDfCpCxHapsK2LtIAJg==", - "license": "MIT", - "dependencies": { - "rfdc": "^1.4.1" - } + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.0.tgz", + "integrity": "sha512-h8uCb4Qs8UT8VdTT5yjY6tOJ//qH7EpxToixR0xqejR55t5OdISIg7AJ7eBkhBs8iu1qG5gY3QQNN1DF1EelAA==", + "license": "MIT" }, "node_modules/vue-router/node_modules/chokidar": { "version": "5.0.0", diff --git a/package.json b/package.json index 4464f579577..51bdf6ec9b1 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@nextcloud/initial-state": "^3.0.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/logger": "^3.0.3", - "@nextcloud/password-confirmation": "^6.0.3", + "@nextcloud/password-confirmation": "^6.1.0", "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0", "@nextcloud/sharing": "^0.4.0",