# API: backups manager Source: https://selfstore.dev/docs/api-backups Complete reference for selfstore/backups - createBackupsManager, the BackupsHost you implement for your destination, and every snapshot field and method the panel drives. Several named backups on one destination: a personal one, ones the user created, ones other people share with them. This is the headless engine; [``](https://selfstore.dev/docs/widget-backups) is its panel. You need it when a destination holds **more than one** backup file. A store with a single durable home does not. ```ts import { createBackupsManager } from 'selfstore/backups'; const manager = createBackupsManager({ store: store.advanced, kv: store.flowHost.kv, host: myDriveHost, naming: { canonicalName: 'my-app.zip' } }); await manager.hydrate(); ``` ## createBackupsManager ```ts function createBackupsManager(deps: { store: LocalStore; kv: KV; host: BackupsHost; naming: BackupsNaming; keys?: BackupsKeys; }): BackupsManager; ``` ## Drive, without implementing anything `driveBackupsHost` is a ready-made `BackupsHost` for Google Drive, so an app storing there writes none of the contract below: ```ts import { driveBackupsHost } from 'selfstore/backups'; const host = driveBackupsHost({ auth, kv, fileName: 'acme.zip', nameContains: 'acme' }); ``` `DriveBackupsHostOptions` extends the usual `DriveOptions` with one field: `nameContains`, which narrows the listing server-side. selfstore ships no naming convention, so without it every file the app can see is a candidate. Implement the contract below only for a destination selfstore does not ship. ## BackupsHost: what you implement The manager knows nothing about your destination. It asks this contract for everything, so the same panel drives Drive, a WebDAV folder or your own service. | Member | Signature | Required | | --- | --- | --- | | `kind` | `string` | yes | | `activeIdKey` | `string` | yes - the KV key holding the active file id | | `list` | `() => Promise` | yes | | `open` | `(fileId: string) => BackupTarget` | yes | | `create` | `(fileName: string) => Promise<{ fileId: string }>` | yes | | `remove` | `(fileId: string) => Promise` | yes | | `findOrCreatePersonal` | `() => Promise<{ fileId, created } \| null>` | yes | | `rename` | `(fileId, fileName) => Promise` | optional | | `ensureSession` | `() => Promise` | optional | | `fileOwner` | `(fileId) => Promise<{ email, name } \| null>` | optional | | `excludedFileIds` | `() => Promise<(string \| null \| undefined)[]>` | optional | The optional ones are capabilities, not niceties: a host without `rename` simply has no rename action, rather than a button that fails. ```ts interface BackupFileInfo { id: string; name: string; modifiedTime: string | null; } ``` ### BackupsNaming ```ts interface BackupsNaming { canonicalName: string; // the personal backup's file name namedFileFor?(label: string): string; // label -> file name parseLabel?(name: string): string | null | undefined; // file name -> label } ``` Supply the pair when your users name their backups. Without them every backup uses the canonical name and only one exists. ### BackupsKeys ```ts interface BackupsKeys { registry?: string; encrypted?: string; shared?: string; joined?: string; owner?: string; } ``` The KV keys the manager bookkeeps under. Override them only when two managers share one KV. ## BackupsSnapshot ```ts interface BackupsSnapshot { registry: KnownBackups; activeFileId: string | null; joined: boolean; owner: BackupOwner | null; lastError: BackupsErrorCode | null; } interface KnownBackups { personalFileId: string | null; shared: { fileId: string; ownerEmail: string | null; ownerName: string | null }[]; } type BackupsErrorCode = 'cancelled' | 'gone' | 'failed'; ``` `'cancelled'` is a user gesture, not a failure - a picker they closed. Treat it as nothing happened. ## BackupRow What `list()` returns, and what a panel renders: ```ts interface BackupRow { fileId: string; name: string; label: string | null; modifiedAt: number | null; encrypted: boolean | null; shared: boolean | null; } ``` `encrypted` and `shared` are **three-state**. `null` means not yet known: the listing is cheap, the encryption probe is not, so a row appears immediately and learns what it is afterwards. Render `null` as "unknown", never as "no". ## Methods | Method | Signature | Notes | | --- | --- | --- | | `hydrate` | `() => Promise` | Load the registry. Call once at boot. | | `refresh` | `() => Promise` | Re-read from the destination. | | `list` | `() => Promise` | | | `markActive` | `(fileId: string) => Promise` | | | `probeEncryption` | `(fileId: string) => Promise` | Cheap header read; no decrypt. | | `noteShared` | `(fileId: string, shared: boolean) => Promise` | Record what your app knows. | | `openBackup` | `(fileId, passphrase?) => Promise<'ok' \| 'encrypted' \| 'failed'>` | `'encrypted'` means ask for a password and call again. | | `openPersonal` | `(passphrase?) => Promise<'ok' \| 'encrypted' \| 'failed'>` | | | `createNamed` | `(label: string) => Promise<'ok' \| 'failed'>` | | | `createShared` | `(fileName: string, owner: BackupOwner) => Promise<'ok' \| 'failed'>` | | | `registerShared` | `(fileId: string, owner: BackupOwner) => Promise` | | | `renameBackup` | `(fileId: string, label: string) => Promise<'ok' \| 'failed'>` | | | `deleteBackup` | `(fileId: string) => Promise` | | | `forgetShared` | `(fileId: string) => Promise` | Drop it locally; the file stays. | | `fileNameFor` | `(label: string) => string` | | The three-way return of `openBackup` is the shape worth copying: `'encrypted'` is not an error, it is the journey asking for the next input. A boolean would force you to inspect an error code to tell "wrong password" from "needs one". The manager is a `FlowStore`, so `snapshot` and `subscribe` work exactly as in [flows](https://selfstore.dev/docs/api-flows). ## Forgetting is not deleting `forgetShared` drops a row from this device's registry. `deleteBackup` removes the file. The panel keeps them as separate gestures with separate confirmations, because one is reversible by re-adding the share and the other is not. Map of this site for a model: https://selfstore.dev/llms.txt Every page in one file: https://selfstore.dev/llms-full.txt