selfstore 1.8.6 → 1.8.8

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/simple/simple.ts"],"names":["fromSession","connect"],"mappings":"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","file":"index.js","sourcesContent":["// The simple store: one call, sensible defaults, and the store owns the data.\n//\n// const store = await selfstore('notes-app');\n// await store.put('todos', { id: 't1', text: 'hello' });\n// store.onChange(render);\n//\n// Convention over configuration: schema version 1, an IndexedDB cache named\n// after the app (in-memory where IndexedDB does not exist, so tests and SSR\n// just work), debounced auto-save, and the browser sync moments wired.\n// Every default has an option; everything deeper lives on store.advanced -\n// the full createLocalStore, same instance.\n//\n// One rule is enforced rather than documented: records need a non-empty\n// string id (the merge identifies records by it), so put() throws a\n// TypeError right away. The advanced pull-model store only logs - it cannot\n// know which collections an app considers mergeable.\n\nimport {\n\tcreateLocalStore,\n\ttype LocalStore,\n\ttype LocalStoreState,\n\ttype StoreError\n} from '../persistence/store';\nimport {\n\tindexedDbCache,\n\tmemoryCache,\n\tisLockableCache,\n\ttype KV,\n\ttype LocalCache\n} from '../persistence/cache';\nimport type { BackupTarget } from '../persistence/target';\nimport type { StatusDescriptor } from '../persistence/status';\nimport type { SyncConfig } from '../sync';\nimport type { Snapshot, SnapshotFile } from '../selfstore/types';\nimport { SelfstoreError } from '../selfstore/errors';\nimport { restore, type PasswordPolicy } from '../selfstore';\nimport { saveToDisk } from '../selfstore/targets/local';\nimport {\n\tconnect as driveConnect,\n\tfromSession as driveFromSession,\n\ttype DriveAuth\n} from '../persistence/targets/drive';\nimport {\n\tconnect as fileConnect,\n\tfromSession as fileFromSession,\n\tisSupported as fileIsSupported\n} from '../persistence/targets/file';\nimport {\n\tconnect as webdavConnect,\n\tfromSession as webdavFromSession,\n\ttype WebdavConfig\n} from '../persistence/targets/webdav';\nimport { connect as s3Connect, type S3Config } from '../persistence/targets/s3';\n\n/** A record as the simple store sees it: plain JSON with a string id (the id\n * field name can be remapped per collection via `sync.ids`). */\nexport type SimpleRecord = Record<string, unknown>;\n\n/** Unlock callback for the ultra-sensitive cacheLock mode: return the session\n * secret - a password (Argon2id-derived) or an app-provided key (e.g. a passkey\n * PRF result). Called at boot; called again with { failed: true } after a wrong\n * secret so the app can re-prompt. Throw to abort the boot (user cancelled). */\nexport type CacheUnlock = (attempt: { failed: boolean }) => Promise<string | CryptoKey>;\n\n/** Options - every one of them optional, the defaults carry a real app. */\nexport interface SimpleOptions {\n\t/** Your DATA schema version (default 1). Bump it together with `migrate`. */\n\tschema?: number;\n\t/** Upgrade a snapshot written by an older schema version. */\n\tmigrate?: (fromVersion: number, snap: Snapshot) => Snapshot;\n\t/** Per-collection merge tuning (id field mapping, strategies). The default -\n\t * records keyed by `id`, later edit wins, deletes propagate - fits most apps. */\n\tsync?: SyncConfig;\n\t/** Google Drive auth, when this app uses Drive: providing it here lets a\n\t * connected Drive backup restore itself on the next start. */\n\tdrive?: DriveAuth;\n\t/** Where the working copy lives (default: IndexedDB named after the app;\n\t * in-memory when IndexedDB does not exist, e.g. tests or SSR). */\n\tcache?: LocalCache;\n\t/** Auto-save debounce in ms. */\n\tdebounceMs?: number;\n\t/** Cross-tab coordination (default on in browsers). */\n\tmultiTab?: boolean;\n\t/** Refuse to ever write or export a plaintext backup: connecting a\n\t * destination then demands a password (or a group). Off by default. */\n\trequireEncryption?: boolean;\n\t/** Reject a backup password weaker than this policy (length, character\n\t * classes) at protect()/addKey time. Preview the rules with\n\t * checkPasswordPolicy for a live UI hint. Omit for no policy. */\n\tpasswordPolicy?: PasswordPolicy;\n\t/** Ultra-sensitive mode: seal the local cache under a key derived from a\n\t * secret held in memory (this callback), never on disk - so a copy of the\n\t * browser profile cannot read it. One unlock per session; branch it on the\n\t * app's existing login to leave the UX unchanged. Browser (IndexedDB) only. */\n\tcacheLock?: CacheUnlock;\n\t/** Wire tab focus / network return / interval / tab hide automatically\n\t * (default true in browsers). Pass false to drive syncing yourself. */\n\tautoSync?: boolean;\n}\n\n/** What connecting a destination did. 'merged': it already held a backup and\n * both sides were folded together. 'started': it was empty, this device's data\n * is now its content. 'manual': non-Chromium file fallback - offer\n * downloadBackup() instead. 'cancelled': the user closed the picker/consent. */\nexport type ConnectOutcome = 'merged' | 'started' | 'manual' | 'cancelled';\n\nexport interface SimpleStore<\n\tS extends Record<string, SimpleRecord> = Record<string, SimpleRecord>\n> {\n\t// --- Your data ---------------------------------------------------------\n\t/** Every record of a collection (treat as read-only; write via put/remove). */\n\tall<K extends keyof S & string>(collection: K): readonly S[K][];\n\t/** One record by id, or undefined. */\n\tget<K extends keyof S & string>(collection: K, id: string): S[K] | undefined;\n\t/** Insert or replace one record (auto-saves, debounced). Throws a TypeError\n\t * when the record has no non-empty string id. */\n\tput<K extends keyof S & string>(collection: K, record: S[K]): Promise<void>;\n\t/** Insert or replace many records in one save. */\n\tputAll<K extends keyof S & string>(collection: K, records: S[K][]): Promise<void>;\n\t/** Delete one record by id (propagates to other devices). Unknown id: no-op. */\n\tremove<K extends keyof S & string>(collection: K, id: string): Promise<void>;\n\t/** Empty a collection (every removal propagates). */\n\tclear<K extends keyof S & string>(collection: K): Promise<void>;\n\t/** Called after any data change: your writes, another tab, another device,\n\t * a restore. Returns an unsubscribe. */\n\tonChange(fn: () => void): () => void;\n\n\t// --- Where it lives ----------------------------------------------------\n\t/** Connect Google Drive as the durable home. An existing backup there is\n\t * MERGED with this device (multi-device); an encrypted one needs its\n\t * password up front (PASSWORD_REQUIRED is thrown before anything changes). */\n\tconnectDrive(auth: DriveAuth, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect a disk file (File System Access; falls back to manual download). */\n\tconnectFile(opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect a WebDAV server (Nextcloud, ownCloud, your own). */\n\tconnectWebdav(config: WebdavConfig, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect an S3-compatible bucket you control (Amazon S3, R2, B2, MinIO). */\n\tconnectS3(config: S3Config, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect any custom BackupTarget with the same merge semantics. */\n\tconnectTarget(target: BackupTarget, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Back to device-only (the destination keeps its last backup). */\n\tdisconnect(): Promise<void>;\n\n\t// --- Backup copy (replica) ---------------------------------------------\n\t/** Also write the same encrypted backup to this second destination on\n\t * every save. A broken copy never gates the store (state.replicas). */\n\taddReplica(target: BackupTarget, opts?: { id?: string }): string;\n\t/** Stop writing the copy (the destination keeps its last backup). */\n\tremoveReplica(id: string): void;\n\n\t// --- Protection & the two gate gestures --------------------------------\n\t/** Encrypt the durable backup end to end with this password (reversible). */\n\tprotect(password: string): Promise<void>;\n\t/** Remove the backup password. */\n\tunprotect(): Promise<void>;\n\t/** status.action === 'unlock': supply the password to resume. */\n\tunlock(password: string): Promise<boolean>;\n\t/** status.action === 'reconnect': re-run the destination's auth gesture. */\n\treconnect(): Promise<boolean>;\n\n\t// --- Portable backups ---------------------------------------------------\n\t/** The portable backup file (a real ZIP; encrypted when protect() is on). */\n\texportBackup(): Promise<Blob>;\n\t/** Download the backup (also resolves the 'manual' file mode's pending flag).\n\t * False when the user closed the save dialog: nothing was written, the\n\t * pending flag stands, and the app must not record a backup. */\n\tdownloadBackup(filename?: string): Promise<boolean>;\n\t/** Load a backup file into this store, replacing the local data (removals\n\t * propagate like edits). Throws PASSWORD_REQUIRED / DECRYPT_FAILED. */\n\timportBackup(file: Blob | Uint8Array, opts?: { password?: string }): Promise<void>;\n\n\t// --- Observability ------------------------------------------------------\n\t/** Headless status: { state, severity, action, labelKey } - map labelKey to\n\t * your own copy. */\n\treadonly status: StatusDescriptor;\n\t/** The last problem: { code, labelKey, message } - show labelKey, log message. */\n\treadonly error: StoreError | null;\n\t/** The full underlying state (advanced reads: journal, peers, mode...). */\n\treadonly state: LocalStoreState;\n\t/** Fires on any state change (status flips included) - for framework bindings. */\n\tsubscribe(fn: () => void): () => void;\n\n\t// --- Lifecycle ----------------------------------------------------------\n\t/** Save now (called for you on tab hide when autoSync is on). */\n\tflush(): Promise<void>;\n\t/** Converge with the destination now (a user gesture like pull-to-refresh). */\n\tsync(): Promise<void>;\n\t/** Drop timers and listeners (tests, SPA teardown). */\n\tdispose(): void;\n\n\t/** The escape hatch: the full advanced store this simple one is built on -\n\t * peers, groups, custom strategies, everything (see selfstore/advanced). */\n\treadonly advanced: LocalStore;\n\n\t/** The attachment point for 'selfstore/flows': the engine plus the cache KV\n\t * and backup file name a flow needs to build destination targets. Apps on\n\t * the advanced store hand a flow the same three by themselves. */\n\treadonly flowHost: { engine: LocalStore; kv: KV; backupName: string };\n}\n\n/** The id field a collection's records are keyed by: `sync.ids` may remap it;\n * a DOTTED path (nested id) is an advanced setup the simple check skips. */\nfunction idFieldOf(sync: SyncConfig | undefined, collection: string): string | null {\n\tconst mapped = sync?.ids?.[collection];\n\tif (mapped == null) return 'id';\n\treturn mapped.includes('.') ? null : mapped;\n}\n\nfunction requireStringId(record: SimpleRecord, field: string | null, collection: string): string {\n\tif (field === null) return ''; // nested-path ids: validated by the engine's own rules\n\tconst id = record[field];\n\tif (typeof id !== 'string' || id.length === 0) {\n\t\tthrow new TypeError(\n\t\t\t`selfstore: a record in \"${collection}\" needs a non-empty STRING \"${field}\" ` +\n\t\t\t\t`(got ${JSON.stringify(id)}). String ids are what the multi-device merge keys on; ` +\n\t\t\t\t`map another field with { sync: { ids: { ${collection}: 'yourField' } } }.`\n\t\t);\n\t}\n\treturn id;\n}\n\n/** True when a browser IndexedDB is available (SSR and plain Node lack it). */\nfunction hasIndexedDb(): boolean {\n\treturn typeof indexedDB !== 'undefined';\n}\n\n/**\n * Open (or create) the app's local store. Awaits the initial load, so the\n * returned store is ready: data readable, destination restored, first converge\n * done. See SimpleOptions for the defaults.\n */\nexport async function selfstore<\n\tS extends Record<string, SimpleRecord> = Record<string, SimpleRecord>\n>(app: string, options: SimpleOptions = {}): Promise<SimpleStore<S>> {\n\tif (typeof app !== 'string' || app.length === 0) {\n\t\tthrow new TypeError('selfstore: pass your app name, e.g. selfstore(\"my-app\").');\n\t}\n\n\t// The one copy of the data. The engine pulls it on save (gather) and pushes\n\t// into it on restores/folds (apply); the facade's mutators edit it in place\n\t// copy-on-write and schedule a save.\n\tlet collections: Record<string, SimpleRecord[]> = {};\n\t// Binary files ride along untouched (a backup that carries them keeps them);\n\t// managing them is an advanced-store concern.\n\tlet files: SnapshotFile[] = [];\n\n\tconst dataSubs = new Set<() => void>();\n\tconst emitData = (): void => dataSubs.forEach((fn) => fn());\n\n\tconst cache =\n\t\toptions.cache ??\n\t\t(hasIndexedDb()\n\t\t\t? indexedDbCache(app, options.cacheLock ? { lock: true } : undefined)\n\t\t\t: memoryCache());\n\tconst backupName = `${app}.zip`;\n\t// connectDrive() remembers the auth so a later restoreTarget can use it even\n\t// when options.drive was not provided up front (same session only).\n\tlet driveAuth: DriveAuth | null = options.drive ?? null;\n\n\t// Ultra-sensitive: unlock the cache before the store hydrates from it. One\n\t// prompt per session, driven by the app (branch it on an existing login to\n\t// keep the UX unchanged). A wrong secret re-prompts; throw to abort.\n\tif (options.cacheLock && isLockableCache(cache)) {\n\t\tlet failed = false;\n\t\twhile (!(await cache.unlock(await options.cacheLock({ failed })))) failed = true;\n\t}\n\n\tconst store = createLocalStore({\n\t\tapp,\n\t\tschemaVersion: options.schema ?? 1,\n\t\tgather: (): Snapshot => structuredClone({ collections, files }),\n\t\tapply: (snap: Snapshot): void => {\n\t\t\tcollections = (snap.collections ?? {}) as Record<string, SimpleRecord[]>;\n\t\t\tfiles = snap.files ?? [];\n\t\t\temitData();\n\t\t},\n\t\tmigrate: options.migrate,\n\t\tsync: options.sync,\n\t\tcache,\n\t\tdebounceMs: options.debounceMs,\n\t\tmultiTab: options.multiTab,\n\t\trequireEncryption: options.requireEncryption,\n\t\tpasswordPolicy: options.passwordPolicy,\n\t\trestoreTarget: async (kind) => {\n\t\t\tif (kind === 'drive' && driveAuth) {\n\t\t\t\treturn driveFromSession({ auth: driveAuth, kv: cache.kv, fileName: backupName });\n\t\t\t}\n\t\t\tif (kind === 'file') return fileFromSession({ kv: cache.kv });\n\t\t\tif (kind === 'webdav') return webdavFromSession({ kv: cache.kv });\n\t\t\treturn null;\n\t\t}\n\t});\n\n\tawait store.init();\n\n\t// A degraded file mode is a verdict about the BROWSER, but it was persisted\n\t// like a property of the data: every later session re-read the word without\n\t// ever asking again. One session that could not open a picker - a browser\n\t// that ships the API and refuses it, a call made a moment too late, a user on\n\t// another browser that day - then pinned download-only mode forever, on a\n\t// Chromium perfectly able to hold a file, with no way back.\n\t//\n\t// Nothing writes this word except a picker that could not deliver, so a\n\t// browser that CAN deliver makes it stale. Re-examined here, in the layer\n\t// that wrote it. Dropping to 'device' is the honest state: manual mode had\n\t// already released the durable target, so there is nothing to detach - only\n\t// a stale claim to stop repeating, and a destination the host can offer again.\n\tif (store.state.targetKind === 'file-manual' && fileIsSupported()) {\n\t\tawait store.detachTarget();\n\t}\n\n\t// Auto-wired sync moments (Spring-Boot-style autoconfiguration): tab focus,\n\t// network return, a slow interval, and save-on-hide. Opt out with\n\t// { autoSync: false } to drive these yourself.\n\tconst teardown: (() => void)[] = [];\n\tif (\n\t\toptions.autoSync !== false &&\n\t\ttypeof document !== 'undefined' &&\n\t\ttypeof window !== 'undefined'\n\t) {\n\t\tconst onVisibility = (): void => {\n\t\t\tif (document.visibilityState === 'hidden') void store.flush();\n\t\t\telse void store.syncIfStale('focus');\n\t\t};\n\t\tconst onOnline = (): void => void store.syncIfStale('online');\n\t\tconst onPageHide = (): void => void store.flush();\n\t\tconst interval = setInterval(() => {\n\t\t\tif (document.visibilityState === 'visible') void store.syncIfStale('interval');\n\t\t}, 5 * 60_000);\n\t\tdocument.addEventListener('visibilitychange', onVisibility);\n\t\twindow.addEventListener('online', onOnline);\n\t\twindow.addEventListener('pagehide', onPageHide);\n\t\tteardown.push(() => {\n\t\t\tclearInterval(interval);\n\t\t\tdocument.removeEventListener('visibilitychange', onVisibility);\n\t\t\twindow.removeEventListener('online', onOnline);\n\t\t\twindow.removeEventListener('pagehide', onPageHide);\n\t\t});\n\t}\n\n\tfunction mutate(collection: string, next: SimpleRecord[]): Promise<void> {\n\t\tcollections = { ...collections, [collection]: next };\n\t\temitData();\n\t\tstore.schedule();\n\t\treturn Promise.resolve();\n\t}\n\n\tasync function connectTarget(\n\t\ttarget: BackupTarget,\n\t\topts: { password?: string } = {}\n\t): Promise<ConnectOutcome> {\n\t\tconst info = await store.inspectTarget(target);\n\t\tif (info.hasBackup) {\n\t\t\t// Another app's backup is refused BEFORE the password question: asking\n\t\t\t// first teaches the user their password \"does not work\" on a file that\n\t\t\t// was never this app's to open.\n\t\t\tif (info.app !== null && info.app !== store.app) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'FOREIGN_BACKUP',\n\t\t\t\t\t`This destination holds a backup written by app \"${info.app}\", not \"${store.app}\". Open it in its own application, or pick another file.`\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Fail before attaching: an encrypted backup without its password would\n\t\t\t// otherwise attach locked, which is a support case, not an outcome.\n\t\t\tif (info.encrypted && !opts.password) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'PASSWORD_REQUIRED',\n\t\t\t\t\t'This destination holds an encrypted backup: pass its password to connect.'\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait store.attachTarget(target, { password: opts.password ?? null, strategy: 'merge' });\n\t\t\treturn 'merged';\n\t\t}\n\t\tawait store.attachTarget(target, {\n\t\t\tpassword: opts.password ?? null,\n\t\t\tstrategy: 'replace-remote'\n\t\t});\n\t\treturn 'started';\n\t}\n\n\tconst simple: SimpleStore<S> = {\n\t\tall<K extends keyof S & string>(collection: K): readonly S[K][] {\n\t\t\treturn (collections[collection] ?? []) as S[K][];\n\t\t},\n\t\tget<K extends keyof S & string>(collection: K, id: string): S[K] | undefined {\n\t\t\tconst field = idFieldOf(options.sync, collection) ?? 'id';\n\t\t\treturn (collections[collection] ?? []).find((r) => r[field] === id) as S[K] | undefined;\n\t\t},\n\t\tput<K extends keyof S & string>(collection: K, record: S[K]): Promise<void> {\n\t\t\tconst field = idFieldOf(options.sync, collection);\n\t\t\tconst id = requireStringId(record, field, collection);\n\t\t\tconst rows = collections[collection] ?? [];\n\t\t\tconst at = field === null ? -1 : rows.findIndex((r) => r[field] === id);\n\t\t\treturn mutate(\n\t\t\t\tcollection,\n\t\t\t\tat === -1 ? [...rows, record] : rows.map((r, i) => (i === at ? record : r))\n\t\t\t);\n\t\t},\n\t\tputAll<K extends keyof S & string>(collection: K, records: S[K][]): Promise<void> {\n\t\t\tconst field = idFieldOf(options.sync, collection);\n\t\t\tconst byId = new Map<unknown, number>();\n\t\t\tfor (const r of records) requireStringId(r, field, collection);\n\t\t\tconst rows = [...(collections[collection] ?? [])];\n\t\t\tif (field !== null) {\n\t\t\t\trows.forEach((r, i) => byId.set(r[field], i));\n\t\t\t\tfor (const r of records) {\n\t\t\t\t\tconst at = byId.get(r[field]);\n\t\t\t\t\tif (typeof at === 'number') rows[at] = r;\n\t\t\t\t\telse rows.push(r);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trows.push(...records);\n\t\t\t}\n\t\t\treturn mutate(collection, rows);\n\t\t},\n\t\tremove<K extends keyof S & string>(collection: K, id: string): Promise<void> {\n\t\t\tconst field = idFieldOf(options.sync, collection) ?? 'id';\n\t\t\tconst rows = collections[collection] ?? [];\n\t\t\tconst next = rows.filter((r) => r[field] !== id);\n\t\t\treturn next.length === rows.length ? Promise.resolve() : mutate(collection, next);\n\t\t},\n\t\tclear<K extends keyof S & string>(collection: K): Promise<void> {\n\t\t\tif ((collections[collection] ?? []).length === 0) return Promise.resolve();\n\t\t\treturn mutate(collection, []);\n\t\t},\n\t\tonChange(fn: () => void): () => void {\n\t\t\tdataSubs.add(fn);\n\t\t\treturn () => dataSubs.delete(fn);\n\t\t},\n\n\t\tasync connectDrive(auth: DriveAuth, opts?: { password?: string }): Promise<ConnectOutcome> {\n\t\t\tdriveAuth = auth;\n\t\t\tconst target = await driveConnect({ auth, kv: cache.kv, fileName: backupName });\n\t\t\tif (!target) return 'cancelled';\n\t\t\treturn connectTarget(target, opts);\n\t\t},\n\t\tasync connectFile(opts?: { password?: string }): Promise<ConnectOutcome> {\n\t\t\t// Asked twice on purpose: the first call answers from what the browser\n\t\t\t// exposes, the second from what it did when actually asked. A browser\n\t\t\t// that ships the picker and then refuses it only tells us so here.\n\t\t\tif (fileIsSupported()) {\n\t\t\t\tconst target = await fileConnect({ kv: cache.kv, fileName: backupName });\n\t\t\t\tif (target) return connectTarget(target, opts);\n\t\t\t\tif (fileIsSupported()) return 'cancelled';\n\t\t\t}\n\t\t\tawait store.setManualFile();\n\t\t\treturn 'manual';\n\t\t},\n\t\tasync connectWebdav(\n\t\t\tconfig: WebdavConfig,\n\t\t\topts?: { password?: string }\n\t\t): Promise<ConnectOutcome> {\n\t\t\tconst target = await webdavConnect({ kv: cache.kv, config });\n\t\t\tif (!target) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'TARGET_UNAVAILABLE',\n\t\t\t\t\t'The WebDAV server did not answer (URL, credentials or CORS).'\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn connectTarget(target, opts);\n\t\t},\n\t\tasync connectS3(config: S3Config, opts?: { password?: string }): Promise<ConnectOutcome> {\n\t\t\tconst target = await s3Connect({ kv: cache.kv, config });\n\t\t\tif (!target) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'TARGET_UNAVAILABLE',\n\t\t\t\t\t'The S3 endpoint did not answer (endpoint, credentials or CORS).'\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn connectTarget(target, opts);\n\t\t},\n\t\tconnectTarget,\n\t\tdisconnect: () => store.detachTarget(),\n\t\taddReplica: (target, opts) => store.attachReplica(target, opts),\n\t\tremoveReplica: (id) => store.detachReplica(id),\n\n\t\tprotect: (password: string) => store.setEncryption(password),\n\t\tunprotect: () => store.setEncryption(null),\n\t\tunlock: (password: string) => store.unlock(password),\n\t\treconnect: () => store.reconnect(),\n\n\t\texportBackup: () => store.exportBlob(),\n\t\tasync downloadBackup(filename?: string): Promise<boolean> {\n\t\t\tconst written = await saveToDisk(await store.exportBlob(), filename ?? backupName);\n\t\t\t// Clearing the pending flag on a cancelled dialog would drop the very\n\t\t\t// nudge that asks for the file the user still does not have.\n\t\t\tif (written) store.markDownloaded();\n\t\t\treturn written;\n\t\t},\n\t\tasync importBackup(file: Blob | Uint8Array, opts?: { password?: string }): Promise<void> {\n\t\t\t// The fluent read() strips reserved bookkeeping collections; removals\n\t\t\t// then propagate because the next save diffs against the sync meta.\n\t\t\tconst reader = restore(file);\n\t\t\tconst snap = opts?.password\n\t\t\t\t? await reader.withPassword(opts.password).read()\n\t\t\t\t: await reader.read();\n\t\t\tcollections = (snap.collections ?? {}) as Record<string, SimpleRecord[]>;\n\t\t\tfiles = snap.files ?? [];\n\t\t\temitData();\n\t\t\tstore.schedule();\n\t\t},\n\n\t\tget status(): StatusDescriptor {\n\t\t\treturn store.state.status;\n\t\t},\n\t\tget error(): StoreError | null {\n\t\t\treturn store.state.lastError;\n\t\t},\n\t\tget state(): LocalStoreState {\n\t\t\treturn store.state;\n\t\t},\n\t\tsubscribe: (fn: () => void) => store.subscribe(fn),\n\n\t\tflush: () => store.flush(),\n\t\tasync sync(): Promise<void> {\n\t\t\tawait store.syncNow();\n\t\t},\n\t\tdispose(): void {\n\t\t\tteardown.forEach((fn) => fn());\n\t\t\tteardown.length = 0;\n\t\t\tstore.dispose();\n\t\t},\n\n\t\tadvanced: store,\n\n\t\tflowHost: { engine: store, kv: cache.kv, backupName }\n\t};\n\n\treturn simple;\n}\n"]}
1
+ {"version":3,"sources":["../src/simple/simple.ts"],"names":["fromSession","connect"],"mappings":";;;;;;;;;;;;;;;;AAuOA,SAAS,SAAA,CAAU,MAA8B,UAAA,EAAmC;AACnF,EAAA,MAAM,MAAA,GAAS,IAAA,EAAM,GAAA,GAAM,UAAU,CAAA;AACrC,EAAA,IAAI,MAAA,IAAU,MAAM,OAAO,IAAA;AAC3B,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,GAAI,IAAA,GAAO,MAAA;AACtC;AAEA,SAAS,eAAA,CAAgB,MAAA,EAAsB,KAAA,EAAsB,UAAA,EAA4B;AAChG,EAAA,IAAI,KAAA,KAAU,MAAM,OAAO,EAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,OAAO,KAAK,CAAA;AACvB,EAAA,IAAI,OAAO,EAAA,KAAO,QAAA,IAAY,EAAA,CAAG,WAAW,CAAA,EAAG;AAC9C,IAAA,MAAM,IAAI,SAAA;AAAA,MACT,CAAA,wBAAA,EAA2B,UAAU,CAAA,4BAAA,EAA+B,KAAK,CAAA,OAAA,EAChE,KAAK,SAAA,CAAU,EAAE,CAAC,CAAA,+FAAA,EACiB,UAAU,CAAA,oBAAA;AAAA,KACvD;AAAA,EACD;AACA,EAAA,OAAO,EAAA;AACR;AAGA,SAAS,YAAA,GAAwB;AAChC,EAAA,OAAO,OAAO,SAAA,KAAc,WAAA;AAC7B;AAGA,SAAS,YAAY,CAAA,EAA2C;AAC/D,EAAA,OAAO,CAAC,CAAC,CAAA,IAAK,OAAQ,EAAgB,KAAA,KAAU,UAAA;AACjD;AAKA,IAAM,eAAA,GAAkB,CAAC,GAAA,KAAwB,CAAA,wBAAA,EAA2B,GAAG,CAAA,CAAA;AAE/E,SAAS,WAAc,GAAA,EAA2C;AACjE,EAAA,IAAI;AACH,IAAA,MAAM,QAAQ,UAAA,CAAW,YAAA;AACzB,IAAA,OAAO,KAAA,GAAQ,GAAA,CAAI,KAAK,CAAA,GAAI,KAAA,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACP,IAAA,OAAO,MAAA;AAAA,EACR;AACD;AAEA,SAAS,uBAAuB,GAAA,EAAiC;AAChE,EAAA,OAAO,UAAA,CAAW,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,eAAA,CAAgB,GAAG,CAAC,CAAC,CAAA,IAAK,MAAA;AAC9D;AAIA,eAAe,iBAAA,CAAkB,KAAa,IAAA,EAAgC;AAC7E,EAAA,IAAI;AACH,IAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAa,EAAE,MAAM,CAAA;AACvC,IAAA,IAAI,GAAA,CAAI,KAAA,EAAO,UAAA,CAAW,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,CAAQ,eAAA,CAAgB,GAAG,CAAA,EAAG,GAAA,CAAI,KAAM,CAAC,CAAA;AAAA,EAC7E,CAAA,CAAA,MAAQ;AAAA,EAER;AACD;AAOA,eAAsB,SAAA,CAEpB,GAAA,EAAa,OAAA,GAAyB,EAAC,EAA4B;AACpE,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,CAAI,WAAW,CAAA,EAAG;AAChD,IAAA,MAAM,IAAI,UAAU,0DAA0D,CAAA;AAAA,EAC/E;AAKA,EAAA,IAAI,cAA8C,EAAC;AAGnD,EAAA,IAAI,QAAwB,EAAC;AAE7B,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAgB;AACrC,EAAA,MAAM,WAAW,MAAY,QAAA,CAAS,QAAQ,CAAC,EAAA,KAAO,IAAI,CAAA;AAE1D,EAAA,MAAM,KAAA,GACL,OAAA,CAAQ,KAAA,KACP,YAAA,KACE,cAAA,CAAe,GAAA,EAAK,OAAA,CAAQ,SAAA,GAAY,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,MAAS,IAClE,WAAA,EAAY,CAAA;AAChB,EAAA,MAAM,UAAA,GAAa,GAAG,GAAG,CAAA,IAAA,CAAA;AASzB,EAAA,IAAI,SAAA,GAA8B,YAAY,OAAA,CAAQ,KAAK,IACxD,OAAA,CAAQ,KAAA,GACR,OAAA,CAAQ,KAAA,GACP,YAAA,CAAa;AAAA,IACb,QAAA,EAAU,QAAQ,KAAA,CAAM,QAAA;AAAA,IACxB,KAAA,EAAO,QAAQ,KAAA,CAAM,KAAA;AAAA,IACrB,OAAA,EAAS,SAAA;AAAA,IACT,IAAA,EAAM,MAAM,sBAAA,CAAuB,GAAG;AAAA,GACtC,CAAA,GACA,IAAA;AAKJ,EAAA,IAAI,OAAA,CAAQ,SAAA,IAAa,eAAA,CAAgB,KAAK,CAAA,EAAG;AAChD,IAAA,IAAI,MAAA,GAAS,KAAA;AACb,IAAA,OAAO,CAAE,MAAM,KAAA,CAAM,MAAA,CAAO,MAAM,OAAA,CAAQ,SAAA,CAAU,EAAE,MAAA,EAAQ,CAAC,CAAA,EAAI,MAAA,GAAS,IAAA;AAAA,EAC7E;AAEA,EAAA,MAAM,QAAQ,gBAAA,CAAiB;AAAA,IAC9B,GAAA;AAAA,IACA,aAAA,EAAe,QAAQ,MAAA,IAAU,CAAA;AAAA,IACjC,QAAQ,MAAgB,eAAA,CAAgB,EAAE,WAAA,EAAa,OAAO,CAAA;AAAA,IAC9D,KAAA,EAAO,CAAC,IAAA,KAAyB;AAChC,MAAA,WAAA,GAAe,IAAA,CAAK,eAAe,EAAC;AACpC,MAAA,KAAA,GAAQ,IAAA,CAAK,SAAS,EAAC;AACvB,MAAA,QAAA,EAAS;AAAA,IACV,CAAA;AAAA,IACA,SAAS,OAAA,CAAQ,OAAA;AAAA,IACjB,MAAM,OAAA,CAAQ,IAAA;AAAA,IACd,KAAA;AAAA,IACA,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,mBAAmB,OAAA,CAAQ,iBAAA;AAAA,IAC3B,gBAAgB,OAAA,CAAQ,cAAA;AAAA,IACxB,aAAA,EAAe,OAAO,IAAA,KAAS;AAC9B,MAAA,IAAI,IAAA,KAAS,WAAW,SAAA,EAAW;AAClC,QAAA,OAAO,WAAA,CAAiB,EAAE,IAAA,EAAM,SAAA,EAAW,IAAI,KAAA,CAAM,EAAA,EAAI,QAAA,EAAU,UAAA,EAAY,CAAA;AAAA,MAChF;AACA,MAAA,IAAI,IAAA,KAAS,QAAQ,OAAOA,aAAAA,CAAgB,EAAE,EAAA,EAAI,KAAA,CAAM,IAAI,CAAA;AAC5D,MAAA,IAAI,IAAA,KAAS,UAAU,OAAOA,YAAAA,CAAkB,EAAE,EAAA,EAAI,KAAA,CAAM,IAAI,CAAA;AAChE,MAAA,OAAO,IAAA;AAAA,IACR;AAAA,GACA,CAAA;AAED,EAAA,MAAM,MAAM,IAAA,EAAK;AAcjB,EAAA,IAAI,KAAA,CAAM,KAAA,CAAM,UAAA,KAAe,aAAA,IAAiB,aAAgB,EAAG;AAClE,IAAA,MAAM,MAAM,YAAA,EAAa;AAAA,EAC1B;AAKA,EAAA,MAAM,WAA2B,EAAC;AAClC,EAAA,IACC,OAAA,CAAQ,aAAa,KAAA,IACrB,OAAO,aAAa,WAAA,IACpB,OAAO,WAAW,WAAA,EACjB;AACD,IAAA,MAAM,eAAe,MAAY;AAChC,MAAA,IAAI,QAAA,CAAS,eAAA,KAAoB,QAAA,EAAU,KAAK,MAAM,KAAA,EAAM;AAAA,WACvD,KAAK,KAAA,CAAM,WAAA,CAAY,OAAO,CAAA;AAAA,IACpC,CAAA;AACA,IAAA,MAAM,QAAA,GAAW,MAAY,KAAK,KAAA,CAAM,YAAY,QAAQ,CAAA;AAC5D,IAAA,MAAM,UAAA,GAAa,MAAY,KAAK,KAAA,CAAM,KAAA,EAAM;AAChD,IAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AAClC,MAAA,IAAI,SAAS,eAAA,KAAoB,SAAA,EAAW,KAAK,KAAA,CAAM,YAAY,UAAU,CAAA;AAAA,IAC9E,CAAA,EAAG,IAAI,GAAM,CAAA;AACb,IAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAoB,YAAY,CAAA;AAC1D,IAAA,MAAA,CAAO,gBAAA,CAAiB,UAAU,QAAQ,CAAA;AAC1C,IAAA,MAAA,CAAO,gBAAA,CAAiB,YAAY,UAAU,CAAA;AAC9C,IAAA,QAAA,CAAS,KAAK,MAAM;AACnB,MAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,MAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAoB,YAAY,CAAA;AAC7D,MAAA,MAAA,CAAO,mBAAA,CAAoB,UAAU,QAAQ,CAAA;AAC7C,MAAA,MAAA,CAAO,mBAAA,CAAoB,YAAY,UAAU,CAAA;AAAA,IAClD,CAAC,CAAA;AAAA,EACF;AAEA,EAAA,SAAS,MAAA,CAAO,YAAoB,IAAA,EAAqC;AACxE,IAAA,WAAA,GAAc,EAAE,GAAG,WAAA,EAAa,CAAC,UAAU,GAAG,IAAA,EAAK;AACnD,IAAA,QAAA,EAAS;AACT,IAAA,KAAA,CAAM,QAAA,EAAS;AACf,IAAA,OAAO,QAAQ,OAAA,EAAQ;AAAA,EACxB;AAEA,EAAA,eAAe,aAAA,CACd,MAAA,EACA,IAAA,GAA8B,EAAC,EACL;AAC1B,IAAA,MAAM,IAAA,GAAO,MAAM,KAAA,CAAM,aAAA,CAAc,MAAM,CAAA;AAC7C,IAAA,IAAI,KAAK,SAAA,EAAW;AAInB,MAAA,IAAI,KAAK,GAAA,KAAQ,IAAA,IAAQ,IAAA,CAAK,GAAA,KAAQ,MAAM,GAAA,EAAK;AAChD,QAAA,MAAM,IAAI,cAAA;AAAA,UACT,gBAAA;AAAA,UACA,CAAA,gDAAA,EAAmD,IAAA,CAAK,GAAG,CAAA,QAAA,EAAW,MAAM,GAAG,CAAA,wDAAA;AAAA,SAChF;AAAA,MACD;AAGA,MAAA,IAAI,IAAA,CAAK,SAAA,IAAa,CAAC,IAAA,CAAK,QAAA,EAAU;AACrC,QAAA,MAAM,IAAI,cAAA;AAAA,UACT,mBAAA;AAAA,UACA;AAAA,SACD;AAAA,MACD;AACA,MAAA,MAAM,KAAA,CAAM,YAAA,CAAa,MAAA,EAAQ,EAAE,QAAA,EAAU,KAAK,QAAA,IAAY,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,CAAA;AACvF,MAAA,OAAO,QAAA;AAAA,IACR;AACA,IAAA,MAAM,KAAA,CAAM,aAAa,MAAA,EAAQ;AAAA,MAChC,QAAA,EAAU,KAAK,QAAA,IAAY,IAAA;AAAA,MAC3B,QAAA,EAAU;AAAA,KACV,CAAA;AACD,IAAA,OAAO,SAAA;AAAA,EACR;AAEA,EAAA,MAAM,MAAA,GAAyB;AAAA,IAC9B,IAAgC,UAAA,EAAgC;AAC/D,MAAA,OAAQ,WAAA,CAAY,UAAU,CAAA,IAAK,EAAC;AAAA,IACrC,CAAA;AAAA,IACA,GAAA,CAAgC,YAAe,EAAA,EAA8B;AAC5E,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,CAAQ,IAAA,EAAM,UAAU,CAAA,IAAK,IAAA;AACrD,MAAA,OAAA,CAAQ,WAAA,CAAY,UAAU,CAAA,IAAK,EAAC,EAAG,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAA,KAAM,EAAE,CAAA;AAAA,IACnE,CAAA;AAAA,IACA,GAAA,CAAgC,YAAe,MAAA,EAA6B;AAC3E,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,CAAQ,IAAA,EAAM,UAAU,CAAA;AAChD,MAAA,MAAM,EAAA,GAAK,eAAA,CAAgB,MAAA,EAAQ,KAAA,EAAO,UAAU,CAAA;AACpD,MAAA,MAAM,IAAA,GAAO,WAAA,CAAY,UAAU,CAAA,IAAK,EAAC;AACzC,MAAA,MAAM,EAAA,GAAK,KAAA,KAAU,IAAA,GAAO,EAAA,GAAK,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAA,KAAM,EAAE,CAAA;AACtE,MAAA,OAAO,MAAA;AAAA,QACN,UAAA;AAAA,QACA,EAAA,KAAO,EAAA,GAAK,CAAC,GAAG,MAAM,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,KAAO,CAAA,KAAM,EAAA,GAAK,SAAS,CAAE;AAAA,OAC3E;AAAA,IACD,CAAA;AAAA,IACA,MAAA,CAAmC,YAAe,OAAA,EAAgC;AACjF,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,CAAQ,IAAA,EAAM,UAAU,CAAA;AAChD,MAAA,MAAM,IAAA,uBAAW,GAAA,EAAqB;AACtC,MAAA,KAAA,MAAW,CAAA,IAAK,OAAA,EAAS,eAAA,CAAgB,CAAA,EAAG,OAAO,UAAU,CAAA;AAC7D,MAAA,MAAM,OAAO,CAAC,GAAI,YAAY,UAAU,CAAA,IAAK,EAAG,CAAA;AAChD,MAAA,IAAI,UAAU,IAAA,EAAM;AACnB,QAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM,IAAA,CAAK,IAAI,CAAA,CAAE,KAAK,CAAA,EAAG,CAAC,CAAC,CAAA;AAC5C,QAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACxB,UAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAK,CAAC,CAAA;AAC5B,UAAA,IAAI,OAAO,EAAA,KAAO,QAAA,EAAU,IAAA,CAAK,EAAE,CAAA,GAAI,CAAA;AAAA,eAClC,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,QACjB;AAAA,MACD,CAAA,MAAO;AACN,QAAA,IAAA,CAAK,IAAA,CAAK,GAAG,OAAO,CAAA;AAAA,MACrB;AACA,MAAA,OAAO,MAAA,CAAO,YAAY,IAAI,CAAA;AAAA,IAC/B,CAAA;AAAA,IACA,MAAA,CAAmC,YAAe,EAAA,EAA2B;AAC5E,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,CAAQ,IAAA,EAAM,UAAU,CAAA,IAAK,IAAA;AACrD,MAAA,MAAM,IAAA,GAAO,WAAA,CAAY,UAAU,CAAA,IAAK,EAAC;AACzC,MAAA,MAAM,IAAA,GAAO,KAAK,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,KAAK,MAAM,EAAE,CAAA;AAC/C,MAAA,OAAO,IAAA,CAAK,WAAW,IAAA,CAAK,MAAA,GAAS,QAAQ,OAAA,EAAQ,GAAI,MAAA,CAAO,UAAA,EAAY,IAAI,CAAA;AAAA,IACjF,CAAA;AAAA,IACA,MAAkC,UAAA,EAA8B;AAC/D,MAAA,IAAA,CAAK,WAAA,CAAY,UAAU,CAAA,IAAK,IAAI,MAAA,KAAW,CAAA,EAAG,OAAO,OAAA,CAAQ,OAAA,EAAQ;AACzE,MAAA,OAAO,MAAA,CAAO,UAAA,EAAY,EAAE,CAAA;AAAA,IAC7B,CAAA;AAAA,IACA,SAAS,EAAA,EAA4B;AACpC,MAAA,QAAA,CAAS,IAAI,EAAE,CAAA;AACf,MAAA,OAAO,MAAM,QAAA,CAAS,MAAA,CAAO,EAAE,CAAA;AAAA,IAChC,CAAA;AAAA,IAEA,MAAM,YAAA,CAAa,IAAA,EAAiB,IAAA,EAAuD;AAC1F,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,MAAM,MAAA,GAAS,MAAMC,SAAA,CAAa,EAAE,IAAA,EAAM,IAAI,KAAA,CAAM,EAAA,EAAI,QAAA,EAAU,UAAA,EAAY,CAAA;AAC9E,MAAA,IAAI,CAAC,QAAQ,OAAO,WAAA;AACpB,MAAA,MAAM,OAAA,GAAU,MAAM,aAAA,CAAc,MAAA,EAAQ,IAAI,CAAA;AAKhD,MAAA,IAAI,OAAA,KAAY,WAAA,EAAa,KAAK,iBAAA,CAAkB,KAAK,IAAI,CAAA;AAC7D,MAAA,OAAO,OAAA;AAAA,IACR,CAAA;AAAA,IACA,MAAM,YAAY,IAAA,EAAuD;AAIxE,MAAA,IAAI,aAAgB,EAAG;AACtB,QAAA,MAAM,MAAA,GAAS,MAAMA,OAAAA,CAAY,EAAE,IAAI,KAAA,CAAM,EAAA,EAAI,QAAA,EAAU,UAAA,EAAY,CAAA;AACvE,QAAA,IAAI,MAAA,EAAQ,OAAO,aAAA,CAAc,MAAA,EAAQ,IAAI,CAAA;AAC7C,QAAA,IAAI,WAAA,IAAmB,OAAO,WAAA;AAAA,MAC/B;AACA,MAAA,MAAM,MAAM,aAAA,EAAc;AAC1B,MAAA,OAAO,QAAA;AAAA,IACR,CAAA;AAAA,IACA,MAAM,aAAA,CACL,MAAA,EACA,IAAA,EAC0B;AAC1B,MAAA,MAAM,MAAA,GAAS,MAAMA,QAAAA,CAAc,EAAE,IAAI,KAAA,CAAM,EAAA,EAAI,QAAQ,CAAA;AAC3D,MAAA,IAAI,CAAC,MAAA,EAAQ;AACZ,QAAA,MAAM,IAAI,cAAA;AAAA,UACT,oBAAA;AAAA,UACA;AAAA,SACD;AAAA,MACD;AACA,MAAA,OAAO,aAAA,CAAc,QAAQ,IAAI,CAAA;AAAA,IAClC,CAAA;AAAA,IACA,MAAM,SAAA,CAAU,MAAA,EAAkB,IAAA,EAAuD;AACxF,MAAA,MAAM,MAAA,GAAS,MAAMA,QAAAA,CAAU,EAAE,IAAI,KAAA,CAAM,EAAA,EAAI,QAAQ,CAAA;AACvD,MAAA,IAAI,CAAC,MAAA,EAAQ;AACZ,QAAA,MAAM,IAAI,cAAA;AAAA,UACT,oBAAA;AAAA,UACA;AAAA,SACD;AAAA,MACD;AACA,MAAA,OAAO,aAAA,CAAc,QAAQ,IAAI,CAAA;AAAA,IAClC,CAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA,EAAY,MAAM,KAAA,CAAM,YAAA,EAAa;AAAA,IACrC,YAAY,CAAC,MAAA,EAAQ,SAAS,KAAA,CAAM,aAAA,CAAc,QAAQ,IAAI,CAAA;AAAA,IAC9D,aAAA,EAAe,CAAC,EAAA,KAAO,KAAA,CAAM,cAAc,EAAE,CAAA;AAAA,IAE7C,OAAA,EAAS,CAAC,QAAA,KAAqB,KAAA,CAAM,cAAc,QAAQ,CAAA;AAAA,IAC3D,SAAA,EAAW,MAAM,KAAA,CAAM,aAAA,CAAc,IAAI,CAAA;AAAA,IACzC,MAAA,EAAQ,CAAC,QAAA,KAAqB,KAAA,CAAM,OAAO,QAAQ,CAAA;AAAA,IACnD,SAAA,EAAW,MAAM,KAAA,CAAM,SAAA,EAAU;AAAA,IAEjC,YAAA,EAAc,MAAM,KAAA,CAAM,UAAA,EAAW;AAAA,IACrC,MAAM,eAAe,QAAA,EAAqC;AACzD,MAAA,MAAM,OAAA,GAAU,MAAM,UAAA,CAAW,MAAM,MAAM,UAAA,EAAW,EAAG,YAAY,UAAU,CAAA;AAGjF,MAAA,IAAI,OAAA,QAAe,cAAA,EAAe;AAClC,MAAA,OAAO,OAAA;AAAA,IACR,CAAA;AAAA,IACA,MAAM,YAAA,CAAa,IAAA,EAAyB,IAAA,EAA6C;AAGxF,MAAA,MAAM,MAAA,GAAS,QAAQ,IAAI,CAAA;AAC3B,MAAA,MAAM,IAAA,GAAO,IAAA,EAAM,QAAA,GAChB,MAAM,MAAA,CAAO,YAAA,CAAa,IAAA,CAAK,QAAQ,CAAA,CAAE,IAAA,EAAK,GAC9C,MAAM,OAAO,IAAA,EAAK;AACrB,MAAA,WAAA,GAAe,IAAA,CAAK,eAAe,EAAC;AACpC,MAAA,KAAA,GAAQ,IAAA,CAAK,SAAS,EAAC;AACvB,MAAA,QAAA,EAAS;AACT,MAAA,KAAA,CAAM,QAAA,EAAS;AAAA,IAChB,CAAA;AAAA,IAEA,IAAI,MAAA,GAA2B;AAC9B,MAAA,OAAO,MAAM,KAAA,CAAM,MAAA;AAAA,IACpB,CAAA;AAAA,IACA,IAAI,KAAA,GAA2B;AAC9B,MAAA,OAAO,MAAM,KAAA,CAAM,SAAA;AAAA,IACpB,CAAA;AAAA,IACA,IAAI,KAAA,GAAyB;AAC5B,MAAA,OAAO,KAAA,CAAM,KAAA;AAAA,IACd,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,EAAA,KAAmB,KAAA,CAAM,UAAU,EAAE,CAAA;AAAA,IAEjD,KAAA,EAAO,MAAM,KAAA,CAAM,KAAA,EAAM;AAAA,IACzB,MAAM,IAAA,GAAsB;AAC3B,MAAA,MAAM,MAAM,OAAA,EAAQ;AAAA,IACrB,CAAA;AAAA,IACA,OAAA,GAAgB;AACf,MAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,EAAA,KAAO,EAAA,EAAI,CAAA;AAC7B,MAAA,QAAA,CAAS,MAAA,GAAS,CAAA;AAClB,MAAA,KAAA,CAAM,OAAA,EAAQ;AAAA,IACf,CAAA;AAAA,IAEA,QAAA,EAAU,KAAA;AAAA,IAEV,UAAU,EAAE,MAAA,EAAQ,OAAO,EAAA,EAAI,KAAA,CAAM,IAAI,UAAA,EAAW;AAAA,IAEpD,IAAI,OAAA,GAAyB;AAC5B,MAAA,OAAO,sBAAA,CAAuB,GAAG,CAAA,IAAK,IAAA;AAAA,IACvC,CAAA;AAAA,IAEA,WAAA,GAAkC;AACjC,MAAA,MAAM,MAAA,GAAS,uBAAuB,GAAG,CAAA;AACzC,MAAA,IAAI,CAAC,SAAA,IAAa,CAAC,MAAA,EAAQ,OAAO,IAAA;AAClC,MAAA,MAAM,IAAA,GAAO,SAAA;AACb,MAAA,OAAO;AAAA,QACN,IAAA,EAAM,OAAA;AAAA,QACN,MAAA;AAAA;AAAA;AAAA;AAAA,QAIA,OAAA,EAAS,MAAM,WAAA,CAAiB,EAAE,IAAA,EAAM,IAAI,KAAA,CAAM,EAAA,EAAI,QAAA,EAAU,UAAA,EAAY;AAAA,OAC7E;AAAA,IACD;AAAA,GACD;AAEA,EAAA,OAAO,MAAA;AACR","file":"index.js","sourcesContent":["// The simple store: one call, sensible defaults, and the store owns the data.\n//\n// const store = await selfstore('notes-app');\n// await store.put('todos', { id: 't1', text: 'hello' });\n// store.onChange(render);\n//\n// Convention over configuration: schema version 1, an IndexedDB cache named\n// after the app (in-memory where IndexedDB does not exist, so tests and SSR\n// just work), debounced auto-save, and the browser sync moments wired.\n// Every default has an option; everything deeper lives on store.advanced -\n// the full createLocalStore, same instance.\n//\n// One rule is enforced rather than documented: records need a non-empty\n// string id (the merge identifies records by it), so put() throws a\n// TypeError right away. The advanced pull-model store only logs - it cannot\n// know which collections an app considers mergeable.\n\nimport {\n\tcreateLocalStore,\n\ttype LocalStore,\n\ttype LocalStoreState,\n\ttype StoreError\n} from '../persistence/store';\nimport {\n\tindexedDbCache,\n\tmemoryCache,\n\tisLockableCache,\n\ttype KV,\n\ttype LocalCache\n} from '../persistence/cache';\nimport type { BackupTarget } from '../persistence/target';\nimport type { StatusDescriptor } from '../persistence/status';\nimport type { SyncConfig } from '../sync';\nimport type { ResumeOffer } from '../flows/connect';\nimport type { Snapshot, SnapshotFile } from '../selfstore/types';\nimport { SelfstoreError } from '../selfstore/errors';\nimport { restore, type PasswordPolicy } from '../selfstore';\nimport { saveToDisk } from '../selfstore/targets/local';\nimport {\n\taccount as driveAccount,\n\tconnect as driveConnect,\n\tfromSession as driveFromSession,\n\ttype DriveAuth\n} from '../persistence/targets/drive';\nimport { gisDriveAuth } from '../persistence/targets/drive-auth-gis';\nimport {\n\tconnect as fileConnect,\n\tfromSession as fileFromSession,\n\tisSupported as fileIsSupported\n} from '../persistence/targets/file';\nimport {\n\tconnect as webdavConnect,\n\tfromSession as webdavFromSession,\n\ttype WebdavConfig\n} from '../persistence/targets/webdav';\nimport { connect as s3Connect, type S3Config } from '../persistence/targets/s3';\n\n/** A record as the simple store sees it: plain JSON with a string id (the id\n * field name can be remapped per collection via `sync.ids`). */\nexport type SimpleRecord = Record<string, unknown>;\n\n/** Unlock callback for the ultra-sensitive cacheLock mode: return the session\n * secret - a password (Argon2id-derived) or an app-provided key (e.g. a passkey\n * PRF result). Called at boot; called again with { failed: true } after a wrong\n * secret so the app can re-prompt. Throw to abort the boot (user cancelled). */\nexport type CacheUnlock = (attempt: { failed: boolean }) => Promise<string | CryptoKey>;\n\n/** Options - every one of them optional, the defaults carry a real app. */\nexport interface SimpleOptions {\n\t/** Your DATA schema version (default 1). Bump it together with `migrate`. */\n\tschema?: number;\n\t/** Upgrade a snapshot written by an older schema version. */\n\tmigrate?: (fromVersion: number, snap: Snapshot) => Snapshot;\n\t/** Per-collection merge tuning (id field mapping, strategies). The default -\n\t * records keyed by `id`, later edit wins, deletes propagate - fits most apps. */\n\tsync?: SyncConfig;\n\t/**\n\t * Google Drive, when this app uses it. Two shapes for two situations:\n\t *\n\t * `{ clientId }` is the whole wiring - the library builds the browser\n\t * connection, keeps ONE session for the app (several would mean several\n\t * consent screens), reuses its token across a reload, remembers which\n\t * account holds the backup and hands that back to Google so the chooser\n\t * stops appearing. Nothing else to write.\n\t *\n\t * A `DriveAuth` instead, for an app that gets its tokens elsewhere - a\n\t * server broker holding a refresh token, a native shell.\n\t *\n\t * Either way, providing it here is also what lets a connected Drive backup\n\t * restore itself on the next start.\n\t */\n\tdrive?: DriveAuth | { clientId: string; scope?: string };\n\t/** Where the working copy lives (default: IndexedDB named after the app;\n\t * in-memory when IndexedDB does not exist, e.g. tests or SSR). */\n\tcache?: LocalCache;\n\t/** Auto-save debounce in ms. */\n\tdebounceMs?: number;\n\t/** Cross-tab coordination (default on in browsers). */\n\tmultiTab?: boolean;\n\t/** Refuse to ever write or export a plaintext backup: connecting a\n\t * destination then demands a password (or a group). Off by default. */\n\trequireEncryption?: boolean;\n\t/** Reject a backup password weaker than this policy (length, character\n\t * classes) at protect()/addKey time. Preview the rules with\n\t * checkPasswordPolicy for a live UI hint. Omit for no policy. */\n\tpasswordPolicy?: PasswordPolicy;\n\t/** Ultra-sensitive mode: seal the local cache under a key derived from a\n\t * secret held in memory (this callback), never on disk - so a copy of the\n\t * browser profile cannot read it. One unlock per session; branch it on the\n\t * app's existing login to leave the UX unchanged. Browser (IndexedDB) only. */\n\tcacheLock?: CacheUnlock;\n\t/** Wire tab focus / network return / interval / tab hide automatically\n\t * (default true in browsers). Pass false to drive syncing yourself. */\n\tautoSync?: boolean;\n}\n\n/** What connecting a destination did. 'merged': it already held a backup and\n * both sides were folded together. 'started': it was empty, this device's data\n * is now its content. 'manual': non-Chromium file fallback - offer\n * downloadBackup() instead. 'cancelled': the user closed the picker/consent. */\nexport type ConnectOutcome = 'merged' | 'started' | 'manual' | 'cancelled';\n\nexport interface SimpleStore<\n\tS extends Record<string, SimpleRecord> = Record<string, SimpleRecord>\n> {\n\t// --- Your data ---------------------------------------------------------\n\t/** Every record of a collection (treat as read-only; write via put/remove). */\n\tall<K extends keyof S & string>(collection: K): readonly S[K][];\n\t/** One record by id, or undefined. */\n\tget<K extends keyof S & string>(collection: K, id: string): S[K] | undefined;\n\t/** Insert or replace one record (auto-saves, debounced). Throws a TypeError\n\t * when the record has no non-empty string id. */\n\tput<K extends keyof S & string>(collection: K, record: S[K]): Promise<void>;\n\t/** Insert or replace many records in one save. */\n\tputAll<K extends keyof S & string>(collection: K, records: S[K][]): Promise<void>;\n\t/** Delete one record by id (propagates to other devices). Unknown id: no-op. */\n\tremove<K extends keyof S & string>(collection: K, id: string): Promise<void>;\n\t/** Empty a collection (every removal propagates). */\n\tclear<K extends keyof S & string>(collection: K): Promise<void>;\n\t/** Called after any data change: your writes, another tab, another device,\n\t * a restore. Returns an unsubscribe. */\n\tonChange(fn: () => void): () => void;\n\n\t// --- Where it lives ----------------------------------------------------\n\t/** Connect Google Drive as the durable home. An existing backup there is\n\t * MERGED with this device (multi-device); an encrypted one needs its\n\t * password up front (PASSWORD_REQUIRED is thrown before anything changes). */\n\tconnectDrive(auth: DriveAuth, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect a disk file (File System Access; falls back to manual download). */\n\tconnectFile(opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect a WebDAV server (Nextcloud, ownCloud, your own). */\n\tconnectWebdav(config: WebdavConfig, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect an S3-compatible bucket you control (Amazon S3, R2, B2, MinIO). */\n\tconnectS3(config: S3Config, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Connect any custom BackupTarget with the same merge semantics. */\n\tconnectTarget(target: BackupTarget, opts?: { password?: string }): Promise<ConnectOutcome>;\n\t/** Back to device-only (the destination keeps its last backup). */\n\tdisconnect(): Promise<void>;\n\n\t// --- Backup copy (replica) ---------------------------------------------\n\t/** Also write the same encrypted backup to this second destination on\n\t * every save. A broken copy never gates the store (state.replicas). */\n\taddReplica(target: BackupTarget, opts?: { id?: string }): string;\n\t/** Stop writing the copy (the destination keeps its last backup). */\n\tremoveReplica(id: string): void;\n\n\t// --- Protection & the two gate gestures --------------------------------\n\t/** Encrypt the durable backup end to end with this password (reversible). */\n\tprotect(password: string): Promise<void>;\n\t/** Remove the backup password. */\n\tunprotect(): Promise<void>;\n\t/** status.action === 'unlock': supply the password to resume. */\n\tunlock(password: string): Promise<boolean>;\n\t/** status.action === 'reconnect': re-run the destination's auth gesture. */\n\treconnect(): Promise<boolean>;\n\n\t// --- Portable backups ---------------------------------------------------\n\t/** The portable backup file (a real ZIP; encrypted when protect() is on). */\n\texportBackup(): Promise<Blob>;\n\t/** Download the backup (also resolves the 'manual' file mode's pending flag).\n\t * False when the user closed the save dialog: nothing was written, the\n\t * pending flag stands, and the app must not record a backup. */\n\tdownloadBackup(filename?: string): Promise<boolean>;\n\t/** Load a backup file into this store, replacing the local data (removals\n\t * propagate like edits). Throws PASSWORD_REQUIRED / DECRYPT_FAILED. */\n\timportBackup(file: Blob | Uint8Array, opts?: { password?: string }): Promise<void>;\n\n\t// --- Observability ------------------------------------------------------\n\t/** Headless status: { state, severity, action, labelKey } - map labelKey to\n\t * your own copy. */\n\treadonly status: StatusDescriptor;\n\t/** The last problem: { code, labelKey, message } - show labelKey, log message. */\n\treadonly error: StoreError | null;\n\t/** The full underlying state (advanced reads: journal, peers, mode...). */\n\treadonly state: LocalStoreState;\n\t/** Fires on any state change (status flips included) - for framework bindings. */\n\tsubscribe(fn: () => void): () => void;\n\n\t// --- Lifecycle ----------------------------------------------------------\n\t/** Save now (called for you on tab hide when autoSync is on). */\n\tflush(): Promise<void>;\n\t/** Converge with the destination now (a user gesture like pull-to-refresh). */\n\tsync(): Promise<void>;\n\t/** Drop timers and listeners (tests, SPA teardown). */\n\tdispose(): void;\n\n\t/** The escape hatch: the full advanced store this simple one is built on -\n\t * peers, groups, custom strategies, everything (see selfstore/advanced). */\n\treadonly advanced: LocalStore;\n\n\t/** The attachment point for 'selfstore/flows': the engine plus the cache KV\n\t * and backup file name a flow needs to build destination targets. Apps on\n\t * the advanced store hand a flow the same three by themselves. */\n\treadonly flowHost: { engine: LocalStore; kv: KV; backupName: string };\n\n\t/** Who holds the destination, when it is known - the Google address behind a\n\t * Drive backup. Learned on connect and remembered across sessions, so a\n\t * surface can NAME the destination (\"Google Drive\" is not an address) and a\n\t * re-grant can skip the account chooser. Null for a file, or before a first\n\t * connect. Reading it costs nothing: no call goes out. */\n\treadonly account: string | null;\n\n\t/** The destination this device already used, ready to hand to a connect flow\n\t * as `options.resume` - so a returning visitor is offered \"reopen my backup\"\n\t * ahead of the plain destinations, instead of re-deriving a decision the\n\t * library already has on file. Null when there is nothing to resume. */\n\tresumeOffer(): ResumeOffer | null;\n}\n\n/** The id field a collection's records are keyed by: `sync.ids` may remap it;\n * a DOTTED path (nested id) is an advanced setup the simple check skips. */\nfunction idFieldOf(sync: SyncConfig | undefined, collection: string): string | null {\n\tconst mapped = sync?.ids?.[collection];\n\tif (mapped == null) return 'id';\n\treturn mapped.includes('.') ? null : mapped;\n}\n\nfunction requireStringId(record: SimpleRecord, field: string | null, collection: string): string {\n\tif (field === null) return ''; // nested-path ids: validated by the engine's own rules\n\tconst id = record[field];\n\tif (typeof id !== 'string' || id.length === 0) {\n\t\tthrow new TypeError(\n\t\t\t`selfstore: a record in \"${collection}\" needs a non-empty STRING \"${field}\" ` +\n\t\t\t\t`(got ${JSON.stringify(id)}). String ids are what the multi-device merge keys on; ` +\n\t\t\t\t`map another field with { sync: { ids: { ${collection}: 'yourField' } } }.`\n\t\t);\n\t}\n\treturn id;\n}\n\n/** True when a browser IndexedDB is available (SSR and plain Node lack it). */\nfunction hasIndexedDb(): boolean {\n\treturn typeof indexedDB !== 'undefined';\n}\n\n/** Told apart by shape: a DriveAuth mints tokens, a `{ clientId }` asks us to. */\nfunction isDriveAuth(v: SimpleOptions['drive']): v is DriveAuth {\n\treturn !!v && typeof (v as DriveAuth).token === 'function';\n}\n\n/** Where the connected Drive address is kept, per app: it is what stops Google\n * asking WHICH account at every re-grant. An address is not a secret, and a\n * browser that refuses storage simply gets the chooser back. */\nconst driveAccountKey = (app: string): string => `selfstore.drive.account.${app}`;\n\nfunction localStore<T>(job: (store: Storage) => T): T | undefined {\n\ttry {\n\t\tconst store = globalThis.localStorage;\n\t\treturn store ? job(store) : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction rememberedDriveAccount(app: string): string | undefined {\n\treturn localStore((s) => s.getItem(driveAccountKey(app))) ?? undefined;\n}\n\n/** Learn the account behind a live Drive session, best-effort and once: it feeds\n * the next re-grant's hint, and any surface that wants to name the destination. */\nasync function learnDriveAccount(app: string, auth: DriveAuth): Promise<void> {\n\ttry {\n\t\tconst who = await driveAccount({ auth });\n\t\tif (who.email) localStore((s) => s.setItem(driveAccountKey(app), who.email!));\n\t} catch {\n\t\t// A destination that will not say costs the hint, never the connection.\n\t}\n}\n\n/**\n * Open (or create) the app's local store. Awaits the initial load, so the\n * returned store is ready: data readable, destination restored, first converge\n * done. See SimpleOptions for the defaults.\n */\nexport async function selfstore<\n\tS extends Record<string, SimpleRecord> = Record<string, SimpleRecord>\n>(app: string, options: SimpleOptions = {}): Promise<SimpleStore<S>> {\n\tif (typeof app !== 'string' || app.length === 0) {\n\t\tthrow new TypeError('selfstore: pass your app name, e.g. selfstore(\"my-app\").');\n\t}\n\n\t// The one copy of the data. The engine pulls it on save (gather) and pushes\n\t// into it on restores/folds (apply); the facade's mutators edit it in place\n\t// copy-on-write and schedule a save.\n\tlet collections: Record<string, SimpleRecord[]> = {};\n\t// Binary files ride along untouched (a backup that carries them keeps them);\n\t// managing them is an advanced-store concern.\n\tlet files: SnapshotFile[] = [];\n\n\tconst dataSubs = new Set<() => void>();\n\tconst emitData = (): void => dataSubs.forEach((fn) => fn());\n\n\tconst cache =\n\t\toptions.cache ??\n\t\t(hasIndexedDb()\n\t\t\t? indexedDbCache(app, options.cacheLock ? { lock: true } : undefined)\n\t\t\t: memoryCache());\n\tconst backupName = `${app}.zip`;\n\t// connectDrive() remembers the auth so a later restoreTarget can use it even\n\t// when options.drive was not provided up front (same session only).\n\t//\n\t// `{ clientId }` is the whole wiring done here rather than in every app: ONE\n\t// session (several would mean several consent screens), a token that survives\n\t// a reload, and the account remembered so Google stops asking which one. Each\n\t// of those was a separate decision every consumer had to discover; the app\n\t// that wrote them by hand hit all three as bugs first.\n\tlet driveAuth: DriveAuth | null = isDriveAuth(options.drive)\n\t\t? options.drive\n\t\t: options.drive\n\t\t\t? gisDriveAuth({\n\t\t\t\t\tclientId: options.drive.clientId,\n\t\t\t\t\tscope: options.drive.scope,\n\t\t\t\t\tpersist: 'session',\n\t\t\t\t\thint: () => rememberedDriveAccount(app)\n\t\t\t\t})\n\t\t\t: null;\n\n\t// Ultra-sensitive: unlock the cache before the store hydrates from it. One\n\t// prompt per session, driven by the app (branch it on an existing login to\n\t// keep the UX unchanged). A wrong secret re-prompts; throw to abort.\n\tif (options.cacheLock && isLockableCache(cache)) {\n\t\tlet failed = false;\n\t\twhile (!(await cache.unlock(await options.cacheLock({ failed })))) failed = true;\n\t}\n\n\tconst store = createLocalStore({\n\t\tapp,\n\t\tschemaVersion: options.schema ?? 1,\n\t\tgather: (): Snapshot => structuredClone({ collections, files }),\n\t\tapply: (snap: Snapshot): void => {\n\t\t\tcollections = (snap.collections ?? {}) as Record<string, SimpleRecord[]>;\n\t\t\tfiles = snap.files ?? [];\n\t\t\temitData();\n\t\t},\n\t\tmigrate: options.migrate,\n\t\tsync: options.sync,\n\t\tcache,\n\t\tdebounceMs: options.debounceMs,\n\t\tmultiTab: options.multiTab,\n\t\trequireEncryption: options.requireEncryption,\n\t\tpasswordPolicy: options.passwordPolicy,\n\t\trestoreTarget: async (kind) => {\n\t\t\tif (kind === 'drive' && driveAuth) {\n\t\t\t\treturn driveFromSession({ auth: driveAuth, kv: cache.kv, fileName: backupName });\n\t\t\t}\n\t\t\tif (kind === 'file') return fileFromSession({ kv: cache.kv });\n\t\t\tif (kind === 'webdav') return webdavFromSession({ kv: cache.kv });\n\t\t\treturn null;\n\t\t}\n\t});\n\n\tawait store.init();\n\n\t// A degraded file mode is a verdict about the BROWSER, but it was persisted\n\t// like a property of the data: every later session re-read the word without\n\t// ever asking again. One session that could not open a picker - a browser\n\t// that ships the API and refuses it, a call made a moment too late, a user on\n\t// another browser that day - then pinned download-only mode forever, on a\n\t// Chromium perfectly able to hold a file, with no way back.\n\t//\n\t// Nothing writes this word except a picker that could not deliver, so a\n\t// browser that CAN deliver makes it stale. Re-examined here, in the layer\n\t// that wrote it. Dropping to 'device' is the honest state: manual mode had\n\t// already released the durable target, so there is nothing to detach - only\n\t// a stale claim to stop repeating, and a destination the host can offer again.\n\tif (store.state.targetKind === 'file-manual' && fileIsSupported()) {\n\t\tawait store.detachTarget();\n\t}\n\n\t// Auto-wired sync moments (Spring-Boot-style autoconfiguration): tab focus,\n\t// network return, a slow interval, and save-on-hide. Opt out with\n\t// { autoSync: false } to drive these yourself.\n\tconst teardown: (() => void)[] = [];\n\tif (\n\t\toptions.autoSync !== false &&\n\t\ttypeof document !== 'undefined' &&\n\t\ttypeof window !== 'undefined'\n\t) {\n\t\tconst onVisibility = (): void => {\n\t\t\tif (document.visibilityState === 'hidden') void store.flush();\n\t\t\telse void store.syncIfStale('focus');\n\t\t};\n\t\tconst onOnline = (): void => void store.syncIfStale('online');\n\t\tconst onPageHide = (): void => void store.flush();\n\t\tconst interval = setInterval(() => {\n\t\t\tif (document.visibilityState === 'visible') void store.syncIfStale('interval');\n\t\t}, 5 * 60_000);\n\t\tdocument.addEventListener('visibilitychange', onVisibility);\n\t\twindow.addEventListener('online', onOnline);\n\t\twindow.addEventListener('pagehide', onPageHide);\n\t\tteardown.push(() => {\n\t\t\tclearInterval(interval);\n\t\t\tdocument.removeEventListener('visibilitychange', onVisibility);\n\t\t\twindow.removeEventListener('online', onOnline);\n\t\t\twindow.removeEventListener('pagehide', onPageHide);\n\t\t});\n\t}\n\n\tfunction mutate(collection: string, next: SimpleRecord[]): Promise<void> {\n\t\tcollections = { ...collections, [collection]: next };\n\t\temitData();\n\t\tstore.schedule();\n\t\treturn Promise.resolve();\n\t}\n\n\tasync function connectTarget(\n\t\ttarget: BackupTarget,\n\t\topts: { password?: string } = {}\n\t): Promise<ConnectOutcome> {\n\t\tconst info = await store.inspectTarget(target);\n\t\tif (info.hasBackup) {\n\t\t\t// Another app's backup is refused BEFORE the password question: asking\n\t\t\t// first teaches the user their password \"does not work\" on a file that\n\t\t\t// was never this app's to open.\n\t\t\tif (info.app !== null && info.app !== store.app) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'FOREIGN_BACKUP',\n\t\t\t\t\t`This destination holds a backup written by app \"${info.app}\", not \"${store.app}\". Open it in its own application, or pick another file.`\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Fail before attaching: an encrypted backup without its password would\n\t\t\t// otherwise attach locked, which is a support case, not an outcome.\n\t\t\tif (info.encrypted && !opts.password) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'PASSWORD_REQUIRED',\n\t\t\t\t\t'This destination holds an encrypted backup: pass its password to connect.'\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait store.attachTarget(target, { password: opts.password ?? null, strategy: 'merge' });\n\t\t\treturn 'merged';\n\t\t}\n\t\tawait store.attachTarget(target, {\n\t\t\tpassword: opts.password ?? null,\n\t\t\tstrategy: 'replace-remote'\n\t\t});\n\t\treturn 'started';\n\t}\n\n\tconst simple: SimpleStore<S> = {\n\t\tall<K extends keyof S & string>(collection: K): readonly S[K][] {\n\t\t\treturn (collections[collection] ?? []) as S[K][];\n\t\t},\n\t\tget<K extends keyof S & string>(collection: K, id: string): S[K] | undefined {\n\t\t\tconst field = idFieldOf(options.sync, collection) ?? 'id';\n\t\t\treturn (collections[collection] ?? []).find((r) => r[field] === id) as S[K] | undefined;\n\t\t},\n\t\tput<K extends keyof S & string>(collection: K, record: S[K]): Promise<void> {\n\t\t\tconst field = idFieldOf(options.sync, collection);\n\t\t\tconst id = requireStringId(record, field, collection);\n\t\t\tconst rows = collections[collection] ?? [];\n\t\t\tconst at = field === null ? -1 : rows.findIndex((r) => r[field] === id);\n\t\t\treturn mutate(\n\t\t\t\tcollection,\n\t\t\t\tat === -1 ? [...rows, record] : rows.map((r, i) => (i === at ? record : r))\n\t\t\t);\n\t\t},\n\t\tputAll<K extends keyof S & string>(collection: K, records: S[K][]): Promise<void> {\n\t\t\tconst field = idFieldOf(options.sync, collection);\n\t\t\tconst byId = new Map<unknown, number>();\n\t\t\tfor (const r of records) requireStringId(r, field, collection);\n\t\t\tconst rows = [...(collections[collection] ?? [])];\n\t\t\tif (field !== null) {\n\t\t\t\trows.forEach((r, i) => byId.set(r[field], i));\n\t\t\t\tfor (const r of records) {\n\t\t\t\t\tconst at = byId.get(r[field]);\n\t\t\t\t\tif (typeof at === 'number') rows[at] = r;\n\t\t\t\t\telse rows.push(r);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trows.push(...records);\n\t\t\t}\n\t\t\treturn mutate(collection, rows);\n\t\t},\n\t\tremove<K extends keyof S & string>(collection: K, id: string): Promise<void> {\n\t\t\tconst field = idFieldOf(options.sync, collection) ?? 'id';\n\t\t\tconst rows = collections[collection] ?? [];\n\t\t\tconst next = rows.filter((r) => r[field] !== id);\n\t\t\treturn next.length === rows.length ? Promise.resolve() : mutate(collection, next);\n\t\t},\n\t\tclear<K extends keyof S & string>(collection: K): Promise<void> {\n\t\t\tif ((collections[collection] ?? []).length === 0) return Promise.resolve();\n\t\t\treturn mutate(collection, []);\n\t\t},\n\t\tonChange(fn: () => void): () => void {\n\t\t\tdataSubs.add(fn);\n\t\t\treturn () => dataSubs.delete(fn);\n\t\t},\n\n\t\tasync connectDrive(auth: DriveAuth, opts?: { password?: string }): Promise<ConnectOutcome> {\n\t\t\tdriveAuth = auth;\n\t\t\tconst target = await driveConnect({ auth, kv: cache.kv, fileName: backupName });\n\t\t\tif (!target) return 'cancelled';\n\t\t\tconst outcome = await connectTarget(target, opts);\n\t\t\t// Learn WHICH account now that there is a session: it is the hint that\n\t\t\t// keeps the chooser away next time, and the name a panel can show. Not\n\t\t\t// awaited into the outcome - a slow metadata call must not delay the\n\t\t\t// connect the user is waiting on.\n\t\t\tif (outcome !== 'cancelled') void learnDriveAccount(app, auth);\n\t\t\treturn outcome;\n\t\t},\n\t\tasync connectFile(opts?: { password?: string }): Promise<ConnectOutcome> {\n\t\t\t// Asked twice on purpose: the first call answers from what the browser\n\t\t\t// exposes, the second from what it did when actually asked. A browser\n\t\t\t// that ships the picker and then refuses it only tells us so here.\n\t\t\tif (fileIsSupported()) {\n\t\t\t\tconst target = await fileConnect({ kv: cache.kv, fileName: backupName });\n\t\t\t\tif (target) return connectTarget(target, opts);\n\t\t\t\tif (fileIsSupported()) return 'cancelled';\n\t\t\t}\n\t\t\tawait store.setManualFile();\n\t\t\treturn 'manual';\n\t\t},\n\t\tasync connectWebdav(\n\t\t\tconfig: WebdavConfig,\n\t\t\topts?: { password?: string }\n\t\t): Promise<ConnectOutcome> {\n\t\t\tconst target = await webdavConnect({ kv: cache.kv, config });\n\t\t\tif (!target) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'TARGET_UNAVAILABLE',\n\t\t\t\t\t'The WebDAV server did not answer (URL, credentials or CORS).'\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn connectTarget(target, opts);\n\t\t},\n\t\tasync connectS3(config: S3Config, opts?: { password?: string }): Promise<ConnectOutcome> {\n\t\t\tconst target = await s3Connect({ kv: cache.kv, config });\n\t\t\tif (!target) {\n\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t'TARGET_UNAVAILABLE',\n\t\t\t\t\t'The S3 endpoint did not answer (endpoint, credentials or CORS).'\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn connectTarget(target, opts);\n\t\t},\n\t\tconnectTarget,\n\t\tdisconnect: () => store.detachTarget(),\n\t\taddReplica: (target, opts) => store.attachReplica(target, opts),\n\t\tremoveReplica: (id) => store.detachReplica(id),\n\n\t\tprotect: (password: string) => store.setEncryption(password),\n\t\tunprotect: () => store.setEncryption(null),\n\t\tunlock: (password: string) => store.unlock(password),\n\t\treconnect: () => store.reconnect(),\n\n\t\texportBackup: () => store.exportBlob(),\n\t\tasync downloadBackup(filename?: string): Promise<boolean> {\n\t\t\tconst written = await saveToDisk(await store.exportBlob(), filename ?? backupName);\n\t\t\t// Clearing the pending flag on a cancelled dialog would drop the very\n\t\t\t// nudge that asks for the file the user still does not have.\n\t\t\tif (written) store.markDownloaded();\n\t\t\treturn written;\n\t\t},\n\t\tasync importBackup(file: Blob | Uint8Array, opts?: { password?: string }): Promise<void> {\n\t\t\t// The fluent read() strips reserved bookkeeping collections; removals\n\t\t\t// then propagate because the next save diffs against the sync meta.\n\t\t\tconst reader = restore(file);\n\t\t\tconst snap = opts?.password\n\t\t\t\t? await reader.withPassword(opts.password).read()\n\t\t\t\t: await reader.read();\n\t\t\tcollections = (snap.collections ?? {}) as Record<string, SimpleRecord[]>;\n\t\t\tfiles = snap.files ?? [];\n\t\t\temitData();\n\t\t\tstore.schedule();\n\t\t},\n\n\t\tget status(): StatusDescriptor {\n\t\t\treturn store.state.status;\n\t\t},\n\t\tget error(): StoreError | null {\n\t\t\treturn store.state.lastError;\n\t\t},\n\t\tget state(): LocalStoreState {\n\t\t\treturn store.state;\n\t\t},\n\t\tsubscribe: (fn: () => void) => store.subscribe(fn),\n\n\t\tflush: () => store.flush(),\n\t\tasync sync(): Promise<void> {\n\t\t\tawait store.syncNow();\n\t\t},\n\t\tdispose(): void {\n\t\t\tteardown.forEach((fn) => fn());\n\t\t\tteardown.length = 0;\n\t\t\tstore.dispose();\n\t\t},\n\n\t\tadvanced: store,\n\n\t\tflowHost: { engine: store, kv: cache.kv, backupName },\n\n\t\tget account(): string | null {\n\t\t\treturn rememberedDriveAccount(app) ?? null;\n\t\t},\n\n\t\tresumeOffer(): ResumeOffer | null {\n\t\t\tconst detail = rememberedDriveAccount(app);\n\t\t\tif (!driveAuth || !detail) return null;\n\t\t\tconst auth = driveAuth;\n\t\t\treturn {\n\t\t\t\tkind: 'drive',\n\t\t\t\tdetail,\n\t\t\t\t// Reopening is not searching: fromSession takes the file id already\n\t\t\t\t// remembered, where a fresh connect resolves by name and could land on\n\t\t\t\t// another file carrying the same one.\n\t\t\t\tconnect: () => driveFromSession({ auth, kv: cache.kv, fileName: backupName })\n\t\t\t};\n\t\t}\n\t};\n\n\treturn simple;\n}\n"]}
@@ -0,0 +1,100 @@
1
+ import { o as Snapshot, E as EncodeOptions, H as Header } from './store-CiLoRJmy.js';
2
+ import { a as DriveAuth } from './drive-B2fm71qD.js';
3
+
4
+ /** Serialize a snapshot to a portable backup blob (compressed; encrypted if a password is given). */
5
+ declare function exportSnapshot(snapshot: Snapshot, opts: EncodeOptions): Promise<Blob>;
6
+ /** Read a backup blob (or raw bytes) back into a snapshot. */
7
+ declare function importSnapshot(input: Blob | Uint8Array, opts?: {
8
+ password?: string;
9
+ }): Promise<Snapshot>;
10
+ /** Peek at a backup's cleartext metadata (app, date, whether it's encrypted) without decrypting. */
11
+ declare function inspect(input: Blob | Uint8Array): Promise<Header>;
12
+ /** True if the backup needs a password to import. */
13
+ declare function isEncrypted(input: Blob | Uint8Array): Promise<boolean>;
14
+ /** Re-encrypt under a new password. `from` opens the file, `to` protects the
15
+ * result; omit `to` for an unencrypted backup. */
16
+ declare function changePassword(input: Blob | Uint8Array, opts: {
17
+ from?: string;
18
+ to?: string;
19
+ readme?: string;
20
+ }): Promise<Blob>;
21
+
22
+ /**
23
+ * A client-only DriveAuth: the Google Identity Services token flow, no backend.
24
+ *
25
+ * What this flow can and cannot do, because it decides how often a user is
26
+ * interrupted. Google's browser token flow issues an access token that lives
27
+ * about an hour and NO refresh token - a refresh token requires a client secret,
28
+ * which requires a server. And `requestAccessToken` always opens a popup, even
29
+ * with `prompt: ''`: the popup closes by itself when the grant is still on file,
30
+ * but opening it at all needs a user gesture. So a purely client-side app cannot
31
+ * silently re-acquire a token on page load. What it CAN do:
32
+ *
33
+ * - reuse a token it already has (`persist: 'session'`), so a reload inside the
34
+ * hour asks for nothing at all;
35
+ * - name the account (`hint`), so the popup does not ask which one;
36
+ * - re-grant without the consent screen (`prompt: ''` before `'consent'`) -
37
+ * which is also what stops Google mailing "you granted access" every time.
38
+ *
39
+ * For a connection that never re-prompts, back the Drive target with a server
40
+ * that holds a refresh token instead (a broker implementing this same DriveAuth).
41
+ */
42
+
43
+ /** Where the access token survives between requests. */
44
+ type GisTokenPersistence = 'memory' | 'session';
45
+ interface GisDriveAuthOptions {
46
+ clientId: string;
47
+ scope?: string;
48
+ /**
49
+ * The account to re-grant for, so the popup does not ask which one. Pass the
50
+ * address the app remembers (`driveTarget.account()` answers it once
51
+ * connected); a function is read at every request, for a host that only
52
+ * learns it after the first connect.
53
+ */
54
+ hint?: string | (() => string | null | undefined);
55
+ /**
56
+ * Where the access token lives between requests.
57
+ *
58
+ * `'memory'` (the default) keeps it in a closure and nowhere else: a reload
59
+ * has to re-acquire it, which needs a click, but no Drive-scoped credential is
60
+ * ever written to web storage.
61
+ *
62
+ * `'session'` also keeps it in `sessionStorage`, so a reload reuses the token
63
+ * it already has and asks for nothing. That token is a bearer credential for
64
+ * the `drive.file` scope, readable by any script on the origin; it dies with
65
+ * the tab and within the hour. Opt in for an app whose users reload often;
66
+ * leave it alone where an XSS on the origin must find nothing to lift.
67
+ */
68
+ persist?: GisTokenPersistence;
69
+ }
70
+ /** Build a client-only DriveAuth for the given OAuth client id (no backend). */
71
+ declare function gisDriveAuth(opts: GisDriveAuthOptions): DriveAuth;
72
+
73
+ /**
74
+ * Save a backup blob to disk via the File System Access API, else a download.
75
+ *
76
+ * Resolves TRUE when bytes were handed to the browser, FALSE when the user
77
+ * closed the save dialog. Callers must branch on it: a host that records "last
78
+ * backup: today" after a cancelled dialog tells the user they are safe when no
79
+ * file exists, and that lie only surfaces the day they need the file.
80
+ *
81
+ * Takes a ready blob, so the dialog opens only after the blob was built. When
82
+ * that blob is an encrypted backup, prefer asking first: see pickSaveHandle.
83
+ */
84
+ declare function saveToDisk(blob: Blob, filename: string): Promise<boolean>;
85
+ /**
86
+ * The same name, stamped to the minute.
87
+ *
88
+ * Used only on the download path, and the reasoning is worth stating because it
89
+ * looks backwards. Through a handle the app rewrites the SAME file, so the name
90
+ * must stay stable. A download never replaces anything: the browser appends
91
+ * " (1)", " (2)", and no web API can stop it. The pile forms either way - so it
92
+ * may as well be readable. A dated series says at a glance which one is the
93
+ * latest and lets the user step back to an earlier one; "backup (7).zip" says
94
+ * neither when, nor in what order.
95
+ */
96
+ declare function datedName(filename: string, when?: Date): string;
97
+ /** Prompt the user to pick a backup file from disk. Resolves null if cancelled. */
98
+ declare function pickFromDisk(): Promise<File | null>;
99
+
100
+ export { type GisDriveAuthOptions as G, type GisTokenPersistence as a, inspect as b, isEncrypted as c, datedName as d, exportSnapshot as e, changePassword as f, gisDriveAuth as g, importSnapshot as i, pickFromDisk as p, saveToDisk as s };
@@ -1,5 +1,5 @@
1
1
  import { K as KV } from './cache-ilsK3Tki.js';
