selfstore 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.d.ts +12 -3
- package/dist/advanced.js +6 -5
- package/dist/advanced.js.map +1 -1
- package/dist/{chunk-GJRHMI2O.js → chunk-2JJYLXAC.js} +19 -6
- package/dist/chunk-2JJYLXAC.js.map +1 -0
- package/dist/{chunk-KSV2F3ZN.js → chunk-5QGCGAAI.js} +3 -3
- package/dist/{chunk-KSV2F3ZN.js.map → chunk-5QGCGAAI.js.map} +1 -1
- package/dist/chunk-GZBCJXAX.js +59 -0
- package/dist/chunk-GZBCJXAX.js.map +1 -0
- package/dist/{chunk-QVXZLZ6R.js → chunk-MNODL7RK.js} +22 -14
- package/dist/chunk-MNODL7RK.js.map +1 -0
- package/dist/{chunk-TEIAFKFS.js → chunk-WF732QXN.js} +33 -24
- package/dist/chunk-WF732QXN.js.map +1 -0
- package/dist/flows.js +3 -3
- package/dist/index.d.ts +8 -2
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/{local-C9mTIwSf.d.ts → local-CwJPULbf.d.ts} +3 -4
- package/dist/local-F2NNXNBS.js +7 -0
- package/dist/{local-6PLQC34M.js.map → local-F2NNXNBS.js.map} +1 -1
- package/dist/widgets.d.ts +9 -0
- package/dist/widgets.js +63 -36
- package/dist/widgets.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-GJRHMI2O.js.map +0 -1
- package/dist/chunk-QVXZLZ6R.js.map +0 -1
- package/dist/chunk-RI4C6PRJ.js +0 -46
- package/dist/chunk-RI4C6PRJ.js.map +0 -1
- package/dist/chunk-TEIAFKFS.js.map +0 -1
- package/dist/local-6PLQC34M.js +0 -7
package/dist/advanced.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { B as BackupTarget } from './store-C20_6JBo.js';
|
|
|
2
2
|
export { A as AuthExpiredError, a as BuiltinTargetKind, E as EncodeOptions, H as Header, K as KdfParams, L as LocalStore, b as LocalStoreOptions, c as LocalStoreState, M as MirrorState, d as Mode, P as PasswordCheck, e as PasswordPolicy, f as PasswordRequirement, g as PeerSource, h as PeerState, R as RESERVED_COLLECTION_PREFIX, i as RESERVED_STORE_MODES, j as RecipientStanza, k as ReplicaState, S as SelfstoreError, l as SelfstoreErrorCode, m as Severity, n as Snapshot, o as SnapshotFile, p as StatusAction, q as StatusDescriptor, r as StatusInput, s as StorageState, t as StoreError, u as StoreGroupConfig, v as SyncJournalEntry, w as SyncSource, T as TargetKind, x as checkPasswordPolicy, y as createLocalStore, z as deriveStatus, C as errorLabelKey, D as isAuthExpired, F as isReservedStoreMode, G as isSelfstoreError } from './store-C20_6JBo.js';
|
|
3
3
|
import { K as KV } from './cache-ilsK3Tki.js';
|
|
4
4
|
export { C as CachedFile, L as LocalCache, e as LockableCache, i as indexedDbCache, f as isLockableCache, m as memoryCache } from './cache-ilsK3Tki.js';
|
|
5
|
-
export { e as exportSnapshot, g as gisDriveAuth, i as importSnapshot, a as inspect, b as isEncrypted, p as pickFromDisk, s as saveToDisk } from './local-
|
|
5
|
+
export { e as exportSnapshot, g as gisDriveAuth, i as importSnapshot, a as inspect, b as isEncrypted, p as pickFromDisk, s as saveToDisk } from './local-CwJPULbf.js';
|
|
6
6
|
import { c as connect$1, f as fromSession$1, p as preview, a as adopt, b as findOrCreateOwnFile, l as listBackups, d as createBackup, e as deleteBackup, r as renameBackup, g as connect$2, h as fromSession$2, i as connect$3, j as fromSession$3, k as peer } from './drive-BhiTdk-Q.js';
|
|
7
7
|
export { D as DriveAuth, m as DriveBackupInfo, n as DriveOptions, S as S3Config, o as S3ConnectOptions, W as WebdavConfig, q as WebdavConnectOptions, s as WebdavPeerOptions } from './drive-BhiTdk-Q.js';
|
|
8
8
|
import './sync.js';
|
|
@@ -21,10 +21,18 @@ interface FileConnectOptions {
|
|
|
21
21
|
/** Suggested name for the backup file the user creates/picks. */
|
|
22
22
|
fileName: string;
|
|
23
23
|
}
|
|
24
|
-
/** True when the browser supports picking a re-writable file (Chromium)
|
|
24
|
+
/** True when the browser supports picking a re-writable file (Chromium), and
|
|
25
|
+
* has not already refused to open one in this session. */
|
|
25
26
|
declare function isSupported(): boolean;
|
|
27
|
+
/** True when the browser can let the user point at an EXISTING file. Hosts must
|
|
28
|
+
* gate that gesture on this: unlike creating, it has no download fallback, so
|
|
29
|
+
* offering it where it cannot run leaves a button that answers nothing. The
|
|
30
|
+
* refusal is shared with `isSupported` - a browser that refuses one picker
|
|
31
|
+
* refuses the family. */
|
|
32
|
+
declare function isOpenSupported(): boolean;
|
|
26
33
|
/** Prompt the user to choose/create the backup file. Persists the handle for
|
|
27
|
-
* next sessions. Returns the target, or null if cancelled
|
|
34
|
+
* next sessions. Returns the target, or null if cancelled - or if the browser
|
|
35
|
+
* refused to open a picker at all, which `isSupported()` then reports. */
|
|
28
36
|
declare function connect(opts: FileConnectOptions): Promise<BackupTarget | null>;
|
|
29
37
|
/** Rebuild the target from the handle persisted in a past session, or null. */
|
|
30
38
|
declare function fromSession(opts: {
|
|
@@ -52,6 +60,7 @@ declare const fileTarget: {
|
|
|
52
60
|
connect: typeof connect;
|
|
53
61
|
fromSession: typeof fromSession;
|
|
54
62
|
isSupported: typeof isSupported;
|
|
63
|
+
isOpenSupported: typeof isOpenSupported;
|
|
55
64
|
};
|
|
56
65
|
/** WebDAV destination (Nextcloud, ownCloud, any server the user controls), plus
|
|
57
66
|
* `peer()`: a read-only source over another member's shared WebDAV link, so a
|
package/dist/advanced.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { RESERVED_STORE_MODES, createLocalStore, deriveStatus, gisDriveAuth, indexedDbCache, isLockableCache, isReservedStoreMode, memoryCache } from './chunk-
|
|
2
|
-
export { pickFromDisk, saveToDisk } from './chunk-
|
|
1
|
+
export { RESERVED_STORE_MODES, createLocalStore, deriveStatus, gisDriveAuth, indexedDbCache, isLockableCache, isReservedStoreMode, memoryCache } from './chunk-5QGCGAAI.js';
|
|
2
|
+
export { pickFromDisk, saveToDisk } from './chunk-GZBCJXAX.js';
|
|
3
3
|
import './chunk-SKWHKM25.js';
|
|
4
|
-
import { FILE_ID_KEY, renameBackup, deleteBackup, createBackup, listBackups, findOrCreateOwnFile, adopt, preview, fromSession, connect, isSupported, fromSession2, connect2, fromSession4, connect4, peer, fromSession3, connect3 } from './chunk-
|
|
5
|
-
export { RESERVED_COLLECTION_PREFIX, checkPasswordPolicy, exportSnapshot, importSnapshot, inspect, isEncrypted } from './chunk-
|
|
4
|
+
import { FILE_ID_KEY, renameBackup, deleteBackup, createBackup, listBackups, findOrCreateOwnFile, adopt, preview, fromSession, connect, isOpenSupported, isSupported, fromSession2, connect2, fromSession4, connect4, peer, fromSession3, connect3 } from './chunk-WF732QXN.js';
|
|
5
|
+
export { RESERVED_COLLECTION_PREFIX, checkPasswordPolicy, exportSnapshot, importSnapshot, inspect, isEncrypted } from './chunk-2JJYLXAC.js';
|
|
6
6
|
import './chunk-KHER6MWR.js';
|
|
7
7
|
import './chunk-QBCU7OOP.js';
|
|
8
8
|
import './chunk-6746AL4I.js';
|
|
@@ -12,7 +12,8 @@ export { AuthExpiredError, SelfstoreError, errorLabelKey, isAuthExpired, isSelfs
|
|
|
12
12
|
var fileTarget = {
|
|
13
13
|
connect: connect2,
|
|
14
14
|
fromSession: fromSession2,
|
|
15
|
-
isSupported
|
|
15
|
+
isSupported,
|
|
16
|
+
isOpenSupported
|
|
16
17
|
};
|
|
17
18
|
var webdavTarget = {
|
|
18
19
|
connect: connect3,
|
package/dist/advanced.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/entries/advanced.ts"],"names":["connect","fromSession"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/entries/advanced.ts"],"names":["connect","fromSession"],"mappings":";;;;;;;;;;;AA+HO,IAAM,UAAA,GAAa;AAAA,EACzB,OAAA,EAASA,QAAAA;AAAA,EACT,WAAA,EAAaC,YAAAA;AAAA,EACb,WAAA;AAAA,EACA;AACD;AAKO,IAAM,YAAA,GAAe;AAAA,EAC3B,OAAA,EAASD,QAAAA;AAAA,EACT,WAAA,EAAaC,YAAAA;AAAA,EACb;AACD;AAMO,IAAM,QAAA,GAAW;AAAA,EACvB,OAAA,EAASD,QAAAA;AAAA,EACT,WAAA,EAAaC;AACd;AAOO,IAAM,WAAA,GAAc;AAAA,EAC1B,OAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,mBAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA;AACD","file":"advanced.js","sourcesContent":["/**\n * selfstore/advanced - the pull-model store and the machinery under it.\n *\n * The simple `selfstore()` facade (package root) owns its data. This entry\n * inverts that: with createLocalStore your app owns the data and hands the\n * store a gather/apply pair - use it when state lives in your own reactive\n * model (Svelte runes, Redux, signals) and the facade's collections would be\n * a second copy. Everything here also backs `store.advanced` on the simple\n * store: same machinery, same instance, so the two styles compose.\n *\n * Also here: the durable destinations (disk file, Google Drive, WebDAV) as\n * connectable targets, the BackupTarget contract for writing your own, the\n * caches, the headless status derivation, and the functional codec for the\n * backup file format (the fluent one lives at the package root).\n */\n\n// --- The pull-model store: your app owns the data ---\nexport {\n\tcreateLocalStore,\n\ttype LocalStore,\n\ttype LocalStoreOptions,\n\ttype LocalStoreState,\n\ttype StoreError,\n\ttype Mode,\n\ttype TargetKind,\n\ttype SyncSource,\n\ttype SyncJournalEntry,\n\ttype PeerState,\n\ttype MirrorState,\n\ttype ReplicaState,\n\ttype StoreGroupConfig\n} from '../persistence/store';\n\n// --- On-device caches (the store's working copy) ---\nexport {\n\tindexedDbCache,\n\tmemoryCache,\n\tisLockableCache,\n\ttype LocalCache,\n\ttype LockableCache,\n\ttype CachedFile,\n\ttype KV\n} from '../persistence/cache';\n\n// --- Headless status: map store state to your UI copy ---\nexport {\n\tderiveStatus,\n\ttype StatusDescriptor,\n\ttype StatusInput,\n\ttype Severity,\n\ttype StorageState,\n\ttype StatusAction\n} from '../persistence/status';\n\n// --- The target contract (write your own destination) ---\nexport {\n\tRESERVED_STORE_MODES,\n\tisReservedStoreMode,\n\ttype BackupTarget,\n\ttype BuiltinTargetKind,\n\ttype PeerSource\n} from '../persistence/target';\n\n// --- The backup file format, functional style (fluent lives at the root) ---\nexport {\n\texportSnapshot,\n\timportSnapshot,\n\tinspect,\n\tisEncrypted,\n\tRESERVED_COLLECTION_PREFIX,\n\ttype Snapshot,\n\ttype SnapshotFile,\n\ttype Header,\n\ttype KdfParams,\n\ttype RecipientStanza,\n\ttype EncodeOptions\n} from '../selfstore';\n\n// --- Password strength policy (the store enforces it; the UI previews it) ---\nexport {\n\tcheckPasswordPolicy,\n\ttype PasswordPolicy,\n\ttype PasswordCheck,\n\ttype PasswordRequirement\n} from '../selfstore';\n\n// --- The full error contract (AuthExpiredError is what a custom target or\n// DriveAuth THROWS to signal genuine access loss; everything else it\n// throws is treated as transient and retried) ---\nexport {\n\tSelfstoreError,\n\tAuthExpiredError,\n\tisSelfstoreError,\n\tisAuthExpired,\n\terrorLabelKey,\n\ttype SelfstoreErrorCode\n} from '../selfstore';\n\n// --- Durable destinations (opt-in), each implementing BackupTarget ---\n// Explicit namespace objects: every member is deliberately public, so a future\n// internal helper in a target module can never leak into the contract.\nimport {\n\tconnect as fileConnect,\n\tfromSession as fileFromSession,\n\tisSupported as fileIsSupported,\n\tisOpenSupported as fileIsOpenSupported\n} from '../persistence/targets/file';\nimport {\n\tconnect as webdavConnect,\n\tfromSession as webdavFromSession,\n\tpeer as webdavPeer\n} from '../persistence/targets/webdav';\nimport { connect as s3Connect, fromSession as s3FromSession } from '../persistence/targets/s3';\nimport {\n\tconnect as driveConnect,\n\tfromSession as driveFromSession,\n\tpreview as drivePreview,\n\tadopt as driveAdopt,\n\tfindOrCreateOwnFile as driveFindOrCreateOwnFile,\n\tlistBackups as driveListBackups,\n\tcreateBackup as driveCreateBackup,\n\tdeleteBackup as driveDeleteBackup,\n\trenameBackup as driveRenameBackup,\n\tFILE_ID_KEY as DRIVE_FILE_ID_KEY\n} from '../persistence/targets/drive';\n\n/** Disk-file destination (File System Access, Chromium). */\nexport const fileTarget = {\n\tconnect: fileConnect,\n\tfromSession: fileFromSession,\n\tisSupported: fileIsSupported,\n\tisOpenSupported: fileIsOpenSupported\n};\n\n/** WebDAV destination (Nextcloud, ownCloud, any server the user controls), plus\n * `peer()`: a read-only source over another member's shared WebDAV link, so a\n * group can share read-write without Google Drive (see store.attachPeer). */\nexport const webdavTarget = {\n\tconnect: webdavConnect,\n\tfromSession: webdavFromSession,\n\tpeer: webdavPeer\n};\n\n/** S3-compatible destination (Amazon S3, Cloudflare R2, Backblaze B2, MinIO):\n * the browser signs each request with SigV4 and writes one object on a bucket\n * the user controls, no vendor broker. The bucket only ever holds the same\n * end-to-end-encrypted .selfstore bytes. */\nexport const s3Target = {\n\tconnect: s3Connect,\n\tfromSession: s3FromSession\n};\n\n/** Google Drive destination, plus the shared-file primitives (preview a specific\n * file, adopt it as this device's backup, find-or-create the user's own file)\n * and the backup-management ops (list the app's files with dates, create a\n * named empty backup, rename one, delete one for good) - the raw pieces a \"my\n * backups\" panel builds on. */\nexport const driveTarget = {\n\tconnect: driveConnect,\n\tfromSession: driveFromSession,\n\tpreview: drivePreview,\n\tadopt: driveAdopt,\n\tfindOrCreateOwnFile: driveFindOrCreateOwnFile,\n\tlistBackups: driveListBackups,\n\tcreateBackup: driveCreateBackup,\n\tdeleteBackup: driveDeleteBackup,\n\trenameBackup: driveRenameBackup,\n\tFILE_ID_KEY: DRIVE_FILE_ID_KEY\n};\n\nexport type { FileConnectOptions } from '../persistence/targets/file';\nexport type { DriveAuth, DriveOptions, DriveBackupInfo } from '../persistence/targets/drive';\nexport type {\n\tWebdavConfig,\n\tWebdavConnectOptions,\n\tWebdavPeerOptions\n} from '../persistence/targets/webdav';\nexport type { S3Config, S3ConnectOptions } from '../persistence/targets/s3';\nexport { gisDriveAuth } from '../persistence/targets/drive-auth-gis';\nexport { saveToDisk, pickFromDisk } from '../selfstore/targets/local';\n"]}
|
|
@@ -399,12 +399,25 @@ var BackupBuilder = class {
|
|
|
399
399
|
/** Save the backup to disk (File System Access API, else a download).
|
|
400
400
|
* Browser-only terminal; defaults to `<app>-<date>.zip`. False when the
|
|
401
401
|
* user closed the save dialog: nothing was written, so do not tell them
|
|
402
|
-
* they have a backup.
|
|
402
|
+
* they have a backup.
|
|
403
|
+
*
|
|
404
|
+
* Asks WHERE first, encrypts after. The save dialog needs the transient
|
|
405
|
+
* activation of the click that led here, and building an encrypted backup
|
|
406
|
+
* outlives it (Argon2id is deliberately slow): encrypting first made the
|
|
407
|
+
* browser refuse the dialog and silently download instead, turning a file
|
|
408
|
+
* the user chose into one they have to go and find. */
|
|
403
409
|
async toDisk(filename) {
|
|
404
|
-
const blob = await this.toBlob();
|
|
405
410
|
const name = filename ?? `${this.opts.app}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}${BACKUP_EXTENSION}`;
|
|
406
|
-
const {
|
|
407
|
-
|
|
411
|
+
const { pickSaveHandle, writeToHandle, downloadBlob } = await import('./local-F2NNXNBS.js');
|
|
412
|
+
const cible = await pickSaveHandle(name);
|
|
413
|
+
if (cible === "CANCELLED") return false;
|
|
414
|
+
const blob = await this.toBlob();
|
|
415
|
+
if (cible) {
|
|
416
|
+
await writeToHandle(cible.handle, blob);
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
downloadBlob(blob, name);
|
|
420
|
+
return true;
|
|
408
421
|
}
|
|
409
422
|
};
|
|
410
423
|
var EncryptedBackupBuilder = class _EncryptedBackupBuilder extends BackupBuilder {
|
|
@@ -481,5 +494,5 @@ async function changePassword(input, opts) {
|
|
|
481
494
|
}
|
|
482
495
|
|
|
483
496
|
export { BACKUP_EXTENSION, BACKUP_MIME, RESERVED_COLLECTION_PREFIX, asBytes, backup, changePassword, checkPasswordPolicy, exportSnapshot, importSnapshot, inspect, isEncrypted, readBoxWithSync, restore, writeBox };
|
|
484
|
-
//# sourceMappingURL=chunk-
|
|
485
|
-
//# sourceMappingURL=chunk-
|
|
497
|
+
//# sourceMappingURL=chunk-2JJYLXAC.js.map
|
|
498
|
+
//# sourceMappingURL=chunk-2JJYLXAC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/selfstore/archive.ts","../src/selfstore/box.ts","../src/selfstore/types.ts","../src/selfstore/password-policy.ts","../src/selfstore/fluent.ts","../src/selfstore/index.ts"],"names":["utf8"],"mappings":"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","file":"chunk-2JJYLXAC.js","sourcesContent":["// The inner archive: a JSON manifest (selfstore.json) plus one entry per\n// binary file, as a plain ZIP. Encrypted backups wrap these same bytes in\n// AES-GCM (box.ts). fflate is imported dynamically - only needed at\n// export/import time.\n\nimport type { Snapshot, SnapshotFile } from './types';\nimport { SelfstoreError } from './errors';\n\nconst MANIFEST = 'selfstore.json';\n// Opaque caller bookkeeping (createLocalStore's schema version + merge\n// metadata). Its own entry, so the manifest holds nothing but app data.\nconst SIDECAR = 'sync.json';\nconst ARCHIVE_VERSION = 1;\n\n// Zip-bomb guards. Backups are user data measured in MB; half a GiB per\n// entry and 1 GiB total are far above legitimate use and bound worst-case\n// inflation (many individually-legal entries must not add up to a bomb).\nexport const MAX_ENTRY_BYTES = 512 * 1024 * 1024;\nexport const MAX_TOTAL_BYTES = 1024 * 1024 * 1024;\n\nconst utf8 = { enc: new TextEncoder(), dec: new TextDecoder() };\n\ninterface FileMeta {\n\tid: string;\n\tname: string;\n\tmime: string;\n}\n\n/**\n * ZIP a set of named entries. `level` applies to the JSON entries; file\n * attachments are stored uncompressed - photos and PDFs are usually already\n * compressed, and re-deflating them was the biggest chunk of per-save\n * main-thread time for near-zero size gain. Still a plain readable ZIP.\n */\nexport async function zip(\n\tentries: Record<string, Uint8Array>,\n\tlevel: 0 | 6 = 6\n): Promise<Uint8Array> {\n\tconst { zipSync } = await import('fflate');\n\tconst input: Record<string, Uint8Array | [Uint8Array, { level: 0 }]> = {};\n\tfor (const [name, bytes] of Object.entries(entries)) {\n\t\tinput[name] = level !== 0 && name.startsWith('files/') ? [bytes, { level: 0 }] : bytes;\n\t}\n\treturn zipSync(input as Parameters<typeof zipSync>[0], { level });\n}\n\n/** Unzip to named entries. BAD_FORMAT on unreadable bytes, TOO_LARGE past the bomb guards. */\nexport async function unzip(\n\tbytes: Uint8Array,\n\tmaxEntryBytes: number = MAX_ENTRY_BYTES,\n\tmaxTotalBytes: number = MAX_TOTAL_BYTES\n): Promise<Record<string, Uint8Array>> {\n\tconst { unzipSync } = await import('fflate');\n\tlet total = 0;\n\ttry {\n\t\treturn unzipSync(bytes, {\n\t\t\tfilter: (f) => {\n\t\t\t\tif (f.originalSize > maxEntryBytes) {\n\t\t\t\t\tthrow new SelfstoreError('TOO_LARGE', `Archive entry \"${f.name}\" is too large.`);\n\t\t\t\t}\n\t\t\t\ttotal += f.originalSize;\n\t\t\t\tif (total > maxTotalBytes) {\n\t\t\t\t\tthrow new SelfstoreError('TOO_LARGE', 'Archive total size exceeds the guard.');\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t});\n\t} catch (e) {\n\t\tif (e instanceof SelfstoreError) throw e;\n\t\tthrow new SelfstoreError('BAD_FORMAT', 'Unreadable archive.');\n\t}\n}\n\n/** Manifest + file entries for a snapshot; `sidecar` rides its own sync.json entry. */\nexport function buildEntries(snap: Snapshot, sidecar?: unknown): Record<string, Uint8Array> {\n\tconst entries: Record<string, Uint8Array> = {};\n\tentries[MANIFEST] = utf8.enc.encode(\n\t\tJSON.stringify({\n\t\t\tversion: ARCHIVE_VERSION,\n\t\t\tcollections: snap.collections,\n\t\t\tfiles: snap.files.map(({ id, name, mime }): FileMeta => ({ id, name, mime }))\n\t\t})\n\t);\n\tif (sidecar !== undefined && sidecar !== null) {\n\t\tentries[SIDECAR] = utf8.enc.encode(JSON.stringify(sidecar));\n\t}\n\tfor (const f of snap.files) entries[`files/${f.id}`] = f.bytes;\n\treturn entries;\n}\n\n/** The sync.json sidecar if present, else null. Unreadable content reads as absent. */\nexport function readSidecar(entries: Record<string, Uint8Array>): unknown {\n\tconst bytes = entries[SIDECAR];\n\tif (!bytes) return null;\n\ttry {\n\t\treturn JSON.parse(utf8.dec.decode(bytes));\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** Rebuild a snapshot from ZIP entries (the inverse of buildEntries). */\nexport function entriesToSnapshot(entries: Record<string, Uint8Array>): Snapshot {\n\tconst manifestBytes = entries[MANIFEST];\n\tif (!manifestBytes) throw new SelfstoreError('BAD_FORMAT', 'Missing manifest.');\n\tconst manifest = JSON.parse(utf8.dec.decode(manifestBytes)) as {\n\t\tcollections?: Record<string, unknown[]>;\n\t\tfiles?: FileMeta[];\n\t};\n\tconst files: SnapshotFile[] = (manifest.files ?? []).map((m) => ({\n\t\t...m,\n\t\tbytes: entries[`files/${m.id}`] ?? new Uint8Array()\n\t}));\n\treturn { collections: manifest.collections ?? {}, files };\n}\n\n/** Pack a snapshot (plus an optional opaque sidecar) into ZIP bytes. */\nexport async function pack(snap: Snapshot, sidecar?: unknown): Promise<Uint8Array> {\n\treturn zip(buildEntries(snap, sidecar), 6);\n}\n\n/** Unpack ZIP bytes into a snapshot plus its sidecar (null when absent). */\nexport async function unpackWithSidecar(\n\tzipBytes: Uint8Array\n): Promise<{ snapshot: Snapshot; sidecar: unknown }> {\n\tconst entries = await unzip(zipBytes);\n\treturn { snapshot: entriesToSnapshot(entries), sidecar: readSidecar(entries) };\n}\n","// The portable backup container - a real ZIP in both cases, never a mystery\n// blob:\n//\n// unencrypted: meta.json + selfstore.json + files/* (browsable, format 1)\n// encrypted: meta.json + data.enc + LISEZMOI.txt (AES-256-GCM / Argon2id)\n//\n// Encrypted means the password envelope (format 3): a random data key seals\n// the inner ZIP, wrapped once per password in keys[], and the exact meta.json\n// bytes ride as GCM AAD so the slot table is tamper-evident. Format 2 is the\n// passwordless group variant. Anything else is refused.\n\nimport type { Snapshot, Header, EncodeOptions, PasswordSlot, ExternalSlot, KeySlot } from './types';\nimport {\n\tbuildEntries,\n\tentriesToSnapshot,\n\treadSidecar,\n\tpack,\n\tunpackWithSidecar,\n\tzip,\n\tunzip\n} from './archive';\nimport {\n\tmintSlot,\n\topenSlot,\n\topenExternalSlot,\n\tMAX_KEY_SLOTS,\n\tgcmSealAad,\n\tgcmOpenAad,\n\ttoBase64,\n\tfromBase64\n} from './crypto';\nimport {\n\tGROUP_KEYING,\n\tgcmSealRaw,\n\tgcmOpenRaw,\n\tsealDataKey,\n\topenDataKey,\n\tsignBox,\n\tverifyBox,\n\ttype GroupIdentity\n} from './group';\nimport { SelfstoreError } from './errors';\n\n// Genuine ZIPs get the honest extension.\nexport const BACKUP_EXTENSION = '.zip';\nexport const BACKUP_MIME = 'application/zip';\n\nconst META = 'meta.json';\nconst DATA = 'data.enc';\nconst SIG = 'sig.bin';\nconst README = 'LISEZMOI.txt';\n\n// Format identifier, which is also the discriminant: 1 plain ZIP, 2 group\n// mode, 3 authenticated password envelope (header bound as GCM AAD). These are\n// fixed wire ids; anything else is refused.\nconst BOX_FORMAT_PLAIN = 1;\nconst BOX_FORMAT_GROUP = 2;\nconst BOX_FORMAT_ENVELOPE_AUTH = 3;\n\nconst ZIP_MAGIC = [0x50, 0x4b, 0x03, 0x04]; // \"PK\\x03\\x04\"\n\nconst utf8 = { enc: new TextEncoder(), dec: new TextDecoder() };\n\n// Shipped inside encrypted backups for whoever opens the ZIP by hand. ASCII\n// only so it renders in any viewer; apps brand it via EncodeOptions.readme.\nconst DEFAULT_README =\n\t'Encrypted backup / Sauvegarde chiffree\\n\\n' +\n\t'This is a valid ZIP archive.\\n' +\n\t'\"data.enc\" holds your encrypted data (AES-256-GCM, key derived with Argon2id);\\n' +\n\t'\"meta.json\" holds the decryption parameters (cleartext).\\n' +\n\t'To read it, import this file into the application that created it\\n' +\n\t'(named in meta.json) with your password.\\n\\n' +\n\t'Ce fichier est une archive ZIP valide.\\n' +\n\t'\"data.enc\" contient vos donnees chiffrees (AES-256-GCM, cle derivee par Argon2id) ;\\n' +\n\t'\"meta.json\" contient les parametres de dechiffrement (en clair).\\n' +\n\t\"Pour la lire, importez ce fichier dans l'application qui l'a creee\\n\" +\n\t'(nommee dans meta.json) avec votre mot de passe.\\n';\n\n/** Coerce an accepted input (a picked File, a fetched Blob, raw bytes) to bytes. */\nexport async function asBytes(input: Blob | Uint8Array): Promise<Uint8Array> {\n\treturn input instanceof Uint8Array ? input : new Uint8Array(await input.arrayBuffer());\n}\n\nfunction startsWith(bytes: Uint8Array, magic: number[]): boolean {\n\treturn bytes.length >= magic.length && magic.every((b, i) => bytes[i] === b);\n}\n\n// An unknown cipher or per-slot KDF means a newer writer: UNSUPPORTED_VERSION,\n// not a misleading DECRYPT_FAILED from feeding foreign params to AES-GCM.\nfunction assertKnownCrypto(header: Header): void {\n\tif (header.encryption !== 'none' && header.encryption !== 'aes-256-gcm') {\n\t\tthrow new SelfstoreError(\n\t\t\t'UNSUPPORTED_VERSION',\n\t\t\t`Encryption \"${header.encryption}\" is newer than this reader supports.`\n\t\t);\n\t}\n\tif (header.keying !== undefined && header.keying !== GROUP_KEYING) {\n\t\tthrow new SelfstoreError(\n\t\t\t'UNSUPPORTED_VERSION',\n\t\t\t`Key envelope \"${header.keying}\" is newer than this reader supports.`\n\t\t);\n\t}\n\tfor (const slot of header.keys ?? []) {\n\t\t// External slots carry no KDF (KEK comes from the caller's secret).\n\t\tif (!slot || (slot as ExternalSlot).kind === 'external') continue;\n\t\tif ((slot as PasswordSlot).kdf?.algo !== 'argon2id') {\n\t\t\tthrow new SelfstoreError(\n\t\t\t\t'UNSUPPORTED_VERSION',\n\t\t\t\t`Key derivation \"${(slot as PasswordSlot).kdf?.algo}\" is newer than this reader supports.`\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Serialize a snapshot to backup bytes. The optional `sidecar`\n * (createLocalStore's bookkeeping) rides its own sync.json entry - inside the\n * envelope when encrypting, so it never leaks in cleartext.\n */\nexport async function writeBox(\n\tsnapshot: Snapshot,\n\topts: EncodeOptions,\n\tsidecar?: unknown\n): Promise<Uint8Array> {\n\tconst header: Header = {\n\t\tformat: BOX_FORMAT_PLAIN,\n\t\tapp: opts.app,\n\t\tappVersion: opts.appVersion,\n\t\tschemaVersion: opts.schemaVersion,\n\t\tcreatedAt: new Date().toISOString(),\n\t\tencryption: 'none'\n\t};\n\n\tif (opts.group) {\n\t\tif (opts.password) {\n\t\t\tthrow new TypeError('writeBox(): `group` and `password` are mutually exclusive.');\n\t\t}\n\t\t// Fresh data key enveloped once per recipient; the author's signature\n\t\t// covers the exact meta.json + data.enc bytes, so nothing a reader\n\t\t// trusts (recipients, author claim, iv, ciphertext) can be altered.\n\t\tconst dataKey = crypto.getRandomValues(new Uint8Array(32));\n\t\tconst enc = await gcmSealRaw(dataKey, await pack(snapshot, sidecar));\n\t\tconst meta: Header = {\n\t\t\t...header,\n\t\t\tformat: BOX_FORMAT_GROUP,\n\t\t\tencryption: 'aes-256-gcm',\n\t\t\tkeying: GROUP_KEYING,\n\t\t\tauthor: opts.group.sign.pub,\n\t\t\trecipients: await sealDataKey(dataKey, opts.group.recipients),\n\t\t\tiv: enc.iv\n\t\t};\n\t\tconst metaBytes = utf8.enc.encode(JSON.stringify(meta));\n\t\treturn zip(\n\t\t\t{\n\t\t\t\t[META]: metaBytes,\n\t\t\t\t[DATA]: enc.ciphertext,\n\t\t\t\t[SIG]: await signBox(metaBytes, enc.ciphertext, opts.group.sign.priv),\n\t\t\t\t[README]: utf8.enc.encode(opts.readme || DEFAULT_README)\n\t\t\t},\n\t\t\t0\n\t\t);\n\t}\n\n\tif (opts.envelope && opts.password) {\n\t\tthrow new TypeError('writeBox(): `envelope` and `password` are mutually exclusive.');\n\t}\n\n\tif (opts.envelope || opts.password) {\n\t\t// A rewrite passes `envelope` (held data key + carried slot table) so a\n\t\t// writer that knows only one password preserves every other slot; a\n\t\t// plain `password` mints a fresh single-slot envelope, i.e. a data-key\n\t\t// rotation - that is what makes setEncryption actually revoke.\n\t\t// The iv is minted before meta.json is serialized so it sits inside the\n\t\t// AAD; seal and open then agree on the exact header bytes.\n\t\tconst dataKey = opts.envelope?.dataKey ?? crypto.getRandomValues(new Uint8Array(32));\n\t\tconst slots = opts.envelope?.slots ?? [await mintSlot(opts.password!, dataKey)];\n\t\tif (slots.length === 0 || slots.length > MAX_KEY_SLOTS) {\n\t\t\tthrow new TypeError(`writeBox(): between 1 and ${MAX_KEY_SLOTS} password slots.`);\n\t\t}\n\t\tconst iv = crypto.getRandomValues(new Uint8Array(12));\n\t\tconst meta: Header = {\n\t\t\t...header,\n\t\t\tformat: BOX_FORMAT_ENVELOPE_AUTH,\n\t\t\tencryption: 'aes-256-gcm',\n\t\t\tkeys: slots,\n\t\t\tiv: toBase64(iv)\n\t\t};\n\t\tconst metaBytes = utf8.enc.encode(JSON.stringify(meta));\n\t\tconst ciphertext = await gcmSealAad(dataKey, iv, await pack(snapshot, sidecar), metaBytes);\n\t\treturn zip(\n\t\t\t{\n\t\t\t\t[META]: metaBytes,\n\t\t\t\t[DATA]: ciphertext,\n\t\t\t\t[README]: utf8.enc.encode(opts.readme || DEFAULT_README)\n\t\t\t},\n\t\t\t0\n\t\t);\n\t}\n\n\t// The file is the browsable archive: manifest + files (+ sync.json), plus meta.json.\n\tconst entries = buildEntries(snapshot, sidecar);\n\tentries[META] = utf8.enc.encode(JSON.stringify(header));\n\treturn zip(entries, 6);\n}\n\n/** Read the cleartext metadata (app, date, whether encrypted) without decrypting. */\nexport async function readBoxMeta(bytes: Uint8Array): Promise<Header> {\n\tif (!startsWith(bytes, ZIP_MAGIC)) {\n\t\tthrow new SelfstoreError(\n\t\t\t'BAD_FORMAT',\n\t\t\t'Not a selfstore backup: expected a ZIP. Pass the exact bytes/Blob produced by ' +\n\t\t\t\t'backup().toBlob() / exportSnapshot(), not a decoded object.'\n\t\t);\n\t}\n\treturn metaOf(await unzip(bytes));\n}\n\n/**\n * Group-mode read inputs: the reader's identity and the trusted author keys\n * (manifest members' Ed25519 publics). `authors` is mandatory - a valid\n * signature over an attacker-chosen author proves nothing (SPEC.md 12.6), so\n * there is no \"decrypt without checking who signed\" mode.\n */\nexport interface GroupReadOptions {\n\tidentity: Pick<GroupIdentity, 'encPub' | 'encPriv'>;\n\tauthors: string[];\n}\n\n/**\n * Key material captured at read time: the data key that opened the file plus\n * the slot table verbatim. Carried into rewrites so a session that knows only\n * one key preserves every slot.\n */\nexport interface BoxEnvelope {\n\tdataKey: Uint8Array;\n\tslots: KeySlot[];\n}\n\n/**\n * App-supplied secret fetch for an external-key slot (the WebAuthn/hardware\n * exchange lives app-side). Return null to skip the slot (wrong key, user\n * cancelled).\n */\nexport type ExternalKeyResolver = (slot: ExternalSlot) => Promise<Uint8Array | null>;\n\n/**\n * Read a backup into a snapshot plus its sync.json sidecar (null when the\n * file carries none). Group copies need `group` and return the verified\n * author; envelope copies accept a held `dataKey` (KDF-free re-read) and\n * return the envelope for later rewrites.\n */\nexport async function readBoxWithSync(\n\tbytes: Uint8Array,\n\tpassword?: string,\n\tgroup?: GroupReadOptions,\n\tdataKey?: Uint8Array,\n\texternalResolver?: ExternalKeyResolver\n): Promise<{\n\tsnapshot: Snapshot;\n\tsidecar: unknown;\n\tauthor?: string;\n\tenvelope?: BoxEnvelope;\n\tformat: number;\n}> {\n\tconst entries = await unzip(bytes);\n\tconst meta = metaOf(entries);\n\tconst format = meta.format ?? BOX_FORMAT_PLAIN;\n\tif (\n\t\tformat !== BOX_FORMAT_PLAIN &&\n\t\tformat !== BOX_FORMAT_GROUP &&\n\t\tformat !== BOX_FORMAT_ENVELOPE_AUTH\n\t) {\n\t\tthrow new SelfstoreError(\n\t\t\t'UNSUPPORTED_VERSION',\n\t\t\t`Backup format ${format} is not supported by this reader.`\n\t\t);\n\t}\n\t// Bind security mode to format generation both ways, so neither `keying`\n\t// nor `format` can be stripped to route a box down the wrong path.\n\tif ((format === BOX_FORMAT_GROUP) !== !!meta.keying) {\n\t\tthrow new SelfstoreError(\n\t\t\t'BAD_FORMAT',\n\t\t\t'Group mode (format 2) and the keying field must agree.'\n\t\t);\n\t}\n\tif ((format === BOX_FORMAT_ENVELOPE_AUTH) !== Array.isArray(meta.keys)) {\n\t\tthrow new SelfstoreError(\n\t\t\t'BAD_FORMAT',\n\t\t\t'Password envelope (format 3) and the keys field must agree.'\n\t\t);\n\t}\n\tif (meta.keying) return { ...(await readGroupBox(entries, meta, group)), format };\n\tif (format === BOX_FORMAT_ENVELOPE_AUTH) {\n\t\treturn {\n\t\t\t...(await readEnvelopeBox(entries, meta, password, dataKey, externalResolver)),\n\t\t\tformat\n\t\t};\n\t}\n\tif (meta.encryption === 'none') {\n\t\treturn { snapshot: entriesToSnapshot(entries), sidecar: readSidecar(entries), format };\n\t}\n\t// Encrypted content in a container claiming the plain format: never written\n\t// by this library. Refuse cleanly rather than half-read.\n\tthrow new SelfstoreError('BAD_FORMAT', 'Encrypted content in a plain-format container.');\n}\n\n// Envelope read path: bounds first, the held data key as a KDF-free fast\n// path, then one trial per slot. All slots failing is DECRYPT_FAILED - wrong\n// key and tampering stay one case.\nasync function readEnvelopeBox(\n\tentries: Record<string, Uint8Array>,\n\tmeta: Header,\n\tpassword?: string,\n\tdataKey?: Uint8Array,\n\texternalResolver?: ExternalKeyResolver\n): Promise<{ snapshot: Snapshot; sidecar: unknown; envelope: BoxEnvelope }> {\n\tconst dataEnc = entries[DATA];\n\tconst metaBytes = entries[META];\n\tconst slots = meta.keys;\n\tif (\n\t\t!dataEnc ||\n\t\t!metaBytes ||\n\t\t!Array.isArray(slots) ||\n\t\tslots.length === 0 ||\n\t\ttypeof meta.iv !== 'string' ||\n\t\tmeta.encryption !== 'aes-256-gcm'\n\t) {\n\t\tthrow new SelfstoreError('BAD_FORMAT', 'Missing or malformed envelope entries or parameters.');\n\t}\n\tif (slots.length > MAX_KEY_SLOTS) {\n\t\tthrow new SelfstoreError(\n\t\t\t'UNSUPPORTED_VERSION',\n\t\t\t`Backup declares ${slots.length} key slots; this reader caps at ${MAX_KEY_SLOTS} ` +\n\t\t\t\t'(each password slot is one memory-hard trial).'\n\t\t);\n\t}\n\t// The exact meta.json bytes are bound as GCM AAD: a tampered header (an\n\t// altered slot table, a swapped KDF) fails the decrypt instead of opening.\n\tconst aad = metaBytes;\n\tconst iv = fromBase64(meta.iv);\n\t// A caller re-reading its own file skips the KDF entirely. On failure fall\n\t// through to the slot trials - another device may have rotated the key.\n\tif (dataKey) {\n\t\ttry {\n\t\t\tconst r = await unpackWithSidecar(await gcmOpenAad(dataKey, iv, dataEnc, aad));\n\t\t\treturn { ...r, envelope: { dataKey, slots } };\n\t\t} catch {\n\t\t\t/* rotated, foreign, or tampered file: the slot path decides */\n\t\t}\n\t}\n\tif (!password && !externalResolver) {\n\t\tthrow new SelfstoreError(\n\t\t\t'PASSWORD_REQUIRED',\n\t\t\t'This backup is encrypted. Provide the password, or the external key (e.g. a passkey), to open it.'\n\t\t);\n\t}\n\tfor (const slot of slots) {\n\t\tlet opened: Uint8Array | null = null;\n\t\tif ((slot as ExternalSlot).kind === 'external') {\n\t\t\tif (externalResolver) {\n\t\t\t\tconst secret = await externalResolver(slot as ExternalSlot);\n\t\t\t\tif (secret) opened = await openExternalSlot(slot as ExternalSlot, secret);\n\t\t\t}\n\t\t} else if (password) {\n\t\t\topened = await openSlot(slot as PasswordSlot, password);\n\t\t}\n\t\tif (!opened) continue;\n\t\t// Every slot wraps the same data key, so if the decrypt below fails\n\t\t// (header tamper surfaces here on format 3) trying another slot gains\n\t\t// nothing - let it throw.\n\t\tconst r = await unpackWithSidecar(await gcmOpenAad(opened, iv, dataEnc, aad));\n\t\treturn { ...r, envelope: { dataKey: opened, slots } };\n\t}\n\tthrow new SelfstoreError(\n\t\t'DECRYPT_FAILED',\n\t\t'Wrong key (no slot opened), or the backup is corrupted.'\n\t);\n}\n\n// Group read path, in trust order: shape, membership, signature, then\n// envelope + decrypt.\nasync function readGroupBox(\n\tentries: Record<string, Uint8Array>,\n\tmeta: Header,\n\tgroup?: GroupReadOptions\n): Promise<{ snapshot: Snapshot; sidecar: unknown; author: string }> {\n\tif (!group || !Array.isArray(group.authors)) {\n\t\tthrow new SelfstoreError(\n\t\t\t'IDENTITY_REQUIRED',\n\t\t\t'This copy is group-encrypted (per-member keys, no password). Open it with the member ' +\n\t\t\t\t'identity AND the trusted author list: the store does this when attached with { group }.'\n\t\t);\n\t}\n\tconst metaBytes = entries[META];\n\tconst dataEnc = entries[DATA];\n\tconst sig = entries[SIG];\n\t// Trusted fields must be well-typed, not merely truthy: malformed input\n\t// fails closed as BAD_FORMAT, never reaches the crypto as a TypeError.\n\tif (\n\t\t!metaBytes ||\n\t\t!dataEnc ||\n\t\t!sig ||\n\t\tmeta.format !== BOX_FORMAT_GROUP ||\n\t\ttypeof meta.author !== 'string' ||\n\t\tmeta.author.length === 0 ||\n\t\t!Array.isArray(meta.recipients) ||\n\t\tmeta.recipients.length === 0 ||\n\t\ttypeof meta.iv !== 'string'\n\t) {\n\t\tthrow new SelfstoreError(\n\t\t\t'BAD_FORMAT',\n\t\t\t'Missing or malformed group encryption entries or parameters.'\n\t\t);\n\t}\n\t// Membership before any crypto: a valid signature over an attacker-chosen\n\t// author proves nothing.\n\tif (!group.authors.includes(meta.author)) {\n\t\tthrow new SelfstoreError(\n\t\t\t'SIGNATURE_INVALID',\n\t\t\t'Copy author is not a trusted group member (check the membership manifest).'\n\t\t);\n\t}\n\tif (!(await verifyBox(metaBytes, dataEnc, sig, meta.author))) {\n\t\tthrow new SelfstoreError('SIGNATURE_INVALID', 'Copy signature verification failed.');\n\t}\n\tconst dataKey = await openDataKey(meta.recipients, group.identity);\n\tconst inner = await gcmOpenRaw(dataKey, meta.iv, dataEnc);\n\tconst r = await unpackWithSidecar(inner);\n\treturn { ...r, author: meta.author };\n}\n\n/** Read a backup into a snapshot, ignoring the sync sidecar. */\nexport async function readBox(bytes: Uint8Array, password?: string): Promise<Snapshot> {\n\treturn (await readBoxWithSync(bytes, password)).snapshot;\n}\n\nfunction metaOf(entries: Record<string, Uint8Array>): Header {\n\tconst metaBytes = entries[META];\n\tif (!metaBytes) throw new SelfstoreError('BAD_FORMAT', 'Missing backup metadata.');\n\tconst meta = JSON.parse(utf8.dec.decode(metaBytes)) as Header;\n\tif ((meta.format ?? BOX_FORMAT_PLAIN) > BOX_FORMAT_ENVELOPE_AUTH) {\n\t\tthrow new SelfstoreError(\n\t\t\t'UNSUPPORTED_VERSION',\n\t\t\t`Backup format v${meta.format} is newer than this reader supports.`\n\t\t);\n\t}\n\tassertKnownCrypto(meta);\n\treturn meta;\n}\n","// Public types. selfstore is schema-agnostic: named collections of opaque\n// documents plus binary files. The app owns the schema and its migrations.\n\n/** A binary attachment (image, PDF, any bytes). */\nexport interface SnapshotFile {\n\tid: string;\n\tname: string;\n\tmime: string;\n\tbytes: Uint8Array;\n}\n\n/**\n * Collection names starting with `__` are reserved for library bookkeeping\n * (createLocalStore keeps its sync metadata under `__store`). The fluent\n * `backup()` rejects them and `read()` strips them.\n */\nexport const RESERVED_COLLECTION_PREFIX = '__';\n\n/** Everything a backup carries. Collection names must not start with `__`. */\nexport interface Snapshot {\n\tcollections: Record<string, unknown[]>;\n\tfiles: SnapshotFile[];\n}\n\n/** Key-derivation parameters. Stored cleartext so older files still decode. */\nexport interface KdfParams {\n\talgo: 'argon2id';\n\tsalt: string;\n\tm: number;\n\tt: number;\n\tp: number;\n}\n\n/**\n * One wrap of the random data key under one password; any slot's password\n * opens the backup. Adding or removing a slot leaves the data key alone.\n * Changing a password rotates the data key (setEncryption) - that is the\n * operation that actually revokes access.\n */\nexport interface PasswordSlot {\n\t/** Random id so an app can list or drop a slot without knowing its\n\t * password. Cleartext, not authenticated. */\n\tid: string;\n\t/** Absent on password slots, so files written before external keys\n\t * existed still parse. */\n\tkind?: 'password';\n\tkdf: KdfParams;\n\t/** 96-bit IV of the wrap, base64. */\n\tiv: string;\n\t/** AES-256-GCM(KEK, dataKey) with tag appended: 48 bytes, base64. */\n\twrapped: string;\n}\n\n/**\n * Data key wrapped under a caller-supplied 32-byte secret (passkey PRF,\n * hardware token). The library never performs the WebAuthn or hardware\n * exchange; the app derives the secret and hands it in. KEK is\n * HKDF-SHA256 of the secret - no Argon2, the input is already\n * high-entropy. Shares the `keys[]` table with password slots, so a\n * backup can hold e.g. a passkey plus a recovery password.\n */\nexport interface ExternalSlot {\n\tid: string;\n\tkind: 'external';\n\t/** App-owned locator for re-deriving the secret (say, a WebAuthn\n\t * credential id). Cleartext, never a security input. */\n\tkeyRef: string;\n\t/** 96-bit IV of the wrap, base64. */\n\tiv: string;\n\t/** AES-256-GCM(KEK, dataKey) with tag appended: 48 bytes, base64. */\n\twrapped: string;\n}\n\nexport type KeySlot = PasswordSlot | ExternalSlot;\n\n/**\n * Group mode (format 2): the per-publication AES key wrapped for one\n * recipient. `kid` = first 8 bytes of SHA-256(recipient X25519 public),\n * base64 - a locator, not a name. `epk` is the ephemeral X25519 public;\n * `wrap` is AES-256-GCM(dataKey) under HKDF of the ECDH shared secret.\n */\nexport interface RecipientStanza {\n\tkid: string;\n\tepk: string;\n\tiv: string;\n\twrap: string;\n}\n\n/**\n * Cleartext metadata: the `meta.json` entry of the ZIP.\n *\n * app/appVersion/createdAt are cosmetic and unauthenticated - never base a\n * security decision on them. In password-envelope mode the wrapped data key\n * authenticates the payload; in group mode the author's Ed25519 signature\n * (sig.bin) covers the exact meta.json and data.enc bytes.\n */\nexport interface Header {\n\t/** Format generation: 2 = plain ZIP, 3 = group, 4 = password envelope.\n\t * Absent means 2. */\n\tformat?: number;\n\tapp: string;\n\t/** Writing app's release version, informational. */\n\tappVersion?: string;\n\t/** Writing app's data schema version (createLocalStore `version`).\n\t * Distinct from appVersion: this one drives migration. */\n\tschemaVersion?: number;\n\tcreatedAt: string;\n\tencryption: 'none' | 'aes-256-gcm';\n\t/** 96-bit IV of data.enc, base64. Present when encrypted. */\n\tiv?: string;\n\t/** Group mode: data-key envelope scheme ('x25519-hkdf-sha256'). */\n\tkeying?: string;\n\t/** Group mode: author's Ed25519 public key. Trust only after verifying\n\t * sig.bin and membership in the group manifest. */\n\tauthor?: string;\n\t/** Group mode: one data-key envelope per recipient. */\n\trecipients?: RecipientStanza[];\n\t/** Password envelope only: the data key wrapped once per password.\n\t * Present iff format === 4. */\n\tkeys?: KeySlot[];\n}\n\n/** Options for writing a backup. */\nexport interface EncodeOptions {\n\tapp: string;\n\tappVersion?: string;\n\tschemaVersion?: number;\n\t/** Omit or leave empty for an unencrypted backup (a plain, readable ZIP). */\n\tpassword?: string;\n\t/** Group mode: encrypt to these recipients (raw X25519 publics, base64)\n\t * under a fresh data key and sign with the author's Ed25519 key.\n\t * Mutually exclusive with `password`. */\n\tgroup?: {\n\t\trecipients: string[];\n\t\tsign: { pub: string; priv: string };\n\t};\n\t/** README text shipped inside an encrypted backup, for whoever opens the\n\t * ZIP by hand. Defaults to a neutral note; apps should brand it. */\n\treadme?: string;\n\t/** Rewrite path: reuse this exact envelope (held data key + slot table\n\t * from the last read) so a writer that knows only one password keeps\n\t * every other slot. Mutually exclusive with `password` and `group`. */\n\tenvelope?: { dataKey: Uint8Array; slots: KeySlot[] };\n}\n","// A password strength policy the store can enforce and a UI can preview from\n// the same rules. Deliberately small: length plus character-class requirements,\n// no dictionary or breach checks (those need data the library does not ship).\n// Unicode-aware so an accented letter counts as a letter and an emoji counts as\n// one character, not two.\n\nexport interface PasswordPolicy {\n\t/** Minimum length in code points (so an emoji counts as one). Default 0. */\n\tminLength?: number;\n\t/** Require at least one lowercase letter (any script with case). */\n\trequireLowercase?: boolean;\n\t/** Require at least one uppercase letter (any script with case). */\n\trequireUppercase?: boolean;\n\t/** Require at least one digit. */\n\trequireDigit?: boolean;\n\t/** Require at least one symbol: anything that is not a letter or a number. */\n\trequireSymbol?: boolean;\n}\n\n/** A stable code for each unmet requirement, so the app maps it to its own copy\n * (like the error codes). `minLength` covers the length rule. */\nexport type PasswordRequirement = 'minLength' | 'lowercase' | 'uppercase' | 'digit' | 'symbol';\n\nexport interface PasswordCheck {\n\tok: boolean;\n\t/** The requirements the password fails, in a stable order. Empty when ok. */\n\tunmet: PasswordRequirement[];\n}\n\n/** Measure a password against a policy. Pure and synchronous: the same call\n * drives a live strength hint in the UI and the store's enforcement. An empty\n * or absent policy passes everything. */\nexport function checkPasswordPolicy(password: string, policy: PasswordPolicy): PasswordCheck {\n\tconst unmet: PasswordRequirement[] = [];\n\t// Count code points, not UTF-16 units, so a password of emoji is not\n\t// over-counted and a min-length rule stays intuitive.\n\tif ([...password].length < (policy.minLength ?? 0)) unmet.push('minLength');\n\tif (policy.requireLowercase && !/\\p{Ll}/u.test(password)) unmet.push('lowercase');\n\tif (policy.requireUppercase && !/\\p{Lu}/u.test(password)) unmet.push('uppercase');\n\tif (policy.requireDigit && !/\\p{Nd}/u.test(password)) unmet.push('digit');\n\tif (policy.requireSymbol && !/[^\\p{L}\\p{N}]/u.test(password)) unmet.push('symbol');\n\treturn { ok: unmet.length === 0, unmet };\n}\n","// Fluent facade over the functional API. The chain is staged so an illegal\n// call order does not compile: backup() exposes only .as(), and .withReadme()\n// appears only after .encryptedWith() (the readme ships inside the encrypted\n// ZIP, so it means nothing on a plain one).\n//\n// const blob = await backup(snapshot).as('my-app', '1.2.0').encryptedWith(pw).toBlob();\n// const snap = await restore(file).withPassword(pw).read();\n\nimport type { Snapshot, Header, EncodeOptions } from './types';\nimport { RESERVED_COLLECTION_PREFIX } from './types';\nimport { writeBox, readBox, readBoxMeta, asBytes, BACKUP_MIME, BACKUP_EXTENSION } from './box';\n\n/** Start writing a backup. Naming the app via .as() is the required next step. */\nexport function backup(snapshot: Snapshot): BackupDraft {\n\treturn new BackupDraft(snapshot);\n}\n\n/** Start reading a backup (a picked File, a fetched Blob, or raw bytes). */\nexport function restore(input: Blob | Uint8Array): RestoreBuilder {\n\treturn new RestoreBuilder(input);\n}\n\n// Validation lives in the constructor, not the factory, so direct\n// construction cannot bypass it.\nexport class BackupDraft {\n\tconstructor(private readonly snapshot: Snapshot) {\n\t\tfor (const name of Object.keys(snapshot.collections)) {\n\t\t\tif (name.startsWith(RESERVED_COLLECTION_PREFIX)) {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`backup(): collection \"${name}\" uses the reserved \"${RESERVED_COLLECTION_PREFIX}\" prefix (library bookkeeping) - rename it`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Name the writing app (stored cleartext in the backup's metadata). */\n\tas(app: string, appVersion?: string): BackupBuilder {\n\t\treturn new BackupBuilder(this.snapshot, { app, appVersion });\n\t}\n}\n\nexport class BackupBuilder {\n\tconstructor(\n\t\tprotected readonly snapshot: Snapshot,\n\t\tprotected readonly opts: EncodeOptions\n\t) {}\n\n\t/** Encrypt the backup (AES-256-GCM over an Argon2id-derived key). */\n\tencryptedWith(password: string): EncryptedBackupBuilder {\n\t\treturn new EncryptedBackupBuilder(this.snapshot, { ...this.opts, password });\n\t}\n\n\t/** The backup as raw bytes. */\n\tasync toBytes(): Promise<Uint8Array> {\n\t\treturn writeBox(this.snapshot, this.opts);\n\t}\n\n\t/** The backup as a Blob, ready to upload or hand to a save dialog. */\n\tasync toBlob(): Promise<Blob> {\n\t\treturn new Blob([(await this.toBytes()) as BlobPart], { type: BACKUP_MIME });\n\t}\n\n\t/** Save the backup to disk (File System Access API, else a download).\n\t * Browser-only terminal; defaults to `<app>-<date>.zip`. False when the\n\t * user closed the save dialog: nothing was written, so do not tell them\n\t * they have a backup.\n\t *\n\t * Asks WHERE first, encrypts after. The save dialog needs the transient\n\t * activation of the click that led here, and building an encrypted backup\n\t * outlives it (Argon2id is deliberately slow): encrypting first made the\n\t * browser refuse the dialog and silently download instead, turning a file\n\t * the user chose into one they have to go and find. */\n\tasync toDisk(filename?: string): Promise<boolean> {\n\t\tconst name =\n\t\t\tfilename ?? `${this.opts.app}-${new Date().toISOString().slice(0, 10)}${BACKUP_EXTENSION}`;\n\t\tconst { pickSaveHandle, writeToHandle, downloadBlob } = await import('./targets/local');\n\t\tconst cible = await pickSaveHandle(name);\n\t\tif (cible === 'CANCELLED') return false;\n\t\tconst blob = await this.toBlob();\n\t\tif (cible) {\n\t\t\tawait writeToHandle(cible.handle, blob);\n\t\t\treturn true;\n\t\t}\n\t\tdownloadBlob(blob, name);\n\t\treturn true;\n\t}\n}\n\nexport class EncryptedBackupBuilder extends BackupBuilder {\n\tconstructor(snapshot: Snapshot, opts: EncodeOptions) {\n\t\tif (!opts.password) {\n\t\t\tthrow new TypeError(\n\t\t\t\t'EncryptedBackupBuilder: a password is required - use backup(snapshot).as(app).encryptedWith(password)'\n\t\t\t);\n\t\t}\n\t\tsuper(snapshot, opts);\n\t}\n\n\t/** Brand the README shipped inside the encrypted ZIP. */\n\twithReadme(text: string): EncryptedBackupBuilder {\n\t\treturn new EncryptedBackupBuilder(this.snapshot, { ...this.opts, readme: text });\n\t}\n}\n\nexport class RestoreBuilder {\n\tprivate password?: string;\n\n\tconstructor(private readonly input: Blob | Uint8Array) {}\n\n\t/** Accepts undefined so callers can pass straight through from an optional field. */\n\twithPassword(password?: string): this {\n\t\tthis.password = password || undefined;\n\t\treturn this;\n\t}\n\n\t/** The cleartext metadata (app, date, encryption), without decrypting. */\n\tasync meta(): Promise<Header> {\n\t\treturn readBoxMeta(await asBytes(this.input));\n\t}\n\n\t/** True if reading will require a password. */\n\tasync isEncrypted(): Promise<boolean> {\n\t\treturn (await this.meta()).encryption !== 'none';\n\t}\n\n\t/** Read the backup into a snapshot. Reserved `__*` collections (library\n\t * bookkeeping) are stripped. PASSWORD_REQUIRED when encrypted and no\n\t * password given, DECRYPT_FAILED on a wrong one. */\n\tasync read(): Promise<Snapshot> {\n\t\tconst snap = await readBox(await asBytes(this.input), this.password);\n\t\tconst collections = Object.fromEntries(\n\t\t\tObject.entries(snap.collections).filter(\n\t\t\t\t([name]) => !name.startsWith(RESERVED_COLLECTION_PREFIX)\n\t\t\t)\n\t\t);\n\t\treturn { collections, files: snap.files };\n\t}\n}\n","// The backup format: Snapshot in, portable ZIP out, and back. Plain archive\n// without a password, AES-256-GCM (over Argon2id) with one.\n//\n// const blob = await exportSnapshot(snapshot, { app: 'my-app', password });\n// const back = await importSnapshot(blob, { password });\n//\n// or fluent, same engine:\n//\n// const blob = await backup(snapshot).as('my-app').encryptedWith(password).toBlob();\n// const back = await restore(blob).withPassword(password).read();\n\nimport type { Snapshot, Header, EncodeOptions } from './types';\nimport { writeBox, readBox, readBoxMeta, asBytes } from './box';\n\nexport type {\n\tSnapshot,\n\tSnapshotFile,\n\tHeader,\n\tKdfParams,\n\tRecipientStanza,\n\tEncodeOptions,\n\tPasswordSlot,\n\tExternalSlot,\n\tKeySlot\n} from './types';\nexport { RESERVED_COLLECTION_PREFIX } from './types';\nexport {\n\tSelfstoreError,\n\tAuthExpiredError,\n\tisSelfstoreError,\n\tisAuthExpired,\n\terrorLabelKey,\n\ttype SelfstoreErrorCode\n} from './errors';\nexport { BACKUP_EXTENSION, BACKUP_MIME } from './box';\nexport {\n\tcheckPasswordPolicy,\n\ttype PasswordPolicy,\n\ttype PasswordCheck,\n\ttype PasswordRequirement\n} from './password-policy';\nexport {\n\tbackup,\n\trestore,\n\ttype BackupDraft,\n\ttype BackupBuilder,\n\ttype EncryptedBackupBuilder,\n\ttype RestoreBuilder\n} from './fluent';\n\n/** Serialize a snapshot to a portable backup blob (compressed; encrypted if a password is given). */\nexport async function exportSnapshot(snapshot: Snapshot, opts: EncodeOptions): Promise<Blob> {\n\treturn new Blob([(await writeBox(snapshot, opts)) as BlobPart], { type: 'application/zip' });\n}\n\n/** Read a backup blob (or raw bytes) back into a snapshot. */\nexport async function importSnapshot(\n\tinput: Blob | Uint8Array,\n\topts: { password?: string } = {}\n): Promise<Snapshot> {\n\treturn readBox(await asBytes(input), opts.password);\n}\n\n/** Peek at a backup's cleartext metadata (app, date, whether it's encrypted) without decrypting. */\nexport async function inspect(input: Blob | Uint8Array): Promise<Header> {\n\treturn readBoxMeta(await asBytes(input));\n}\n\n/** True if the backup needs a password to import. */\nexport async function isEncrypted(input: Blob | Uint8Array): Promise<boolean> {\n\treturn (await inspect(input)).encryption !== 'none';\n}\n\n/** Re-encrypt under a new password. `from` opens the file, `to` protects the\n * result; omit `to` for an unencrypted backup. */\nexport async function changePassword(\n\tinput: Blob | Uint8Array,\n\topts: { from?: string; to?: string; readme?: string }\n): Promise<Blob> {\n\tconst bytes = await asBytes(input);\n\tconst meta = await readBoxMeta(bytes);\n\tconst snapshot = await readBox(bytes, opts.from);\n\treturn exportSnapshot(snapshot, {\n\t\tapp: meta.app,\n\t\tappVersion: meta.appVersion,\n\t\tschemaVersion: meta.schemaVersion,\n\t\tpassword: opts.to,\n\t\treadme: opts.readme\n\t});\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createNode, createMeta, gcTombstones, stamp, merge, unsyncableCounts, idPathFor, detectConflicts, changes } from './chunk-SKWHKM25.js';
|
|
2
|
-
import { inspect, checkPasswordPolicy, writeBox, BACKUP_MIME, readBoxWithSync, asBytes } from './chunk-
|
|
2
|
+
import { inspect, checkPasswordPolicy, writeBox, BACKUP_MIME, readBoxWithSync, asBytes } from './chunk-2JJYLXAC.js';
|
|
3
3
|
import { openManifest, GROUP_KEYING } from './chunk-KHER6MWR.js';
|
|
4
4
|
import { seal, isEnvelope, unseal, newDeviceKey } from './chunk-QBCU7OOP.js';
|
|
5
5
|
import { mintSlot, MAX_KEY_SLOTS, mintExternalSlot, openSlot } from './chunk-6746AL4I.js';
|
|
@@ -2028,5 +2028,5 @@ function gisDriveAuth(opts) {
|
|
|
2028
2028
|
}
|
|
2029
2029
|
|
|
2030
2030
|
export { RESERVED_STORE_MODES, createLocalStore, deriveStatus, gisDriveAuth, indexedDbCache, isLockableCache, isReservedStoreMode, memoryCache };
|
|
2031
|
-
//# sourceMappingURL=chunk-
|
|
2032
|
-
//# sourceMappingURL=chunk-
|
|
2031
|
+
//# sourceMappingURL=chunk-5QGCGAAI.js.map
|
|
2032
|
+
//# sourceMappingURL=chunk-5QGCGAAI.js.map
|