nextcloud-initial-state
Reads server-injected initial state data into Nextcloud app frontends with typed fallbacks.
Repository Health
Technical Analysis
@nextcloud/initial-state is the client-side counterpart of Nextcloud’s server-side initial state API. Nextcloud apps written in PHP can embed data directly into the HTML response as base64-encoded JSON inside hidden input elements, letting the frontend bootstrap with real data on first paint instead of firing an extra AJAX request. This library provides the single loadState() function that locates those hidden inputs, decodes and parses the payload, and hands it back to the calling JavaScript or TypeScript code.
Beyond the basic lookup, it adds a small but useful set of guarantees: results are cached in a shared window._nc_initial_state map so repeated calls for the same key never re-parse the DOM, a generic type parameter lets callers annotate the expected shape of the returned value, and an optional fallback argument controls whether a missing or malformed key throws an Error or silently resolves to a default. It ships as a tiny, dependency-free TypeScript package and is used across Nextcloud’s own first-party apps as well as third-party Nextcloud app development.
What You Get
- A single
loadState<T>(app, key, fallback?)function with no other public API surface to learn - Automatic base64/JSON decoding of the hidden
<input>elements Nextcloud’s server-side initial state API renders - In-memory caching via a shared
window._nc_initial_stateMap so repeat calls for the same key skip re-parsing - Generic typing so callers can annotate the expected return shape at the call site
- Configurable fallback semantics: throws a descriptive
Errorwhen a key is missing or unparsable unless a fallback value is supplied
Common Use Cases
- Bootstrapping a Nextcloud app’s Vue/React frontend with user preferences or config computed server-side on initial page load
- Passing feature flags or capability flags from PHP into the app’s JavaScript without an extra API call
- Seeding initial list/table data (e.g. files, contacts, calendar entries) rendered by the PHP controller straight into the frontend’s first render
- Providing typed defaults for optional per-app settings so the frontend can render sensibly even if the server never set a value
Under The Hood
Architecture
The package is a single exported function, loadState<T>(), with no internal module boundaries to speak of: it checks an in-memory window._nc_initial_state Map first, falls back to a document.querySelector lookup for an #initial-state-{app}-{key} hidden input, decodes the element’s base64-encoded JSON value, populates the cache, and returns the typed result (or a fallback / thrown Error on failure). This is appropriate for the package’s narrow scope, but it does mean discovery, caching, decoding, and error handling all live inline in one function rather than being separated into composable units — any change to the DOM selector convention or the server-side encoding format has to be coordinated with the PHP-side initial state API this library is the counterpart to.
Tech Stack
Written in TypeScript and compiled with tsc per tsconfig.json, with zero runtime dependencies — it relies only on browser-native atob and JSON.parse. The dev toolchain uses Vitest with a jsdom environment for DOM-dependent tests, @nextcloud/eslint-config for linting, and TypeDoc for generating API documentation into dist/doc. Node engine constraints target current LTS runtimes (^20 || ^22 || ^24), and the package publishes only its compiled dist/ output plus the changelog.
Code Quality
A single test file (test/index.test.ts) exercises the one exported function fairly thoroughly: it covers the missing-key throw path, the fallback-default path, correct-value retrieval, cache-hit behavior (asserting JSON.parse is called only once across ten repeated lookups), and both the throw and fallback branches when the underlying JSON is malformed. Error handling is explicit, using typed Error objects with a cause chain rather than swallowing failures. Linting is enforced via a shared Nextcloud ESLint config, and the repository’s README badges indicate a CI workflow plus Codecov coverage reporting.
API Design
The entire public API is one generic function call, loadState<T>(app, key, fallback?), so there is essentially no ramp-up cost or boilerplate for a caller who already knows their app ID and state key. The design deliberately narrows itself to one specific convention — base64-encoded JSON in a hidden input matching Nextcloud’s server-side initial state contract — rather than trying to be a general-purpose data-fetching utility, which keeps the surface area small but ties its usefulness tightly to Nextcloud app development specifically.