Vault stores files for your app — documents, images, reports — on the NubleStation host, scoped to your app. Files live in collections, which are just strings in the path (think folders, no setup required). Every file is private by default; you opt individual files into public access or share them per user.
Get up and running
-
Get an API key. In the Console, open your app and copy its API key (
nbl_<key_id>.<secret>). -
Install the SDK.
npm install @nublestation/vault # or pnpm add @nublestation/vault -
Create a client and move some files.
import { createVaultClient } from "@nublestation/vault"; const vault = createVaultClient({ url: "http://api.clinic.local", // your Gateway apiKey: "nbl_<key_id>.<secret>", // from the Console }); // Upload (Blob, Uint8Array, or ArrayBuffer) const uploaded = await vault.upload("reports", "q1.pdf", file); // List a collection const files = await vault.list("reports"); // Download as ArrayBuffer const bytes = await vault.download("reports", "q1.pdf");
That’s it. Every call is scoped to the app that issued the API key — one app can never touch another app’s files.
Everyday usage
Upload
upload never overwrites. If a file already exists at that path you get a 409 — delete and re-upload:
import { VaultError } from "@nublestation/vault";
try {
await vault.upload("reports", "q1.pdf", file);
} catch (err) {
if (err instanceof VaultError && err.status === 409) {
await vault.delete("reports", "q1.pdf");
await vault.upload("reports", "q1.pdf", file);
} else {
throw err;
}
}
List
const all = await vault.list(); // everything you can access
const reports = await vault.list("reports"); // one collection
// Scoped views — these need Identity wired in (signed-in user):
const mine = await vault.listMine(); // files you own
const shared = await vault.listSharedWithMe(); // shared with you (with your role)
const open = await vault.listPublic(); // the public space
listMine / listSharedWithMe / listPublic rely on the session cookie from Identity. Without it, listMine returns [].
Download
const bytes = await vault.download("reports", "q1.pdf"); // ArrayBuffer
// Browser: display it
const url = URL.createObjectURL(new Blob([bytes], { type: "application/pdf" }));
Make a file public
const f = await vault.setPublic("avatars", "user-42.png", true);
Public files are served — no API key, no login — at a stable URL:
http://api.{org}.local/vault/{app_slug}/{collection}/{filename}
Flip it back with setPublic(..., false) and the URL returns 403.
Share with a user
Owners can share a file (or a whole collection, by passing null as the filename) with one user at a time, as viewer (read/download) or editor (read/download/delete):
await vault.share("reports", "q1.pdf", granteeUserId, "viewer");
await vault.unshare("reports", "q1.pdf", granteeUserId);
const grants = await vault.listGrants("reports", "q1.pdf"); // who has access
Sharing requires Identity. Get shareable users from identity.listAppUsers(). The rules — who counts as an owner, what each role can do, why recipients must already have app access — are enforced server-side; see Vault — Access Control.
Delete
await vault.delete("reports", "q1.pdf");
Removes the bytes from disk and the metadata. This cannot be undone.
Reference
Methods
| Method | Returns | Notes |
|---|---|---|
upload(collection, filename, data) | FileResult | 409 if path exists |
list(collection?) | FileResult[] | everything you can access |
listMine(collection?) | FileResult[] | needs Identity session |
listSharedWithMe() | FileResult[] | needs Identity session |
listPublic(collection?) | FileResult[] | the public space |
download(collection, filename) | ArrayBuffer | raw bytes |
setPublic(collection, filename, isPublic) | FileResult | toggles the public URL |
share(collection, filename | null, userId, role) | void | role: "viewer" | "editor" |
unshare(collection, filename | null, userId) | void | revokes a grant |
listGrants(collection, filename | null) | Grant[] | owner only |
delete(collection, filename) | void | permanent |
Errors
All methods throw VaultError with .status (HTTP code) and .code (machine string):
| Code | Status | Meaning |
|---|---|---|
file_already_exists | 409 | A file already exists at this path |
file_too_large | 413 | Exceeds the app’s max file size |
extension_not_allowed | 415 | Extension blocked by the app’s allowlist |
not_found | 404 | File does not exist |
Limits & gotchas
- No overwrite, no rename. A path is write-once — delete and re-upload (see the 409 pattern above).
- 50 MB per file by default. Configurable per app in Console → App → Vault Settings.
- Extension allowlist. If the admin sets one, anything else is rejected with
415. Empty list = allow all. - No versioning. One file per path, one version. Keep history yourself if you need it.
- LAN only. Files — including “public” ones — are only reachable inside the organisation’s network.