2
- import { B as BackupTarget, L as LocalStore } from './store-BiQ-BuVl.js';
2
+ import { B as BackupTarget, L as LocalStore } from './store-CiLoRJmy.js';
3
3
  import { F as FlowStore } from './machine-ALMkT3mk.js';
4
4
 
5
5
  /** What the destination reports about a listed file (one cheap metadata call). */
@@ -1,4 +1,4 @@
1
- import { B as BackupTarget, P as PeerSource } from './store-BiQ-BuVl.js';
1
+ import { B as BackupTarget, P as PeerSource } from './store-CiLoRJmy.js';
2
2
  import { K as KV } from './cache-ilsK3Tki.js';
3
3
 
4
4
  /**
@@ -594,4 +594,4 @@ interface LocalStore {
594
594
  }
595
595
  declare function createLocalStore(opts: LocalStoreOptions): LocalStore;
596
596
 
597
- export { AuthExpiredError as A, type BackupTarget as B, errorLabelKey as C, isAuthExpired as D, type EncodeOptions as E, isReservedStoreMode as F, isSelfstoreError as G, type Header as H, type KdfParams as K, type LocalStore as L, type MirrorState as M, type PeerSource as P, RESERVED_COLLECTION_PREFIX as R, SelfstoreError as S, type TargetKind as T, type BuiltinTargetKind as a, type LocalStoreOptions as b, type LocalStoreState as c, type Mode as d, type PasswordCheck as e, type PasswordPolicy as f, type PasswordRequirement as g, type PeerState as h, RESERVED_STORE_MODES as i, type RecipientStanza as j, type ReplicaState as k, type SelfstoreErrorCode as l, type Severity as m, type Snapshot as n, type SnapshotFile as o, type StatusAction as p, type StatusDescriptor as q, type StatusInput as r, type StorageState as s, type StoreError as t, type StoreGroupConfig as u, type SyncJournalEntry as v, type SyncSource as w, checkPasswordPolicy as x, createLocalStore as y, deriveStatus as z };
597
+ export { AuthExpiredError as A, type BackupTarget as B, errorLabelKey as C, isAuthExpired as D, type EncodeOptions as E, isReservedStoreMode as F, isSelfstoreError as G, type Header as H, type KdfParams as K, type LocalStore as L, type MirrorState as M, type PeerSource as P, RESERVED_COLLECTION_PREFIX as R, type StoreError as S, type TargetKind as T, type BuiltinTargetKind as a, type LocalStoreOptions as b, type LocalStoreState as c, type Mode as d, type PasswordCheck as e, type PasswordPolicy as f, type PasswordRequirement as g, type PeerState as h, RESERVED_STORE_MODES as i, type RecipientStanza as j, type ReplicaState as k, SelfstoreError as l, type SelfstoreErrorCode as m, type Severity as n, type Snapshot as o, type SnapshotFile as p, type StatusAction as q, type StatusDescriptor as r, type StatusInput as s, type StorageState as t, type StoreGroupConfig as u, type SyncJournalEntry as v, type SyncSource as w, checkPasswordPolicy as x, createLocalStore as y, deriveStatus as z };
package/dist/widgets.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- import { F as FlowHost, S as StoreLike, C as ConnectTargets, a as ConnectFlowOptions, b as ConnectKind, c as ConnectFlow, d as ShareEngine, e as ShareLevel, f as ShareFlow, J as JoinEngine, g as JoinFlow, R as ReplicaFlow } from './flows-vX9zy9bI.js';
2
- import { f as BackupsManager } from './manager-DZ1c_aSS.js';
3
- import './store-BiQ-BuVl.js';
1
+ import { F as FlowHost, S as StoreLike, C as ConnectTargets, a as ConnectFlowOptions, b as ConnectKind, c as ConnectFlow } from './connect-DaZFPJdt.js';
2
+ import { ShareEngine, ShareLevel, ShareFlow, JoinEngine, JoinFlow, ReplicaFlow } from './flows.js';
3
+ import { f as BackupsManager } from './manager-BqzTVaep.js';
4
+ import './store-CiLoRJmy.js';
4
5
  import './cache-ilsK3Tki.js';
5
6
  import './sync.js';
6
- import './drive-CTYvGg_7.js';
7
- import './s3-DvsnA-FK.js';
7
+ import './drive-B2fm71qD.js';
8
+ import './s3-DgyTwMRc.js';
8
9
  import './machine-ALMkT3mk.js';
9
10
 
10
11
  /** Flat key -> string map; widgets merge a partial override over EN defaults. */
package/dist/widgets.js CHANGED
@@ -3479,6 +3479,7 @@ var SelfstoreGateElement = class extends FlowWidget {
3479
3479
  shouldOpen() {
3480
3480
  const host = this.host();
3481
3481
  if (!host || !this.#armed || this.#deferred) return false;
3482
+ if (!host.engine.state.ready) return false;
3482
3483
  return host.engine.state.status.action === "choose-destination";
3483
3484
  }
3484
3485
  sync() {