selfstore 1.8.2 → 1.8.3
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 +8 -4
- package/dist/advanced.js +14 -13
- package/dist/advanced.js.map +1 -1
- package/dist/backups.d.ts +31 -179
- package/dist/backups.js +40 -3
- package/dist/backups.js.map +1 -1
- package/dist/{cache-lock-RCN3JJ4Q.js → cache-lock-KWJUORTS.js} +3 -4
- package/dist/cache-lock-KWJUORTS.js.map +1 -0
- package/dist/{chunk-HK4VPO65.js → chunk-3OBJOMQ2.js} +28 -4
- package/dist/chunk-3OBJOMQ2.js.map +1 -0
- package/dist/{chunk-HDR75TQ7.js → chunk-DCEXWSM6.js} +3 -3
- package/dist/{chunk-HDR75TQ7.js.map → chunk-DCEXWSM6.js.map} +1 -1
- package/dist/{chunk-7N2YR3QW.js → chunk-ELDSPUTS.js} +7 -8
- package/dist/chunk-ELDSPUTS.js.map +1 -0
- package/dist/chunk-J5MFXJU6.js +310 -0
- package/dist/chunk-J5MFXJU6.js.map +1 -0
- package/dist/{chunk-BNDFMU3J.js → chunk-MGDXR3RB.js} +5 -6
- package/dist/chunk-MGDXR3RB.js.map +1 -0
- package/dist/{chunk-453KRCMM.js → chunk-O3Y6FORN.js} +3 -4
- package/dist/chunk-O3Y6FORN.js.map +1 -0
- package/dist/{chunk-JMJZIZKY.js → chunk-PNX7AJYO.js} +13 -12
- package/dist/chunk-PNX7AJYO.js.map +1 -0
- package/dist/{chunk-5NS7YQNP.js → chunk-TKWU52LK.js} +26 -312
- package/dist/chunk-TKWU52LK.js.map +1 -0
- package/dist/{chunk-U5F4GI7C.js → chunk-W22V5CRM.js} +3 -3
- package/dist/{chunk-U5F4GI7C.js.map → chunk-W22V5CRM.js.map} +1 -1
- package/dist/{drive-l_4-m1eT.d.ts → drive-CTYvGg_7.d.ts} +23 -110
- package/dist/{flows-C_uookek.d.ts → flows-1EntUZ91.d.ts} +2 -1
- package/dist/flows.d.ts +3 -2
- package/dist/flows.js +16 -16
- package/dist/flows.js.map +1 -1
- package/dist/groups.js +3 -4
- package/dist/groups.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/{local-bfv4Ld7s.d.ts → local-C52j3DeH.d.ts} +1 -1
- package/dist/local-DPS35F5C.js +6 -0
- package/dist/{local-2YREU4Q2.js.map → local-DPS35F5C.js.map} +1 -1
- package/dist/manager-DZ1c_aSS.d.ts +181 -0
- package/dist/s3-DvsnA-FK.d.ts +112 -0
- package/dist/widgets.d.ts +4 -3
- package/dist/widgets.js +7 -7
- package/package.json +1 -1
- package/dist/cache-lock-RCN3JJ4Q.js.map +0 -1
- package/dist/chunk-453KRCMM.js.map +0 -1
- package/dist/chunk-5NS7YQNP.js.map +0 -1
- package/dist/chunk-7N2YR3QW.js.map +0 -1
- package/dist/chunk-BNDFMU3J.js.map +0 -1
- package/dist/chunk-CPN2KUD5.js +0 -29
- package/dist/chunk-CPN2KUD5.js.map +0 -1
- package/dist/chunk-HK4VPO65.js.map +0 -1
- package/dist/chunk-JMJZIZKY.js.map +0 -1
- package/dist/local-2YREU4Q2.js +0 -7
package/dist/advanced.d.ts
CHANGED
|
@@ -2,9 +2,11 @@ import { B as BackupTarget } from './store-BiQ-BuVl.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, e as PasswordCheck, f as PasswordPolicy, g as PasswordRequirement, P 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-BiQ-BuVl.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 { d as datedName, e as exportSnapshot, g as gisDriveAuth, i as importSnapshot, a as inspect, b as isEncrypted, p as pickFromDisk, s as saveToDisk } from './local-
|
|
6
|
-
import { c as connect$
|
|
7
|
-
export {
|
|
5
|
+
export { d as datedName, e as exportSnapshot, g as gisDriveAuth, i as importSnapshot, a as inspect, b as isEncrypted, p as pickFromDisk, s as saveToDisk } from './local-C52j3DeH.js';
|
|
6
|
+
import { c as connect$2, f as fromSession$2, a as connect$3, b as fromSession$3, p as peer } from './s3-DvsnA-FK.js';
|
|
7
|
+
export { S as S3Config, d as S3ConnectOptions, W as WebdavConfig, e as WebdavConnectOptions, g as WebdavPeerOptions } from './s3-DvsnA-FK.js';
|
|
8
|
+
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 account } from './drive-CTYvGg_7.js';
|
|
9
|
+
export { h as DriveAccount, i as DriveAuth, j as DriveBackupInfo, D as DriveOptions } from './drive-CTYvGg_7.js';
|
|
8
10
|
import './sync.js';
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -143,7 +145,8 @@ declare const s3Target: {
|
|
|
143
145
|
* file, adopt it as this device's backup, find-or-create the user's own file)
|
|
144
146
|
* and the backup-management ops (list the app's files with dates, create a
|
|
145
147
|
* named empty backup, rename one, delete one for good) - the raw pieces a "my
|
|
146
|
-
* backups" panel builds on.
|
|
148
|
+
* backups" panel builds on. `account()` names WHICH Google account holds them,
|
|
149
|
+
* because a brand name is not an address. */
|
|
147
150
|
declare const driveTarget: {
|
|
148
151
|
connect: typeof connect$1;
|
|
149
152
|
fromSession: typeof fromSession$1;
|
|
@@ -154,6 +157,7 @@ declare const driveTarget: {
|
|
|
154
157
|
createBackup: typeof createBackup;
|
|
155
158
|
deleteBackup: typeof deleteBackup;
|
|
156
159
|
renameBackup: typeof renameBackup;
|
|
160
|
+
account: typeof account;
|
|
157
161
|
FILE_ID_KEY: string;
|
|
158
162
|
};
|
|
159
163
|
|
package/dist/advanced.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { RESERVED_STORE_MODES, createLocalStore, deriveStatus, gisDriveAuth, indexedDbCache, isLockableCache, isReservedStoreMode, memoryCache } from './chunk-
|
|
2
|
-
export { datedName, pickFromDisk, saveToDisk } from './chunk-
|
|
1
|
+
export { RESERVED_STORE_MODES, createLocalStore, deriveStatus, gisDriveAuth, indexedDbCache, isLockableCache, isReservedStoreMode, memoryCache } from './chunk-ELDSPUTS.js';
|
|
2
|
+
export { datedName, pickFromDisk, saveToDisk } from './chunk-DCEXWSM6.js';
|
|
3
3
|
import './chunk-SKWHKM25.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { openExisting, isOpenSupported, isSupported, fromSession as fromSession$1, connect as connect$1, fromSession3, connect3, peer, fromSession2, connect2 } from './chunk-TKWU52LK.js';
|
|
5
|
+
import { FILE_ID_KEY, account, renameBackup, deleteBackup, createBackup, listBackups, findOrCreateOwnFile, adopt, preview, fromSession, connect } from './chunk-J5MFXJU6.js';
|
|
6
|
+
export { RESERVED_COLLECTION_PREFIX, checkPasswordPolicy, exportSnapshot, importSnapshot, inspect, isEncrypted } from './chunk-MGDXR3RB.js';
|
|
7
7
|
import './chunk-QBCU7OOP.js';
|
|
8
|
-
import './chunk-
|
|
9
|
-
export { AuthExpiredError, SelfstoreError, errorLabelKey, isAuthExpired, isSelfstoreError } from './chunk-
|
|
8
|
+
import './chunk-O3Y6FORN.js';
|
|
9
|
+
export { AuthExpiredError, SelfstoreError, errorLabelKey, isAuthExpired, isSelfstoreError } from './chunk-3OBJOMQ2.js';
|
|
10
10
|
|
|
11
11
|
// src/persistence/installation.ts
|
|
12
12
|
function isSafari(ua) {
|
|
@@ -36,8 +36,8 @@ function storageAdvice() {
|
|
|
36
36
|
|
|
37
37
|
// src/entries/advanced.ts
|
|
38
38
|
var fileTarget = {
|
|
39
|
-
connect:
|
|
40
|
-
fromSession:
|
|
39
|
+
connect: connect$1,
|
|
40
|
+
fromSession: fromSession$1,
|
|
41
41
|
isSupported,
|
|
42
42
|
isOpenSupported,
|
|
43
43
|
/** Let the user point at an EXISTING backup file and adopt it as the
|
|
@@ -46,13 +46,13 @@ var fileTarget = {
|
|
|
46
46
|
openExisting
|
|
47
47
|
};
|
|
48
48
|
var webdavTarget = {
|
|
49
|
-
connect:
|
|
50
|
-
fromSession:
|
|
49
|
+
connect: connect2,
|
|
50
|
+
fromSession: fromSession2,
|
|
51
51
|
peer
|
|
52
52
|
};
|
|
53
53
|
var s3Target = {
|
|
54
|
-
connect:
|
|
55
|
-
fromSession:
|
|
54
|
+
connect: connect3,
|
|
55
|
+
fromSession: fromSession3
|
|
56
56
|
};
|
|
57
57
|
var driveTarget = {
|
|
58
58
|
connect,
|
|
@@ -64,6 +64,7 @@ var driveTarget = {
|
|
|
64
64
|
createBackup,
|
|
65
65
|
deleteBackup,
|
|
66
66
|
renameBackup,
|
|
67
|
+
account,
|
|
67
68
|
FILE_ID_KEY
|
|
68
69
|
};
|
|
69
70
|
|
package/dist/advanced.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/persistence/installation.ts","../src/entries/advanced.ts"],"names":["connect","fromSession"],"mappings":";;;;;;;;;;;AAuCA,SAAS,SAAS,EAAA,EAAqB;AACtC,EAAA,OAAO,UAAA,CAAW,IAAA,CAAK,EAAE,CAAA,IAAK,CAAC,uBAAA,CAAwB,IAAA,CAAK,EAAE,CAAA,IAAK,CAAC,eAAA,CAAgB,IAAA,CAAK,EAAE,CAAA;AAC5F;AAEA,SAAS,YAAA,GAAwB;AAChC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,KAAA;AAC1C,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,UAAA,GAAa,4BAA4B,GAAG,OAAA,KAAY,IAAA;AAEnF,EAAA,MAAM,GAAA,GAAO,UAAmD,UAAA,KAAe,IAAA;AAC/E,EAAA,OAAO,WAAA,IAAe,GAAA;AACvB;AAOO,SAAS,aAAA,GAA+B;AAC9C,EAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,OAAO,WAAW,WAAA,EAAa;AACtE,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAM;AAAA,EACzC;AACA,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,IAAI,CAAC,QAAA,CAAS,SAAA,CAAU,SAAS,KAAK,SAAA,EAAW;AAChD,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAA,EAAU;AAAA,EAClC;AACA,EAAA,MAAM,QAAQ,kBAAA,CAAmB,IAAA,CAAK,UAAU,SAAS,CAAA,IAAK,UAAU,cAAA,GAAiB,CAAA;AACzF,EAAA,OAAO;AAAA,IACN,IAAA,EAAM,mBAAA;AAAA,IACN,MAAA,EAAQ,QAAQ,wBAAA,GAA2B,iBAAA;AAAA,IAC3C,SAAA,EAAW;AAAA,GACZ;AACD;;;AC6DO,IAAM,UAAA,GAAa;AAAA,EACzB,OAAA,EAASA,QAAAA;AAAA,EACT,WAAA,EAAaC,YAAAA;AAAA,EACb,WAAA;AAAA,EACA,eAAA;AAAA;AAAA;AAAA;AAAA,EAIA;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 * Whether this browser will keep the local store, and what the user can do\n * about it.\n *\n * One browser does not merely inconvenience a local-first app, it DELETES its\n * data: Safari erases script-writable storage after seven days of browser use\n * without interaction with the site. Someone who closes for three weeks comes\n * back to an empty app, and nothing warned them - which is also the moment they\n * notice it last.\n *\n * Adding the app to the Dock or the Home Screen switches its storage to\n * persistent mode, which WebKit exempts from its eviction triggers. WebKit does\n * not write anywhere that this neutralises the inactivity rule by name, so this\n * module reports an advisory, never a guarantee.\n *\n * The library ships no user-facing copy: it names the situation, the host writes\n * the sentence.\n */\n\n/** What stands between this browser and keeping the data. */\nexport type StorageRisk =\n\t/** Nothing known against it: the store survives until the user clears it. */\n\t| 'none'\n\t/** Data is erased when the tab closes (private browsing). Refuse to set up here. */\n\t| 'ephemeral'\n\t/** Erased after a stretch of not opening the app, unless it is installed. */\n\t| 'evicted-when-idle';\n\nexport interface StorageAdvice {\n\trisk: StorageRisk;\n\t/** The gesture that removes the risk, when there is one. Stable key; the\n\t * host owns the wording and the platform-specific instructions. */\n\tremedy?: 'install-to-dock' | 'install-to-home-screen';\n\t/** Already running as an installed app, so the remedy is done. */\n\tinstalled: boolean;\n}\n\n/** Real Safari, not Chrome or Edge on macOS - all three carry \"Safari\" in the\n * user agent, and only Safari carries none of the others' tokens. */\nfunction isSafari(ua: string): boolean {\n\treturn /Safari\\//.test(ua) && !/Chrome|Chromium|Edg\\//.test(ua) && !/OPR\\/|Android/.test(ua);\n}\n\nfunction isStandalone(): boolean {\n\tif (typeof window === 'undefined') return false;\n\tconst displayMode = window.matchMedia?.('(display-mode: standalone)')?.matches === true;\n\t// iOS and iPadOS kept their own flag, older than display-mode.\n\tconst ios = (navigator as Navigator & { standalone?: boolean }).standalone === true;\n\treturn displayMode || ios;\n}\n\n/**\n * What this browser will do with the local store, and the one gesture that\n * changes it. Call it before setting up, and again in whatever screen owns the\n * data: the advice disappears on its own once the remedy is applied.\n */\nexport function storageAdvice(): StorageAdvice {\n\tif (typeof navigator === 'undefined' || typeof window === 'undefined') {\n\t\treturn { risk: 'none', installed: false };\n\t}\n\tconst installed = isStandalone();\n\tif (!isSafari(navigator.userAgent) || installed) {\n\t\treturn { risk: 'none', installed };\n\t}\n\tconst touch = /iPhone|iPad|iPod/.test(navigator.userAgent) || navigator.maxTouchPoints > 1;\n\treturn {\n\t\trisk: 'evicted-when-idle',\n\t\tremedy: touch ? 'install-to-home-screen' : 'install-to-dock',\n\t\tinstalled: false\n\t};\n}\n","/**\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// --- Will this browser keep the data, and what can the user do about it ---\nexport { storageAdvice, type StorageAdvice, type StorageRisk } from '../persistence/installation';\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\topenExisting as fileOpenExisting\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\t/** Let the user point at an EXISTING backup file and adopt it as the\n\t * destination. Gate on isOpenSupported(): unlike creating, this has no\n\t * download fallback. */\n\topenExisting: fileOpenExisting\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, datedName } from '../selfstore/targets/local';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/persistence/installation.ts","../src/entries/advanced.ts"],"names":["connect","fromSession"],"mappings":";;;;;;;;;;;AAuCA,SAAS,SAAS,EAAA,EAAqB;AACtC,EAAA,OAAO,UAAA,CAAW,IAAA,CAAK,EAAE,CAAA,IAAK,CAAC,uBAAA,CAAwB,IAAA,CAAK,EAAE,CAAA,IAAK,CAAC,eAAA,CAAgB,IAAA,CAAK,EAAE,CAAA;AAC5F;AAEA,SAAS,YAAA,GAAwB;AAChC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,KAAA;AAC1C,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,UAAA,GAAa,4BAA4B,GAAG,OAAA,KAAY,IAAA;AAEnF,EAAA,MAAM,GAAA,GAAO,UAAmD,UAAA,KAAe,IAAA;AAC/E,EAAA,OAAO,WAAA,IAAe,GAAA;AACvB;AAOO,SAAS,aAAA,GAA+B;AAC9C,EAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,OAAO,WAAW,WAAA,EAAa;AACtE,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAM;AAAA,EACzC;AACA,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,IAAI,CAAC,QAAA,CAAS,SAAA,CAAU,SAAS,KAAK,SAAA,EAAW;AAChD,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAA,EAAU;AAAA,EAClC;AACA,EAAA,MAAM,QAAQ,kBAAA,CAAmB,IAAA,CAAK,UAAU,SAAS,CAAA,IAAK,UAAU,cAAA,GAAiB,CAAA;AACzF,EAAA,OAAO;AAAA,IACN,IAAA,EAAM,mBAAA;AAAA,IACN,MAAA,EAAQ,QAAQ,wBAAA,GAA2B,iBAAA;AAAA,IAC3C,SAAA,EAAW;AAAA,GACZ;AACD;;;AC8DO,IAAM,UAAA,GAAa;AAAA,EACzB,OAAA,EAASA,SAAAA;AAAA,EACT,WAAA,EAAaC,aAAAA;AAAA,EACb,WAAA;AAAA,EACA,eAAA;AAAA;AAAA;AAAA;AAAA,EAIA;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;AAQO,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,OAAA;AAAA,EACA;AACD","file":"advanced.js","sourcesContent":["/**\n * Whether this browser will keep the local store, and what the user can do\n * about it.\n *\n * One browser does not merely inconvenience a local-first app, it DELETES its\n * data: Safari erases script-writable storage after seven days of browser use\n * without interaction with the site. Someone who closes for three weeks comes\n * back to an empty app, and nothing warned them - which is also the moment they\n * notice it last.\n *\n * Adding the app to the Dock or the Home Screen switches its storage to\n * persistent mode, which WebKit exempts from its eviction triggers. WebKit does\n * not write anywhere that this neutralises the inactivity rule by name, so this\n * module reports an advisory, never a guarantee.\n *\n * The library ships no user-facing copy: it names the situation, the host writes\n * the sentence.\n */\n\n/** What stands between this browser and keeping the data. */\nexport type StorageRisk =\n\t/** Nothing known against it: the store survives until the user clears it. */\n\t| 'none'\n\t/** Data is erased when the tab closes (private browsing). Refuse to set up here. */\n\t| 'ephemeral'\n\t/** Erased after a stretch of not opening the app, unless it is installed. */\n\t| 'evicted-when-idle';\n\nexport interface StorageAdvice {\n\trisk: StorageRisk;\n\t/** The gesture that removes the risk, when there is one. Stable key; the\n\t * host owns the wording and the platform-specific instructions. */\n\tremedy?: 'install-to-dock' | 'install-to-home-screen';\n\t/** Already running as an installed app, so the remedy is done. */\n\tinstalled: boolean;\n}\n\n/** Real Safari, not Chrome or Edge on macOS - all three carry \"Safari\" in the\n * user agent, and only Safari carries none of the others' tokens. */\nfunction isSafari(ua: string): boolean {\n\treturn /Safari\\//.test(ua) && !/Chrome|Chromium|Edg\\//.test(ua) && !/OPR\\/|Android/.test(ua);\n}\n\nfunction isStandalone(): boolean {\n\tif (typeof window === 'undefined') return false;\n\tconst displayMode = window.matchMedia?.('(display-mode: standalone)')?.matches === true;\n\t// iOS and iPadOS kept their own flag, older than display-mode.\n\tconst ios = (navigator as Navigator & { standalone?: boolean }).standalone === true;\n\treturn displayMode || ios;\n}\n\n/**\n * What this browser will do with the local store, and the one gesture that\n * changes it. Call it before setting up, and again in whatever screen owns the\n * data: the advice disappears on its own once the remedy is applied.\n */\nexport function storageAdvice(): StorageAdvice {\n\tif (typeof navigator === 'undefined' || typeof window === 'undefined') {\n\t\treturn { risk: 'none', installed: false };\n\t}\n\tconst installed = isStandalone();\n\tif (!isSafari(navigator.userAgent) || installed) {\n\t\treturn { risk: 'none', installed };\n\t}\n\tconst touch = /iPhone|iPad|iPod/.test(navigator.userAgent) || navigator.maxTouchPoints > 1;\n\treturn {\n\t\trisk: 'evicted-when-idle',\n\t\tremedy: touch ? 'install-to-home-screen' : 'install-to-dock',\n\t\tinstalled: false\n\t};\n}\n","/**\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// --- Will this browser keep the data, and what can the user do about it ---\nexport { storageAdvice, type StorageAdvice, type StorageRisk } from '../persistence/installation';\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\topenExisting as fileOpenExisting\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\taccount as driveAccount,\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\t/** Let the user point at an EXISTING backup file and adopt it as the\n\t * destination. Gate on isOpenSupported(): unlike creating, this has no\n\t * download fallback. */\n\topenExisting: fileOpenExisting\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. `account()` names WHICH Google account holds them,\n * because a brand name is not an address. */\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\taccount: driveAccount,\n\tFILE_ID_KEY: DRIVE_FILE_ID_KEY\n};\n\nexport type { FileConnectOptions } from '../persistence/targets/file';\nexport type {\n\tDriveAuth,\n\tDriveOptions,\n\tDriveBackupInfo,\n\tDriveAccount\n} 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, datedName } from '../selfstore/targets/local';\n"]}
|
package/dist/backups.d.ts
CHANGED
|
@@ -1,182 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import { B as BackupsHost } from './manager-DZ1c_aSS.js';
|
|
2
|
+
export { a as BackupFileInfo, b as BackupOwner, c as BackupRow, d as BackupsErrorCode, e as BackupsKeys, f as BackupsManager, g as BackupsNaming, h as BackupsSnapshot, K as KnownBackups, i as createBackupsManager } from './manager-DZ1c_aSS.js';
|
|
3
|
+
import { D as DriveOptions } from './drive-CTYvGg_7.js';
|
|
4
|
+
import './cache-ilsK3Tki.js';
|
|
5
|
+
import './store-BiQ-BuVl.js';
|
|
4
6
|
import './sync.js';
|
|
7
|
+
import './machine-ALMkT3mk.js';
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
* the account already carries (a duplicate poisons find-by-name). */
|
|
31
|
-
create(fileName: string): Promise<{
|
|
32
|
-
fileId: string;
|
|
33
|
-
}>;
|
|
34
|
-
/** Delete a file for good. */
|
|
35
|
-
remove(fileId: string): Promise<void>;
|
|
36
|
-
/** Rename a file in place (metadata only: the id must not change). */
|
|
37
|
-
rename?(fileId: string, fileName: string): Promise<void>;
|
|
38
|
-
/** Find (or create) the PERSONAL file by its canonical name, ignoring any
|
|
39
|
-
* currently adopted id. Null when the user backs out of the session. */
|
|
40
|
-
findOrCreatePersonal(): Promise<{
|
|
41
|
-
fileId: string;
|
|
42
|
-
created: boolean;
|
|
43
|
-
} | null>;
|
|
44
|
-
/** Make sure a usable session exists before a remote call (re-consent when
|
|
45
|
-
* it lapsed). False = the user refused; the gesture aborts as 'cancelled'.
|
|
46
|
-
* Absent = sessions are the target's own business. */
|
|
47
|
-
ensureSession?(): Promise<boolean>;
|
|
48
|
-
/** Resolve the owner label of a file this account does not own, for the
|
|
49
|
-
* shared registry ("shared by X"). Best-effort. */
|
|
50
|
-
fileOwner?(fileId: string): Promise<{
|
|
51
|
-
email: string | null;
|
|
52
|
-
name: string | null;
|
|
53
|
-
} | null>;
|
|
54
|
-
/** File ids that must never enter the registry even though the store may
|
|
55
|
-
* attach them (e.g. a sharing engine's published copy file). */
|
|
56
|
-
excludedFileIds?(): Promise<(string | null | undefined)[]>;
|
|
57
|
-
}
|
|
58
|
-
/** How backup files are named on the destination. */
|
|
59
|
-
interface BackupsNaming {
|
|
60
|
-
/** The personal, unnamed file ("App.zip"). Its label reads as null. */
|
|
61
|
-
canonicalName: string;
|
|
62
|
-
/** label -> file name. Default: "Stem (label).ext" derived from
|
|
63
|
-
* canonicalName ("App.zip" + "family" -> "App (family).zip"). */
|
|
64
|
-
namedFileFor?(label: string): string;
|
|
65
|
-
/** file name -> parsed label; null = the personal file; undefined = not one
|
|
66
|
-
* of ours (dropped from listings). Default matches the default namedFileFor. */
|
|
67
|
-
parseLabel?(name: string): string | null | undefined;
|
|
68
|
-
}
|
|
69
|
-
/** The kv keys the manager persists under - override to keep a pre-existing
|
|
70
|
-
* install's records. */
|
|
71
|
-
interface BackupsKeys {
|
|
72
|
-
/** The known-backups registry. */
|
|
73
|
-
registry?: string;
|
|
74
|
-
/** fileId -> encrypted? map. */
|
|
75
|
-
encrypted?: string;
|
|
76
|
-
/** fileId -> shared? map. */
|
|
77
|
-
shared?: string;
|
|
78
|
-
/** Set while the ACTIVE file is not the personal one (another account's). */
|
|
79
|
-
joined?: string;
|
|
80
|
-
/** Cached owner label of that file. */
|
|
81
|
-
owner?: string;
|
|
82
|
-
}
|
|
83
|
-
/** Every backup this device has connected to: its own personal file and each
|
|
84
|
-
* OTHER account's file it was let into. Isolated snapshots, all of them. */
|
|
85
|
-
interface KnownBackups {
|
|
86
|
-
personalFileId: string | null;
|
|
87
|
-
shared: {
|
|
88
|
-
fileId: string;
|
|
89
|
-
ownerEmail: string | null;
|
|
90
|
-
ownerName: string | null;
|
|
91
|
-
}[];
|
|
92
|
-
}
|
|
93
|
-
/** One row of the "my backups" list: a file this account owns. */
|
|
94
|
-
interface BackupRow {
|
|
95
|
-
fileId: string;
|
|
96
|
-
name: string;
|
|
97
|
-
/** Parsed display label; null for the personal, unnamed file. */
|
|
98
|
-
label: string | null;
|
|
99
|
-
/** Last-write time, epoch ms (null when the destination did not say). */
|
|
100
|
-
modifiedAt: number | null;
|
|
101
|
-
/** true/false once known (opened, created or probed); null until then. */
|
|
102
|
-
encrypted: boolean | null;
|
|
103
|
-
/** true/false once learned (while this file was the active one); null
|
|
104
|
-
* until then. A share link existing is the shared state. */
|
|
105
|
-
shared: boolean | null;
|
|
106
|
-
}
|
|
107
|
-
/** The owner label of a joined (another account's) file. */
|
|
108
|
-
interface BackupOwner {
|
|
109
|
-
email: string | null;
|
|
110
|
-
name: string | null;
|
|
111
|
-
}
|
|
112
|
-
/** Stable failure codes; the host maps them to its own copy. */
|
|
113
|
-
type BackupsErrorCode = 'cancelled' | 'gone' | 'failed';
|
|
114
|
-
interface BackupsSnapshot {
|
|
115
|
-
registry: KnownBackups;
|
|
116
|
-
/** The file currently attached, when the store is on the managed kind. */
|
|
117
|
-
activeFileId: string | null;
|
|
118
|
-
/** The active file is not the personal one (someone else's). */
|
|
119
|
-
joined: boolean;
|
|
120
|
-
/** Who owns the joined file, when known. */
|
|
121
|
-
owner: BackupOwner | null;
|
|
122
|
-
/** The last gesture's failure, or null. Reset at each gesture start. */
|
|
123
|
-
lastError: BackupsErrorCode | null;
|
|
124
|
-
}
|
|
125
|
-
interface BackupsManager extends FlowStore<BackupsSnapshot> {
|
|
126
|
-
/** Boot: load registry + joined/owner from kv and stamp the active file.
|
|
127
|
-
* Kv-only, no destination call. */
|
|
128
|
-
hydrate(): Promise<void>;
|
|
129
|
-
/** Re-read the registry and restamp the active file. Kv-only, cheap. */
|
|
130
|
-
refresh(): Promise<void>;
|
|
131
|
-
/** After an attach the manager did not make (a connect widget, a join):
|
|
132
|
-
* record the now-active file in the registry and restamp joined/owner. */
|
|
133
|
-
markActive(fileId: string): Promise<void>;
|
|
134
|
-
/** Live list of this account's own files, per the naming rules, decorated
|
|
135
|
-
* with the learned memories. One destination listing call. */
|
|
136
|
-
list(): Promise<BackupRow[]>;
|
|
137
|
-
/** Learn a listed file's encrypted bit without opening it for real: one
|
|
138
|
-
* download + header read, remembered for good. Null when unreachable. */
|
|
139
|
-
probeEncryption(fileId: string): Promise<boolean | null>;
|
|
140
|
-
/** Record the ACTIVE file's live share state, keyed by file id, so its row
|
|
141
|
-
* stays truthful after a switch away. */
|
|
142
|
-
noteShared(fileId: string, shared: boolean): Promise<void>;
|
|
143
|
-
/** Open a known backup: an isolated snapshot replaces the local data.
|
|
144
|
-
* 'encrypted' = collect its passphrase and call again with it. A file the
|
|
145
|
-
* destination reports GONE is pruned from the registry (lastError 'gone'). */
|
|
146
|
-
openBackup(fileId: string, passphrase?: string | null): Promise<'ok' | 'encrypted' | 'failed'>;
|
|
147
|
-
/** Open (or create blank) the personal file. */
|
|
148
|
-
openPersonal(passphrase?: string | null): Promise<'ok' | 'encrypted' | 'failed'>;
|
|
149
|
-
/** Create a brand-new empty named backup and open it (starts blank - never
|
|
150
|
-
* seeded from the currently loaded file). */
|
|
151
|
-
createNamed(label: string): Promise<'ok' | 'failed'>;
|
|
152
|
-
/** Record a file in the SHARED registry under the sharer's label, without
|
|
153
|
-
* opening it. For a joined portfolio's dedicated wallet: the file may live
|
|
154
|
-
* on this very account, yet it presents as "shared by X", never as mine. */
|
|
155
|
-
registerShared(fileId: string, owner: BackupOwner): Promise<void>;
|
|
156
|
-
/** Create a joined portfolio's dedicated wallet: a file under the given
|
|
157
|
-
* name (outside the own-files naming on purpose), attached BLANK - never
|
|
158
|
-
* seeded from the previously loaded silo - and recorded in the shared
|
|
159
|
-
* registry under the sharer's label. The host stages the shared content
|
|
160
|
-
* afterwards (restore the projection, then save). */
|
|
161
|
-
createShared(fileName: string, owner: BackupOwner): Promise<'ok' | 'failed'>;
|
|
162
|
-
/** Rename a file in place (id unchanged, so renaming the ACTIVE file never
|
|
163
|
-
* detaches it). The host target refuses a name already carried. */
|
|
164
|
-
renameBackup(fileId: string, label: string): Promise<'ok' | 'failed'>;
|
|
165
|
-
/** Delete a file for good. Deleting the ACTIVE one detaches first (the app
|
|
166
|
-
* goes device-only, local data stays), so nothing writes mid-delete. */
|
|
167
|
-
deleteBackup(fileId: string): Promise<boolean>;
|
|
168
|
-
/** Drop a KNOWN shared (another account's) file from this device's
|
|
169
|
-
* registry. Forgetting only - the owner's file is never touched. */
|
|
170
|
-
forgetShared(fileId: string): Promise<void>;
|
|
171
|
-
/** The file name a label produces (the create form's preview line). */
|
|
172
|
-
fileNameFor(label: string): string;
|
|
173
|
-
}
|
|
174
|
-
declare function createBackupsManager(deps: {
|
|
175
|
-
store: LocalStore;
|
|
176
|
-
kv: KV;
|
|
177
|
-
host: BackupsHost;
|
|
178
|
-
naming: BackupsNaming;
|
|
179
|
-
keys?: BackupsKeys;
|
|
180
|
-
}): BackupsManager;
|
|
9
|
+
interface DriveBackupsHostOptions extends DriveOptions {
|
|
10
|
+
/** Narrow the listing server-side to names containing this fragment (the
|
|
11
|
+
* app's own stem, typically). The manager still applies its naming rules on
|
|
12
|
+
* what comes back, so this is a bandwidth hint and never a filter to rely
|
|
13
|
+
* on for correctness. Default: the whole visible listing. */
|
|
14
|
+
nameContains?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The Drive destination as a `BackupsHost`, ready for `createBackupsManager`
|
|
18
|
+
* (and therefore for `<selfstore-backups>`).
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* const manager = createBackupsManager({
|
|
22
|
+
* store: store.engine,
|
|
23
|
+
* kv: store.kv,
|
|
24
|
+
* host: driveBackupsHost({ auth, kv: store.kv, fileName: 'app.zip' }),
|
|
25
|
+
* naming: { canonicalName: 'app.zip' }
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* The `drive.file` scope already narrows what a listing can see to the files
|
|
30
|
+
* this app created or was handed, so nothing here can enumerate a user's Drive.
|
|
31
|
+
*/
|
|
32
|
+
declare function driveBackupsHost(opts: DriveBackupsHostOptions): BackupsHost;
|
|
181
33
|
|
|
182
|
-
export {
|
|
34
|
+
export { BackupsHost, type DriveBackupsHostOptions, driveBackupsHost };
|
package/dist/backups.js
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
|
-
import { makeMachine } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { makeMachine } from './chunk-W22V5CRM.js';
|
|
2
|
+
import { FILE_ID_KEY, findOrCreateOwnFile, renameBackup, deleteBackup, createBackup, preview, listBackups } from './chunk-J5MFXJU6.js';
|
|
3
|
+
import './chunk-MGDXR3RB.js';
|
|
4
|
+
import './chunk-O3Y6FORN.js';
|
|
5
|
+
import './chunk-3OBJOMQ2.js';
|
|
6
|
+
|
|
7
|
+
// src/backups/drive-host.ts
|
|
8
|
+
function driveBackupsHost(opts) {
|
|
9
|
+
return {
|
|
10
|
+
kind: "drive",
|
|
11
|
+
activeIdKey: FILE_ID_KEY,
|
|
12
|
+
async list() {
|
|
13
|
+
return listBackups({ auth: opts.auth, nameContains: opts.nameContains });
|
|
14
|
+
},
|
|
15
|
+
open(fileId) {
|
|
16
|
+
return preview(opts, fileId);
|
|
17
|
+
},
|
|
18
|
+
async create(fileName) {
|
|
19
|
+
return createBackup({ auth: opts.auth, fileName });
|
|
20
|
+
},
|
|
21
|
+
async remove(fileId) {
|
|
22
|
+
return deleteBackup({ auth: opts.auth, fileId });
|
|
23
|
+
},
|
|
24
|
+
async rename(fileId, fileName) {
|
|
25
|
+
return renameBackup({ auth: opts.auth, fileId, fileName });
|
|
26
|
+
},
|
|
27
|
+
async findOrCreatePersonal() {
|
|
28
|
+
return findOrCreateOwnFile(opts);
|
|
29
|
+
},
|
|
30
|
+
async ensureSession() {
|
|
31
|
+
try {
|
|
32
|
+
await opts.auth.token();
|
|
33
|
+
return true;
|
|
34
|
+
} catch {
|
|
35
|
+
return opts.auth.reconnect();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
3
40
|
|
|
4
41
|
// src/backups/manager.ts
|
|
5
42
|
var DEFAULT_KEYS = {
|
|
@@ -355,6 +392,6 @@ function createBackupsManager(deps) {
|
|
|
355
392
|
};
|
|
356
393
|
}
|
|
357
394
|
|
|
358
|
-
export { createBackupsManager };
|
|
395
|
+
export { createBackupsManager, driveBackupsHost };
|
|
359
396
|
//# sourceMappingURL=backups.js.map
|
|
360
397
|
//# sourceMappingURL=backups.js.map
|