diff --git a/README.md b/README.md
index ef8d3b1..52c49c3 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,8 @@ npm i -S @nextcloud/sharing
## Usage
-There are two entry points provided:
+There are three entry points provided:
- The main entry point `@nextcloud/sharing` provides general utils for file sharing
- The _public_ entry point `@nextcloud/sharing/public` provides utils for handling public file shares
+- The _ui_ entry point `@nextcloud/sharing/ui` provides API bindings to interact with the files sharing interface in the files app.
diff --git a/REUSE.toml b/REUSE.toml
index f374a26..b3e6a8f 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -6,7 +6,7 @@ SPDX-PackageSupplier = "Nextcloud GmbH "
SPDX-PackageDownloadLocation = "https://github.com/nextcloud-libraries/nextcloud-sharing"
[[annotations]]
-path = ["package.json", "package-lock.json", "tsconfig.json"]
+path = ["package.json", "package-lock.json", "**/tsconfig.json"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2021 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "GPL-3.0-or-later"
diff --git a/lib/index.ts b/lib/index.ts
index 930a2b9..c9f35ca 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -3,46 +3,5 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-/** @deprecated will be removed with the next version use `ShareType` instead */
-export enum Type {
- SHARE_TYPE_USER = 0,
- SHARE_TYPE_GROUP = 1,
- SHARE_TYPE_LINK = 3,
- SHARE_TYPE_EMAIL = 4,
- SHARE_TYPE_REMOTE = 6,
- SHARE_TYPE_CIRCLE = 7,
- SHARE_TYPE_GUEST = 8,
- SHARE_TYPE_REMOTE_GROUP = 9,
- SHARE_TYPE_ROOM = 10,
- SHARE_TYPE_DECK = 12,
- /**
- * @since 26.0.0
- */
- SHARE_TYPE_FEDERATED_GROUP = 14,
-}
-
-export enum ShareType {
- User = 0,
- Group = 1,
- Link = 3,
- Email = 4,
- Remote = 6,
- /**
- * Was called `Circle` before Nextcloud 29
- */
- Team = 7,
- Guest = 8,
- RemoteGroup = 9,
- Room = 10,
- Deck = 12,
- /**
- * @since 26.0.0
- */
- FederatedGroup = 14,
- /**
- * Third party share types
- *
- * @since 25.0.0
- */
- ScienceMesh = 15,
-}
+export type * from './share/index.ts'
+export { ShareType } from './share/index.ts'
diff --git a/lib/share/Share.ts b/lib/share/Share.ts
new file mode 100644
index 0000000..67b6ab1
--- /dev/null
+++ b/lib/share/Share.ts
@@ -0,0 +1,158 @@
+/*!
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import type { ShareType } from './ShareType.ts'
+
+export type ShareAttribute = {
+ value: boolean
+ key: string
+ scope: string
+}
+
+export interface IGenericShare {
+ /**
+ * The share id
+ */
+ id: number
+
+ /**
+ * The share type
+ */
+ type: ShareType
+
+ /**
+ * The generic share attributes
+ */
+ attributes: ShareAttribute[]
+
+ /**
+ * The share creation timestamp (in seconds since UNIX epoch)
+ */
+ createdTime: number
+
+ /**
+ * The share permissions for the share receiver.
+ *
+ * A bitmask of the share permissions like `SharePermission.Read | SharePermission.Write`.
+ * These are not the permissions for the current user but for the share recipient (shareWith).
+ */
+ permissions: number
+
+ /**
+ * Whether the current user can edit this share.
+ * Only relevant for existing shares.
+ */
+ readonly canEdit: boolean
+
+ /**
+ * Whether the current user can delete this share.
+ * Only relevant for existing shares.
+ */
+ readonly canDelete: boolean
+
+ /**
+ * The uid of the share owner
+ */
+ owner: string
+
+ /**
+ * The displayname of the share owner
+ */
+ ownerDisplayname: string
+
+ /**
+ * Get the share with entity id
+ */
+ shareWith: string
+
+ /**
+ * The displayname of the entity this was shared with
+ */
+ shareWithDisplayname: string
+
+ /**
+ * In case of multiple shares with the same entity this is the unique displayname.
+ */
+ shareWithDisplaynameUnique: string
+
+ /**
+ * The uid of the owner of the shared file or folder.
+ */
+ fileOwner: string
+
+ /**
+ * The displayname of the owner of the shared file or folder.
+ */
+ fileOwnerDisplayname: string
+
+ /**
+ * Hide the download functionalities for the shared nodes.
+ * This obfuscates the download buttons for such shares.
+ */
+ hideDownload: boolean
+
+ /**
+ * Have a mail been sent to the share recipient
+ */
+ mailSend: boolean
+
+ /**
+ * The share note
+ */
+ note?: string
+
+ /**
+ * The share label
+ */
+ label?: string
+
+ /**
+ * The share expiration date in "YYYY-MM-DD HH:mm" format
+ */
+ expireDate?: `${number}-${number}-${number} ${number}:${number}`
+}
+
+export interface ILinkShare extends IGenericShare {
+ /**
+ * @inheritdoc
+ */
+ type: ShareType.Link | ShareType.Email
+
+ /**
+ * The share token
+ */
+ token: string
+
+ /**
+ * The share password
+ */
+ password: string
+
+ /**
+ * Password expiration time as "YYYY-MM-DD HH:mm" format
+ */
+ passwordExpirationTime: `${number}-${number}-${number} ${number}:${number}`
+
+ /**
+ * Password should be sent to recipient using Nextcloud Talk
+ */
+ sendPasswordByTalk: boolean
+}
+
+export interface IRemoteShare extends IGenericShare {
+ /**
+ * @inheritdoc
+ */
+ type: ShareType.Remote | ShareType.RemoteGroup
+
+ /**
+ * Is the share from a trusted remote server
+ */
+ isTrustedServer: boolean
+}
+
+export type IInternalShare = IGenericShare
+
+export type IShare = ILinkShare | IInternalShare | IRemoteShare
diff --git a/lib/share/ShareType.ts b/lib/share/ShareType.ts
new file mode 100644
index 0000000..c67096a
--- /dev/null
+++ b/lib/share/ShareType.ts
@@ -0,0 +1,30 @@
+/*!
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+export enum ShareType {
+ User = 0,
+ Group = 1,
+ Link = 3,
+ Email = 4,
+ Remote = 6,
+ /**
+ * Was called `Circle` before Nextcloud 29
+ */
+ Team = 7,
+ Guest = 8,
+ RemoteGroup = 9,
+ Room = 10,
+ Deck = 12,
+ /**
+ * @since 26.0.0
+ */
+ FederatedGroup = 14,
+ /**
+ * Third party share types
+ *
+ * @since 25.0.0
+ */
+ ScienceMesh = 15,
+}
diff --git a/lib/share/index.ts b/lib/share/index.ts
new file mode 100644
index 0000000..ae60ae1
--- /dev/null
+++ b/lib/share/index.ts
@@ -0,0 +1,8 @@
+/*!
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+export type * from './Share.ts'
+
+export { ShareType } from './ShareType.ts'
diff --git a/lib/ui/index.ts b/lib/ui/index.ts
new file mode 100644
index 0000000..0d361d6
--- /dev/null
+++ b/lib/ui/index.ts
@@ -0,0 +1,10 @@
+/*!
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+export type * from './sidebar-action.ts'
+export type * from './sidebar-section.ts'
+
+export * from './sidebar-action.ts'
+export * from './sidebar-section.ts'
diff --git a/lib/ui/sidebar-action.ts b/lib/ui/sidebar-action.ts
new file mode 100644
index 0000000..d718e37
--- /dev/null
+++ b/lib/ui/sidebar-action.ts
@@ -0,0 +1,158 @@
+/*!
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import type { INode } from '@nextcloud/files'
+import type { IShare } from '../index.ts'
+
+import isSvg from 'is-svg'
+
+export interface ISidebarAction {
+ /**
+ * Unique identifier for the action
+ */
+ id: string
+
+ /**
+ * The registered identifier of the custom web component to be used.
+ *
+ * The custom elements identifier must be prefixed with your apps namespace like `oca_myapp-sharing_action`.
+ * Also the component must implement following properties:
+ * - `node`: The shared node as `INode` from `@nextcloud/files`.
+ * - `share`: The share model if the share already exists as object of type `IShare` (potentially undefined).
+ * - `onSave`: A registration method to register a on-save callback which will be called when the share is saved `(callback: () => Promise) => void`
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Web_components
+ * @see https://vuejs.org/guide/extras/web-components#building-custom-elements-with-vue
+ */
+ element: string
+
+ /**
+ * Order of the sidebar actions.
+ * A higher value means the action will be displayed first.
+ */
+ order: number
+
+ /**
+ * Check if the action is enabled for a specific share type
+ *
+ * @param share - The share
+ * @param node - The node that share is about
+ */
+ enabled(share: IShare, node: INode): boolean
+}
+
+export interface ISidebarInlineAction {
+ /**
+ * Unique identifier for the action
+ */
+ id: string
+
+ /**
+ * Check if the action is enabled for a specific share type
+ *
+ * @param share - The share
+ * @param node - The node that share is about
+ */
+ enabled(share: IShare, node: INode): boolean
+
+ /**
+ * The callback handler when the user selected this action.
+ *
+ * @param share - The share
+ * @param node - The shared node
+ */
+ exec(share: IShare, node: INode): void | Promise
+
+ /**
+ * The inline svg icon to use.
+ */
+ iconSvg: string
+
+ /**
+ * The localized label of this action
+ *
+ * @param share - The current share (might not be created yet)
+ * @param node - The shared node
+ */
+ label(share: IShare, node: INode): string
+
+ /**
+ * Order of the sidebar actions.
+ * A higher value means the action will be displayed first.
+ */
+ order: number
+}
+
+/**
+ * Register a new sidebar action
+ *
+ * @param action - The action to register
+ */
+export function registerSidebarAction(action: ISidebarAction): void {
+ if (!action.id) {
+ throw new Error('Sidebar actions must have an id')
+ }
+ if (!action.element || !action.element.startsWith('oca_') || !window.customElements.get(action.element)) {
+ throw new Error('Sidebar actions must provide a registered custom web component identifier')
+ }
+ if (typeof action.order !== 'number') {
+ throw new Error('Sidebar actions must have the order property')
+ }
+ if (typeof action.enabled !== 'function') {
+ throw new Error('Sidebar actions must implement the "enabled" method')
+ }
+ window._nc_files_sharing_sidebar_actions ??= new Map()
+
+ if (window._nc_files_sharing_sidebar_actions.has(action.id)) {
+ throw new Error(`Sidebar action with id "${action.id}" is already registered`)
+ }
+ window._nc_files_sharing_sidebar_actions.set(action.id, action)
+}
+
+/**
+ * Register a new sidebar action
+ *
+ * @param action - The action to register
+ */
+export function registerSidebarInlineAction(action: ISidebarInlineAction): void {
+ if (!action.id) {
+ throw new Error('Sidebar actions must have an id')
+ }
+ if (typeof action.order !== 'number') {
+ throw new Error('Sidebar actions must have the "order" property')
+ }
+ if (typeof action.iconSvg !== 'string' || !isSvg(action.iconSvg)) {
+ throw new Error('Sidebar actions must have the "iconSvg" property')
+ }
+ if (typeof action.label !== 'function') {
+ throw new Error('Sidebar actions must implement the "label" method')
+ }
+ if (typeof action.exec !== 'function') {
+ throw new Error('Sidebar actions must implement the "exec" method')
+ }
+ if (typeof action.enabled !== 'function') {
+ throw new Error('Sidebar actions must implement the "enabled" method')
+ }
+ window._nc_files_sharing_sidebar_inline_actions ??= new Map()
+
+ if (window._nc_files_sharing_sidebar_inline_actions.has(action.id)) {
+ throw new Error(`Sidebar action with id "${action.id}" is already registered`)
+ }
+ window._nc_files_sharing_sidebar_inline_actions.set(action.id, action)
+}
+
+/**
+ * Get all registered sidebar actions
+ */
+export function getSidebarActions(): ISidebarAction[] {
+ return [...(window._nc_files_sharing_sidebar_actions?.values() ?? [])]
+}
+
+/**
+ * Get all registered sidebar inline actions
+ */
+export function getSidebarInlineActions(): ISidebarInlineAction[] {
+ return [...(window._nc_files_sharing_sidebar_inline_actions?.values() ?? [])]
+}
diff --git a/lib/ui/sidebar-section.ts b/lib/ui/sidebar-section.ts
new file mode 100644
index 0000000..b0599c3
--- /dev/null
+++ b/lib/ui/sidebar-section.ts
@@ -0,0 +1,70 @@
+/*!
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import type { INode } from '@nextcloud/files'
+
+export interface ISidebarSection {
+ /**
+ * Unique identifier for the section
+ */
+ id: string
+
+ /**
+ * The registered identifier of the custom web component to be used.
+ *
+ * The custom elements identifier must be prefixed with your apps namespace like `oca_myapp-sharing_section`.
+ * Also the component must at least have a `node` property which must accept the current active node as `INode` from `@nextcloud/files`.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Web_components
+ * @see https://vuejs.org/guide/extras/web-components#building-custom-elements-with-vue
+ */
+ element: string
+
+ /**
+ * Order of the sidebar sections.
+ * A higher value means the section will be displayed first.
+ */
+ order: number
+
+ /**
+ * Check if the section is enabled for the current active node
+ *
+ * @param node - The node to check
+ */
+ enabled(node: INode): boolean
+}
+
+/**
+ * Register a new sidebar section inside the files sharing sidebar tab.
+ *
+ * @param section - The section to register
+ */
+export function registerSidebarSection(section: ISidebarSection): void {
+ if (!section.id) {
+ throw new Error('Sidebar sections must have an id')
+ }
+ if (!section.element || !section.element.startsWith('oca_') || !window.customElements.get(section.element)) {
+ throw new Error('Sidebar sections must provide a registered custom web component identifier')
+ }
+ if (typeof section.order !== 'number') {
+ throw new Error('Sidebar sections must have the order property')
+ }
+ if (typeof section.enabled !== 'function') {
+ throw new Error('Sidebar sections must implement the enabled method')
+ }
+
+ window._nc_files_sharing_sidebar_sections ??= new Map()
+ if (window._nc_files_sharing_sidebar_sections.has(section.id)) {
+ throw new Error(`Sidebar section with id "${section.id}" is already registered`)
+ }
+ window._nc_files_sharing_sidebar_sections.set(section.id, section)
+}
+
+/**
+ * Get all registered sidebar sections for the files sharing sidebar tab.
+ */
+export function getSidebarSections(): ISidebarSection[] {
+ return [...(window._nc_files_sharing_sidebar_sections?.values() ?? [])]
+}
diff --git a/lib/window.d.ts b/lib/window.d.ts
new file mode 100644
index 0000000..36955a6
--- /dev/null
+++ b/lib/window.d.ts
@@ -0,0 +1,14 @@
+/*!
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import type { ISidebarAction, ISidebarInlineAction, ISidebarSection } from './ui/index.ts'
+
+declare global {
+ interface Window {
+ _nc_files_sharing_sidebar_actions?: Map
+ _nc_files_sharing_sidebar_inline_actions?: Map
+ _nc_files_sharing_sidebar_sections?: Map
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 5bcf898..5cfc277 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,11 +9,12 @@
"version": "0.2.5",
"license": "GPL-3.0-or-later",
"dependencies": {
- "@nextcloud/initial-state": "^3.0.0"
+ "@nextcloud/initial-state": "^3.0.0",
+ "is-svg": "^6.1.0"
},
"devDependencies": {
- "@nextcloud/browserslist-config": "^3.0.1",
"@nextcloud/eslint-config": "^9.0.0-rc.5",
+ "@nextcloud/files": "^3.12.0",
"@types/node": "^24.3.0",
"@vitest/coverage-v8": "^3.2.4",
"eslint": "^9.29.0",
@@ -24,6 +25,9 @@
},
"engines": {
"node": "^20.0.0 || ^22.0.0 || ^24.0.0"
+ },
+ "optionalDependencies": {
+ "@nextcloud/files": "^3.12.0"
}
},
"node_modules/@ampproject/remapping": {
@@ -100,6 +104,16 @@
"node": ">=18"
}
},
+ "node_modules/@buttercup/fetch": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@buttercup/fetch/-/fetch-0.2.1.tgz",
+ "integrity": "sha512-sCgECOx8wiqY8NN1xN22BqqKzXYIG2AicNLlakOAI4f0WgyLVUbAigMf8CZhBtJxdudTcB1gD5lciqi44jwJvg==",
+ "dev": true,
+ "license": "MIT",
+ "optionalDependencies": {
+ "node-fetch": "^3.3.0"
+ }
+ },
"node_modules/@es-joy/jsdoccomment": {
"version": "0.52.0",
"resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.52.0.tgz",
@@ -778,6 +792,16 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@file-type/xml": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/@file-type/xml/-/xml-0.4.4.tgz",
+ "integrity": "sha512-NhCyXoHlVZ8TqM476hyzwGJ24+D5IPSaZhmrPj7qXnEVb3q6jrFzA3mM9TBpknKSI9EuQeGTKRg2DXGUwvBBoQ==",
+ "license": "MIT",
+ "dependencies": {
+ "sax": "^1.4.1",
+ "strtok3": "^10.3.4"
+ }
+ },
"node_modules/@gerrit0/mini-shiki": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.12.0.tgz",
@@ -949,10 +973,52 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "node_modules/@nextcloud/browserslist-config": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@nextcloud/browserslist-config/-/browserslist-config-3.0.1.tgz",
- "integrity": "sha512-GZTxL5fsDgmFoot/qnRurjHCuHjSfOg+A6t4+P2TySXua2Q1Ex0lecZYlSnRuOR/W5BGOZ06ITTA/hbkSh1Ypg==",
+ "node_modules/@nextcloud/auth": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-2.5.2.tgz",
+ "integrity": "sha512-1dr+Xhvg2QtsFC23KFXJSkU524EVgI/+WFBGTZ8tFa+9hmcZ3CqZIHjtXm3KxUvezwAY5023Ml0n2vpdYkpBXQ==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/browser-storage": "^0.4.0",
+ "@nextcloud/event-bus": "^3.3.2"
+ },
+ "engines": {
+ "node": "^20.0.0 || ^22.0.0 || ^24.0.0"
+ }
+ },
+ "node_modules/@nextcloud/browser-storage": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.4.0.tgz",
+ "integrity": "sha512-D6XxznxCYmJ3oBCC3p0JB6GZJ2RZ9dgbB1UqtTePXrIvHUMBAeF/YkiGKYxLAVZCZb+NSNZXgAYHm/3LnIUbDg==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "core-js": "3.37.0"
+ },
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
+ "node_modules/@nextcloud/capabilities": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@nextcloud/capabilities/-/capabilities-1.2.0.tgz",
+ "integrity": "sha512-L1NQtOfHWzkfj0Ple1MEJt6HmOHWAi3y4qs+OnwSWexqJT0DtXTVPyRxi7ADyITwRxS5H9R/HMl6USAj4Nr1nQ==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/initial-state": "^2.1.0"
+ },
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
+ "node_modules/@nextcloud/capabilities/node_modules/@nextcloud/initial-state": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-2.2.0.tgz",
+ "integrity": "sha512-cDW98L5KGGgpS8pzd+05304/p80cyu8U2xSDQGa+kGPTpUFmCbv2qnO5WrwwGTauyjYijCal2bmw82VddSH+Pg==",
"dev": true,
"license": "GPL-3.0-or-later",
"engines": {
@@ -987,6 +1053,44 @@
"eslint": ">=9"
}
},
+ "node_modules/@nextcloud/event-bus": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-3.3.2.tgz",
+ "integrity": "sha512-1Qfs6i7Tz2qd1A33NpBQOt810ydHIRjhyXMFwSEkYX2yUI80lAk/sWO8HIB2Fqp+iffhyviPPcQYoytMDRyDNw==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@types/semver": "^7.5.8",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
+ "node_modules/@nextcloud/files": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.0.tgz",
+ "integrity": "sha512-LVZklgooZzBj2jkbPRZO4jnnvW5+RvOn7wN5weyOZltF6i2wVMbg1Y/Czl2pi/UNMjUm5ENqc0j7FgxMBo8bwA==",
+ "dev": true,
+ "license": "AGPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/auth": "^2.5.1",
+ "@nextcloud/capabilities": "^1.2.0",
+ "@nextcloud/l10n": "^3.3.0",
+ "@nextcloud/logger": "^3.0.2",
+ "@nextcloud/paths": "^2.2.1",
+ "@nextcloud/router": "^3.0.1",
+ "@nextcloud/sharing": "^0.2.4",
+ "cancelable-promise": "^4.3.1",
+ "is-svg": "^6.0.0",
+ "typescript-event-target": "^1.1.1",
+ "webdav": "^5.8.0"
+ },
+ "engines": {
+ "node": "^20.0.0 || ^22.0.0 || ^24.0.0"
+ }
+ },
"node_modules/@nextcloud/initial-state": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz",
@@ -996,6 +1100,100 @@
"node": "^20.0.0 || ^22.0.0 || ^24.0.0"
}
},
+ "node_modules/@nextcloud/l10n": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.0.tgz",
+ "integrity": "sha512-K4UBSl0Ou6sXXLxyjuhktRf2FyTCjyvHxJyBLmS2z3YEYcRkpf8ib3XneRwEQIEpzBPQjul2/ZdFlt7umd8Gaw==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/router": "^3.0.1",
+ "@nextcloud/typings": "^1.9.1",
+ "@types/escape-html": "^1.0.4",
+ "dompurify": "^3.2.6",
+ "escape-html": "^1.0.3"
+ },
+ "engines": {
+ "node": "^20 || ^22 || ^24"
+ }
+ },
+ "node_modules/@nextcloud/logger": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@nextcloud/logger/-/logger-3.0.2.tgz",
+ "integrity": "sha512-wByt0R0/6QC44RBpaJr1MWghjjOxk/pRbACHo/ZWWKht1qYbJRHB4GtEi+35KEIHY07ZpqxiDk6dIRuN7sXYWQ==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/auth": "^2.3.0"
+ },
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
+ "node_modules/@nextcloud/paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-2.2.1.tgz",
+ "integrity": "sha512-M3ShLjrxR7B48eKThLMoqbxTqTKyQXcwf9TgeXQGbCIhiHoXU6as5j8l5qNv/uZlANokVdowpuWHBi3b2+YNNA==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
+ "node_modules/@nextcloud/router": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.0.1.tgz",
+ "integrity": "sha512-Ci/uD3x8OKHdxSqXL6gRJ+mGJOEXjeiHjj7hqsZqVTsT7kOrCjDf0/J8z5RyLlokKZ0IpSe+hGxgi3YB7Gpw3Q==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/typings": "^1.7.0"
+ },
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
+ "node_modules/@nextcloud/sharing": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.2.5.tgz",
+ "integrity": "sha512-B3K5Dq9b5dexDA5n3AAuCF69Huwhrpw0J72fsVXV4KpPdImjhVPlExAv5o70AoXa+OqN4Rwn6gqJw+3ED892zg==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/initial-state": "^2.2.0"
+ },
+ "engines": {
+ "node": "^20.0.0 || ^22.0.0 || ^24.0.0"
+ }
+ },
+ "node_modules/@nextcloud/sharing/node_modules/@nextcloud/initial-state": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-2.2.0.tgz",
+ "integrity": "sha512-cDW98L5KGGgpS8pzd+05304/p80cyu8U2xSDQGa+kGPTpUFmCbv2qnO5WrwwGTauyjYijCal2bmw82VddSH+Pg==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
+ "node_modules/@nextcloud/typings": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-1.9.1.tgz",
+ "integrity": "sha512-i0l/L5gKW8EACbXHVxXM6wn3sUhY2qmnL2OijppzU4dENC7/hqySMQDer7/+cJbNSNG7uHF/Z+9JmHtDfRfuGg==",
+ "dev": true,
+ "license": "GPL-3.0-or-later",
+ "dependencies": {
+ "@types/jquery": "3.5.16"
+ },
+ "engines": {
+ "node": "^20.0.0",
+ "npm": "^10.0.0"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1719,6 +1917,12 @@
"eslint": ">=9.0.0"
}
},
+ "node_modules/@tokenizer/token": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
+ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
+ "license": "MIT"
+ },
"node_modules/@types/chai": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
@@ -1736,6 +1940,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/escape-html": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz",
+ "integrity": "sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -1753,6 +1964,16 @@
"@types/unist": "*"
}
},
+ "node_modules/@types/jquery": {
+ "version": "3.5.16",
+ "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz",
+ "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/sizzle": "*"
+ }
+ },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -1770,6 +1991,28 @@
"undici-types": "~7.10.0"
}
},
+ "node_modules/@types/semver": {
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz",
+ "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/sizzle": {
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz",
+ "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/@types/unist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
@@ -2300,6 +2543,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/base-64": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
+ "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -2330,6 +2580,13 @@
"node": ">=8"
}
},
+ "node_modules/byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/byte-length/-/byte-length-1.0.2.tgz",
+ "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/cac": {
"version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
@@ -2350,6 +2607,13 @@
"node": ">=6"
}
},
+ "node_modules/cancelable-promise": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/cancelable-promise/-/cancelable-promise-4.3.1.tgz",
+ "integrity": "sha512-A/8PwLk/T7IJDfUdQ68NR24QHa8rIlnN/stiJEBo6dmVUkD4K14LswG0w3VwdeK/o7qOwRUR1k2MhK5Rpy2m7A==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/chai": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
@@ -2384,6 +2648,16 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/check-error": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
@@ -2449,6 +2723,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/core-js": {
+ "version": "3.37.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.0.tgz",
+ "integrity": "sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2464,6 +2750,16 @@
"node": ">= 8"
}
},
+ "node_modules/crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -2477,6 +2773,16 @@
"node": ">=4"
}
},
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/debug": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
@@ -2550,6 +2856,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/dompurify": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz",
+ "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==",
+ "dev": true,
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -2625,6 +2941,13 @@
"@esbuild/win32-x64": "0.25.5"
}
},
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -3038,6 +3361,30 @@
}
}
},
+ "node_modules/fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3119,6 +3466,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -3240,6 +3600,13 @@
"node": ">=8"
}
},
+ "node_modules/hot-patcher": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/hot-patcher/-/hot-patcher-2.0.1.tgz",
+ "integrity": "sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -3293,6 +3660,13 @@
"node": ">=0.8.19"
}
},
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -3349,6 +3723,21 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-svg": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-6.1.0.tgz",
+ "integrity": "sha512-i7YPdvYuSCYcaLQrKwt8cvKTlwHcdA6Hp8N9SO3Q5jIzo8x6kH3N47W0BvPP7NdxVBmIHx7X9DK36czYYW7lHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@file-type/xml": "^0.4.3"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3487,6 +3876,13 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/layerr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/layerr/-/layerr-3.0.0.tgz",
+ "integrity": "sha512-tv754Ki2dXpPVApOrjTyRo4/QegVb9eVFq4mjqp4+NM5NaX7syQvN5BBNfV/ZpAHCEHV24XdUVrBAoka4jt3pA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -3611,6 +4007,18 @@
"markdown-it": "bin/markdown-it.mjs"
}
},
+ "node_modules/md5": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
+ "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2",
+ "is-buffer": "~1.1.6"
+ }
+ },
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
@@ -3724,6 +4132,13 @@
"node": ">=18"
}
},
+ "node_modules/nested-property": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/nested-property/-/nested-property-4.0.0.tgz",
+ "integrity": "sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
@@ -3733,6 +4148,46 @@
"optional": true,
"peer": true
},
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "deprecated": "Use your platform's native DOMException instead",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
+ "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@@ -3853,6 +4308,13 @@
"node": ">=8"
}
},
+ "node_modules/path-posix": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz",
+ "integrity": "sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/path-scurry": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
@@ -3980,6 +4442,13 @@
"node": ">=6"
}
},
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -4017,6 +4486,13 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -4132,6 +4608,12 @@
"@parcel/watcher": "^2.4.1"
}
},
+ "node_modules/sax": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+ "license": "ISC"
+ },
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
@@ -4409,6 +4891,22 @@
],
"license": "MIT"
},
+ "node_modules/strtok3": {
+ "version": "10.3.4",
+ "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz",
+ "integrity": "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==",
+ "license": "MIT",
+ "dependencies": {
+ "@tokenizer/token": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -4599,6 +5097,13 @@
"typescript": ">=4.8.4 <6.0.0"
}
},
+ "node_modules/typescript-event-target": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/typescript-event-target/-/typescript-event-target-1.1.1.tgz",
+ "integrity": "sha512-dFSOFBKV6uwaloBCCUhxlD3Pr/P1a/tJdcmPrTXCHlEFD3faj0mztjcGn6VBAhQ0/Bdy8K3VWrrqwbt/ffsYsg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
@@ -4623,6 +5128,27 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/url-join": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz",
+ "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -4826,6 +5352,87 @@
"eslint": "^8.57.0 || ^9.0.0"
}
},
+ "node_modules/web-streams-polyfill": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
+ "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/webdav": {
+ "version": "5.8.0",
+ "resolved": "https://registry.npmjs.org/webdav/-/webdav-5.8.0.tgz",
+ "integrity": "sha512-iuFG7NamJ41Oshg4930iQgfIpRrUiatPWIekeznYgEf2EOraTRcDPTjy7gIOMtkdpKTaqPk1E68NO5PAGtJahA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@buttercup/fetch": "^0.2.1",
+ "base-64": "^1.0.0",
+ "byte-length": "^1.0.2",
+ "entities": "^6.0.0",
+ "fast-xml-parser": "^4.5.1",
+ "hot-patcher": "^2.0.1",
+ "layerr": "^3.0.0",
+ "md5": "^2.3.0",
+ "minimatch": "^9.0.5",
+ "nested-property": "^4.0.0",
+ "node-fetch": "^3.3.2",
+ "path-posix": "^1.0.0",
+ "url-join": "^5.0.0",
+ "url-parse": "^1.5.10"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/webdav/node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/webdav/node_modules/fast-xml-parser": {
+ "version": "4.5.3",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz",
+ "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "strnum": "^1.1.1"
+ },
+ "bin": {
+ "fxparser": "src/cli/cli.js"
+ }
+ },
+ "node_modules/webdav/node_modules/strnum": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz",
+ "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/whatwg-mimetype": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
diff --git a/package.json b/package.json
index 2255a18..897166e 100644
--- a/package.json
+++ b/package.json
@@ -11,11 +11,15 @@
"exports": {
".": {
"types": "./dist/index.d.ts",
- "import": "./dist/index.js"
+ "default": "./dist/index.js"
},
"./public": {
"types": "./dist/public.d.ts",
- "import": "./dist/public.js"
+ "default": "./dist/public.js"
+ },
+ "./ui": {
+ "types": "./dist/ui/index.d.ts",
+ "default": "./dist/ui/index.js"
}
},
"main": "dist/index.js",
@@ -29,7 +33,7 @@
"scripts": {
"build": "npm run build:cleanup && npm run build:source",
"build:cleanup": "tsc --build --clean",
- "build:doc": "typedoc --out dist/doc lib/index.ts lib/publicShare.ts && touch dist/doc/.nojekyll",
+ "build:doc": "typedoc --out dist/doc lib/index.ts lib/publicShare.ts lib/ui/index.ts && touch dist/doc/.nojekyll",
"build:source": "tsc",
"dev": "vite --mode development build",
"lint": "eslint",
@@ -40,15 +44,13 @@
"ts:check": "tsc --noEmit",
"watch": "vite --mode development build --watch"
},
- "browserslist": [
- "extends @nextcloud/browserslist-config"
- ],
"dependencies": {
- "@nextcloud/initial-state": "^3.0.0"
+ "@nextcloud/initial-state": "^3.0.0",
+ "is-svg": "^6.1.0"
},
"devDependencies": {
- "@nextcloud/browserslist-config": "^3.0.1",
"@nextcloud/eslint-config": "^9.0.0-rc.5",
+ "@nextcloud/files": "^3.12.0",
"@types/node": "^24.3.0",
"@vitest/coverage-v8": "^3.2.4",
"eslint": "^9.29.0",
@@ -57,6 +59,9 @@
"typescript": "^5.9.2",
"vitest": "^3.2.4"
},
+ "optionalDependencies": {
+ "@nextcloud/files": "^3.12.0"
+ },
"engines": {
"node": "^20.0.0 || ^22.0.0 || ^24.0.0"
},
diff --git a/lib/index.spec.ts b/tests/index.spec.ts
similarity index 92%
rename from lib/index.spec.ts
rename to tests/index.spec.ts
index 792128a..6266f22 100644
--- a/lib/index.spec.ts
+++ b/tests/index.spec.ts
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
import { expect, test } from 'vitest'
-import { ShareType } from '.'
+import { ShareType } from '../lib/index.ts'
test('ShareType', () => {
for (const type of Object.values(ShareType)) {
diff --git a/lib/publicShare.spec.ts b/tests/publicShare.spec.ts
similarity index 97%
rename from lib/publicShare.spec.ts
rename to tests/publicShare.spec.ts
index 75e6bfa..edd1573 100644
--- a/lib/publicShare.spec.ts
+++ b/tests/publicShare.spec.ts
@@ -60,7 +60,7 @@ describe('getSharingToken', () => {
})
const getSharingToken = async () => {
- const { getSharingToken: sharingToken } = await import('./public.ts')
+ const { getSharingToken: sharingToken } = await import('../lib/public.ts')
return sharingToken()
}
diff --git a/tests/tsconfig.json b/tests/tsconfig.json
new file mode 100644
index 0000000..60b965b
--- /dev/null
+++ b/tests/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../tsconfig.json",
+ "include": ["../lib/**/*.ts", "./**/*.ts"],
+ "exclude": [],
+ "compilerOptions": {
+ "rootDir": ".."
+ }
+}
diff --git a/tests/ui/sidebar-action.spec.ts b/tests/ui/sidebar-action.spec.ts
new file mode 100644
index 0000000..3a72566
--- /dev/null
+++ b/tests/ui/sidebar-action.spec.ts
@@ -0,0 +1,83 @@
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * @vitest-environment happy-dom
+ */
+
+import type { ISidebarAction } from '../../lib/ui/index.ts'
+
+import { beforeEach, describe, expect, test, vi } from 'vitest'
+import { getSidebarActions, registerSidebarAction } from '../../lib/ui/index.ts'
+
+describe('sidebar action', () => {
+ const elementsSpy = vi.spyOn(window.customElements, 'get')
+
+ beforeEach(() => {
+ vi.resetAllMocks()
+ elementsSpy.mockImplementation((id: string) => id.startsWith('oca_myapp') ? class extends HTMLElement {} : undefined)
+ delete window._nc_files_sharing_sidebar_actions
+ })
+
+ test('register action', async () => {
+ registerSidebarAction(createAction())
+ expect(window._nc_files_sharing_sidebar_actions).toHaveLength(1)
+ expect(elementsSpy).toHaveBeenCalledOnce()
+ })
+
+ test('register multiple actions', async () => {
+ registerSidebarAction(createAction())
+ registerSidebarAction({ ...createAction(), id: 'test-2' })
+ expect(window._nc_files_sharing_sidebar_actions).toHaveLength(2)
+ expect(elementsSpy).toHaveBeenCalledTimes(2)
+ })
+
+ test('get registered actions', async () => {
+ registerSidebarAction(createAction())
+ registerSidebarAction({ ...createAction(), id: 'test-2' })
+ expect(getSidebarActions()).toHaveLength(2)
+ expect(getSidebarActions().map(({ id }) => id)).toEqual(['test', 'test-2'])
+ })
+
+ test('register same action twice', async () => {
+ registerSidebarAction(createAction())
+ expect(() => registerSidebarAction(createAction())).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar action with id "test" is already registered]')
+ })
+
+ test('register action with missing id', async () => {
+ expect(() => registerSidebarAction({
+ ...createAction(),
+ id: '',
+ })).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar actions must have an id]')
+ })
+
+ test('register action with missing enabled', async () => {
+ const action = createAction()
+ // @ts-expect-error mocking for tests
+ delete action.enabled
+
+ expect(() => registerSidebarAction(action)).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar actions must implement the "enabled" method]')
+ })
+
+ test('register action with invalid element', async () => {
+ const action = createAction()
+ action.element = 'invalid-element'
+
+ expect(() => registerSidebarAction(action)).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar actions must provide a registered custom web component identifier]')
+ })
+
+ test('register action with unregistered element', async () => {
+ const action = createAction()
+ action.element = 'oca_non_existent_element'
+
+ expect(() => registerSidebarAction(action)).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar actions must provide a registered custom web component identifier]')
+ })
+})
+
+function createAction(): ISidebarAction {
+ return {
+ id: 'test',
+ order: 0,
+ element: 'oca_myapp-sharing_action',
+ enabled: vi.fn(),
+ }
+}
diff --git a/tests/ui/sidebar-inline-action.spec.ts b/tests/ui/sidebar-inline-action.spec.ts
new file mode 100644
index 0000000..6cf4332
--- /dev/null
+++ b/tests/ui/sidebar-inline-action.spec.ts
@@ -0,0 +1,78 @@
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * @vitest-environment happy-dom
+ */
+
+import type { ISidebarInlineAction } from '../../lib/ui/index.ts'
+
+import { beforeEach, describe, expect, test, vi } from 'vitest'
+import { getSidebarInlineActions, registerSidebarInlineAction } from '../../lib/ui/index.ts'
+
+describe('sidebar inline action', () => {
+ beforeEach(() => {
+ delete window._nc_files_sharing_sidebar_inline_actions
+ })
+
+ test('register action', async () => {
+ registerSidebarInlineAction(createAction())
+ expect(window._nc_files_sharing_sidebar_inline_actions).toHaveLength(1)
+ })
+
+ test('register multiple actions', async () => {
+ registerSidebarInlineAction(createAction())
+ registerSidebarInlineAction({ ...createAction(), id: 'test-2' })
+ expect(window._nc_files_sharing_sidebar_inline_actions).toHaveLength(2)
+ })
+
+ test('get registered actions', async () => {
+ registerSidebarInlineAction(createAction())
+ registerSidebarInlineAction({ ...createAction(), id: 'test-2' })
+ expect(getSidebarInlineActions()).toHaveLength(2)
+ expect(getSidebarInlineActions().map(({ id }) => id)).toEqual(['test', 'test-2'])
+ })
+
+ test('register same action twice', async () => {
+ registerSidebarInlineAction(createAction())
+ expect(() => registerSidebarInlineAction(createAction())).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar action with id "test" is already registered]')
+ })
+
+ test('register action with missing id', async () => {
+ expect(() => registerSidebarInlineAction({
+ ...createAction(),
+ id: '',
+ })).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar actions must have an id]')
+ })
+
+ test.for`
+ method
+ --
+ ${'enabled'}
+ ${'label'}
+ ${'exec'}
+ `('register action with missing $method', async ({ method }) => {
+ const action = createAction()
+ // @ts-expect-error mocking for tests
+ delete action[method]
+
+ expect(() => registerSidebarInlineAction(action)).toThrowError()
+ })
+
+ test('register action with invalid icon', async () => {
+ expect(() => registerSidebarInlineAction({
+ ...createAction(),
+ iconSvg: '',
+ })).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar actions must have the "iconSvg" property]')
+ })
+})
+
+function createAction(): ISidebarInlineAction {
+ return {
+ id: 'test',
+ order: 0,
+ iconSvg: '',
+ enabled: vi.fn(),
+ label: vi.fn(),
+ exec: vi.fn(),
+ }
+}
diff --git a/tests/ui/sidebar-section.spec.ts b/tests/ui/sidebar-section.spec.ts
new file mode 100644
index 0000000..ba90c58
--- /dev/null
+++ b/tests/ui/sidebar-section.spec.ts
@@ -0,0 +1,83 @@
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * @vitest-environment happy-dom
+ */
+
+import type { ISidebarSection } from '../../lib/ui/index.ts'
+
+import { beforeEach, describe, expect, test, vi } from 'vitest'
+import { getSidebarSections, registerSidebarSection } from '../../lib/ui/index.ts'
+
+describe('sidebar section', () => {
+ const elementsSpy = vi.spyOn(window.customElements, 'get')
+
+ beforeEach(() => {
+ vi.resetAllMocks()
+ elementsSpy.mockImplementation((id: string) => id.startsWith('oca_myapp') ? class extends HTMLElement {} : undefined)
+ delete window._nc_files_sharing_sidebar_sections
+ })
+
+ test('register section', async () => {
+ registerSidebarSection(createSection())
+ expect(window._nc_files_sharing_sidebar_sections).toHaveLength(1)
+ expect(elementsSpy).toHaveBeenCalledOnce()
+ })
+
+ test('register multiple sections', async () => {
+ registerSidebarSection(createSection())
+ registerSidebarSection({ ...createSection(), id: 'test-2' })
+ expect(window._nc_files_sharing_sidebar_sections).toHaveLength(2)
+ expect(elementsSpy).toHaveBeenCalledTimes(2)
+ })
+
+ test('get registered sections', async () => {
+ registerSidebarSection(createSection())
+ registerSidebarSection({ ...createSection(), id: 'test-2' })
+ expect(getSidebarSections()).toHaveLength(2)
+ expect(getSidebarSections().map(({ id }) => id)).toEqual(['test', 'test-2'])
+ })
+
+ test('register same section twice', async () => {
+ registerSidebarSection(createSection())
+ expect(() => registerSidebarSection(createSection())).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar section with id "test" is already registered]')
+ })
+
+ test('register section with missing id', async () => {
+ expect(() => registerSidebarSection({
+ ...createSection(),
+ id: '',
+ })).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar sections must have an id]')
+ })
+
+ test('register section with missing enabled', async () => {
+ const section = createSection()
+ // @ts-expect-error mocking for tests
+ delete section.enabled
+
+ expect(() => registerSidebarSection(section)).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar sections must implement the enabled method]')
+ })
+
+ test('register section with invalid element', async () => {
+ const section = createSection()
+ section.element = 'invalid-element'
+
+ expect(() => registerSidebarSection(section)).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar sections must provide a registered custom web component identifier]')
+ })
+
+ test('register section with unregistered element', async () => {
+ const section = createSection()
+ section.element = 'oca_non_existent_element'
+
+ expect(() => registerSidebarSection(section)).toThrowErrorMatchingInlineSnapshot('[Error: Sidebar sections must provide a registered custom web component identifier]')
+ })
+})
+
+function createSection(): ISidebarSection {
+ return {
+ id: 'test',
+ order: 0,
+ element: 'oca_myapp-sharing_section',
+ enabled: vi.fn(),
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
index 6f69eff..deb0819 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,9 +3,9 @@
"exclude": ["lib/**/*.spec.ts"],
"compilerOptions": {
"rootDir": "lib",
- "target": "ESNext",
- "module": "nodenext",
- "moduleResolution": "nodenext",
+ "target": "esnext",
+ "module": "esnext",
+ "moduleResolution": "bundler",
"declaration": true,
"outDir": "./dist",
"strict": true,