nextcloud-sharing
Typed share models, public-share helpers, and a reactive Share API with dialog UI for building Nextcloud file-sharing features.
Repository Health
Technical Analysis
@nextcloud/sharing packages the front-end building blocks Nextcloud and its apps use to implement file sharing: typed models for shares and share types, helpers for detecting and reading public-share context, and UI bindings for the Files app sidebar. It ships as four independent entry points — a general utilities module, a /public module for public-share pages, a /ui module for registering sidebar actions and sections, and an experimental /dialog module — so consumers only pull in the surface area they need.
The /dialog entry point is the most substantial piece: it exposes a reactive Share class (created via createShare() or fetched via getShare()) that wraps Nextcloud’s unified sharing OCS API, plus a ready-made SharingDialog Vue component and composables (useLinkShare, recipient search, permission presets) for building custom sharing UIs. Every mutation on a Share — adding a source or recipient, toggling a permission, applying a preset — round-trips to the server and updates the instance in place, keeping any bound Vue component in sync without extra plumbing.
What You Get
- Typed
IShare/ILinkShare/IRemoteShareinterfaces and theShareTypeenum matching Nextcloud’s share types isPublicShare()andgetSharingToken()helpers for detecting and reading public-share context on public pages- Sidebar action/section registration helpers for the Files app’s sharing UI (
/uientry point) - A reactive
Shareclass withcreateShare()/getShare()factories wrapping the unified sharing OCS API (/dialogentry point) - A ready-to-use
SharingDialogVue component plus composables for link shares, recipient search, and permission presets
Common Use Cases
- Reading whether the current page is a public share and retrieving its token before rendering public-share UI
- Registering a custom sidebar action or section in the Files app’s sharing panel from a Nextcloud app
- Opening a prebuilt sharing dialog for a file/folder node with
openSharingDialog(node) - Building a custom sharing UI by driving a
Shareinstance directly — adding sources/recipients, applying permission presets, and reacting to server-synced state
Under The Hood
Architecture
The package is organized around four independent entry points (index.ts, public.ts, ui/index.ts, dialog/index.ts) each re-exporting from focused submodules — a clean layered separation between pure type definitions (share/Share.ts, share/ShareType.ts), a thin OCS HTTP client (dialog/api/sharing.ts) that wraps axios calls behind typed functions and a single envelope-unwrapping helper, and a reactive domain object (the Share class) built on a private shallowRef with a single internal sync method as the sole mutation path — every method on Share delegates to the client, then replaces the ref wholesale, so the server is always the single source of truth and Vue components re-render for free. UI concerns are pushed further out still, into the SharingDialog component and composables like useLinkShare that depend only on Share’s public getters, never on the HTTP layer directly. This is a clean three-tier design (transport, domain model, UI); if the sync-on-every-mutation contract changed, every composable and the dialog component would need to change in lockstep, since they all assume synchronous consistency with the backend after each mutation.
Tech Stack TypeScript in strict mode, built with Vite through a shared Nextcloud Vite config, targeting Vue 3 as a peer dependency and using the Nextcloud Vue component library for dialog primitives. HTTP goes through a shared Nextcloud Axios wrapper; API URL construction uses a shared router helper for the OCS-envelope endpoints. Other first-party Nextcloud packages handle cross-cutting concerns — capability detection, toast dialogs, server-injected initial state, translations, and structured logging. Testing runs on Vitest with a DOM shim and coverage reporting, plus a dedicated component-testing setup for browser-rendered Vue components. Type documentation is generated automatically. The package ships as ESM only, with a separate declaration file and bundle per entry point declared through the package’s exports map.
Code Quality
An extensive set of colocated spec files (using Vitest and Vue Test Utils, plus dedicated component tests for browser-rendered Vue components) gives real coverage of the composables, utilities, and dialog components, not just trivial smoke tests. Error handling is explicit: async functions run inside try/catch blocks that route failures through a shared error-message helper and a dedicated logger module rather than swallowing them, and composables surface loading/error state to callers instead of throwing into the void. TypeScript runs in strict mode with a dedicated type-checking script, private class fields enforce real encapsulation on the Share class, and linting is configured through a shared Nextcloud ESLint config and gated independently in CI alongside separate type-check and test workflows.
What Makes It Unique
The public API purposefully hides its constructor — Share is exported as a type only and can only be obtained via createShare()/getShare(), which prevents consumers from constructing invalid mid-state objects and keeps the reactive wiring internal. Every mutating method returns the instance after resyncing from the server response, enabling a fluent, chainable style while guaranteeing the caller’s reference is never stale. Convenience layers stack cleanly on top: activating a share is sugar over a generic state-transition method, opening the dialog lazily loads the dialog component and its host library only when actually invoked (keeping the UI out of the API-only bundle), and an availability check lets consumers feature-detect the unified sharing API before touching it at all. This is a well-considered developer experience for a domain — multi-recipient, permission-preset, source-attached sharing — that is inherently more complex than a typical CRUD resource.