selfstore 1.8.7 → 1.8.9
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 +7 -7
- package/dist/backups.d.ts +4 -4
- package/dist/{flows-vX9zy9bI.d.ts → connect-DaZFPJdt.d.ts} +4 -179
- package/dist/{drive-CTYvGg_7.d.ts → drive-B2fm71qD.d.ts} +2 -2
- package/dist/flows.d.ts +184 -5
- package/dist/households.d.ts +1 -1
- package/dist/index.d.ts +48 -8
- package/dist/index.js +53 -5
- package/dist/index.js.map +1 -1
- package/dist/{local-VLHtF3vT.d.ts → local-CldSa9EY.d.ts} +2 -2
- package/dist/{manager-DZ1c_aSS.d.ts → manager-BqzTVaep.d.ts} +1 -1
- package/dist/{s3-DvsnA-FK.d.ts → s3-DgyTwMRc.d.ts} +1 -1
- package/dist/{store-BiQ-BuVl.d.ts → store-CiLoRJmy.d.ts} +1 -1
- package/dist/widgets.d.ts +64 -6
- package/dist/widgets.js +138 -1
- package/dist/widgets.js.map +1 -1
- package/llms.txt +12 -1
- package/package.json +1 -1
package/dist/advanced.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { B as BackupTarget } from './store-
|
|
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,
|
|
1
|
+
import { B as BackupTarget } from './store-CiLoRJmy.js';
|
|
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, l as SelfstoreError, m as SelfstoreErrorCode, n as Severity, o as Snapshot, p as SnapshotFile, q as StatusAction, r as StatusDescriptor, s as StatusInput, t as StorageState, S 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-CiLoRJmy.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 { G as GisDriveAuthOptions, a as GisTokenPersistence, d as datedName, e as exportSnapshot, g as gisDriveAuth, i as importSnapshot, b as inspect, c as isEncrypted, p as pickFromDisk, s as saveToDisk } from './local-
|
|
6
|
-
import { c as connect$2, f as fromSession$2, a as connect$3, b as fromSession$3, p as peer } from './s3-
|
|
7
|
-
export { S as S3Config, d as S3ConnectOptions, W as WebdavConfig, e as WebdavConnectOptions, g as WebdavPeerOptions } from './s3-
|
|
8
|
-
import { c as connect$1, f as fromSession$1, p as preview,
|
|
9
|
-
export {
|
|
5
|
+
export { G as GisDriveAuthOptions, a as GisTokenPersistence, d as datedName, e as exportSnapshot, g as gisDriveAuth, i as importSnapshot, b as inspect, c as isEncrypted, p as pickFromDisk, s as saveToDisk } from './local-CldSa9EY.js';
|
|
6
|
+
import { c as connect$2, f as fromSession$2, a as connect$3, b as fromSession$3, p as peer } from './s3-DgyTwMRc.js';
|
|
7
|
+
export { S as S3Config, d as S3ConnectOptions, W as WebdavConfig, e as WebdavConnectOptions, g as WebdavPeerOptions } from './s3-DgyTwMRc.js';
|
|
8
|
+
import { c as connect$1, f as fromSession$1, p as preview, b as adopt, d as findOrCreateOwnFile, l as listBackups, e as createBackup, g as deleteBackup, r as renameBackup, h as account } from './drive-B2fm71qD.js';
|
|
9
|
+
export { i as DriveAccount, a as DriveAuth, j as DriveBackupInfo, D as DriveOptions } from './drive-B2fm71qD.js';
|
|
10
10
|
import './sync.js';
|
|
11
11
|
|
|
12
12
|
/**
|
package/dist/backups.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { B as BackupsHost } from './manager-
|
|
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-
|
|
3
|
-
import { D as DriveOptions } from './drive-
|
|
1
|
+
import { B as BackupsHost } from './manager-BqzTVaep.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-BqzTVaep.js';
|
|
3
|
+
import { D as DriveOptions } from './drive-B2fm71qD.js';
|
|
4
4
|
import './cache-ilsK3Tki.js';
|
|
5
|
-
import './store-
|
|
5
|
+
import './store-CiLoRJmy.js';
|
|
6
6
|
import './sync.js';
|
|
7
7
|
import './machine-ALMkT3mk.js';
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as StoreError, B as BackupTarget, L as LocalStore } from './store-CiLoRJmy.js';
|
|
2
2
|
import { K as KV } from './cache-ilsK3Tki.js';
|
|
3
|
-
import {
|
|
4
|
-
import { W as WebdavConfig, S as S3Config } from './s3-
|
|
3
|
+
import { a as DriveAuth } from './drive-B2fm71qD.js';
|
|
4
|
+
import { W as WebdavConfig, S as S3Config } from './s3-DgyTwMRc.js';
|
|
5
5
|
import { F as FlowStore } from './machine-ALMkT3mk.js';
|
|
6
6
|
|
|
7
7
|
type ConnectKind = 'drive' | 'file' | 'webdav' | 's3';
|
|
@@ -189,179 +189,4 @@ interface ConnectFlow extends FlowStore<ConnectSnapshot> {
|
|
|
189
189
|
}
|
|
190
190
|
declare function connectFlow(store: StoreLike, targets: ConnectTargets, options?: ConnectFlowOptions): ConnectFlow;
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
declare const REPLICA_ID = "replica";
|
|
194
|
-
type ReplicaStep = 'idle' | 'choose' | 'form-webdav' | 'form-s3';
|
|
195
|
-
interface ReplicaSnapshot {
|
|
196
|
-
step: ReplicaStep;
|
|
197
|
-
/** The kinds the host offers, in ConnectTargets order. */
|
|
198
|
-
kinds: ConnectKind[];
|
|
199
|
-
busy: boolean;
|
|
200
|
-
error: StoreError | null;
|
|
201
|
-
/** The live engine entry (label, lastPublishAt, lastError), null when none. */
|
|
202
|
-
replica: ReplicaState | null;
|
|
203
|
-
}
|
|
204
|
-
interface ReplicaFlowOptions {
|
|
205
|
-
/** File name of the copy on its destination. Default: the primary backup
|
|
206
|
-
* name with `.replica` before the extension ("App.zip" -> "App.replica.zip"),
|
|
207
|
-
* which a same-account Drive never confuses with the primary file and the
|
|
208
|
-
* backups panel never lists as a backup of its own. */
|
|
209
|
-
fileName?: string;
|
|
210
|
-
/** Rebuild the target of a custom Connector kind on restore() (built-in
|
|
211
|
-
* kinds rebuild by themselves). Without it, custom kinds are not restored. */
|
|
212
|
-
restoreTarget?: (kind: ConnectKind) => Promise<BackupTarget | null>;
|
|
213
|
-
}
|
|
214
|
-
interface ReplicaFlow extends FlowStore<ReplicaSnapshot> {
|
|
215
|
-
/** Show the destination choice (from the user's gesture). */
|
|
216
|
-
open(): void;
|
|
217
|
-
/** Back to idle; never an error. */
|
|
218
|
-
cancel(): void;
|
|
219
|
-
/** Run a destination (inside the user's click - pickers and consent popups
|
|
220
|
-
* open from it). `webdav: true` / `s3: true` route to their form step. */
|
|
221
|
-
pick(kind: ConnectKind): void;
|
|
222
|
-
/** 'form-webdav' step: submit the server config. */
|
|
223
|
-
submitWebdav(config: WebdavConfig): void;
|
|
224
|
-
/** 'form-s3' step: submit the bucket config. */
|
|
225
|
-
submitS3(config: S3Config): void;
|
|
226
|
-
/** Detach the copy and forget its session. Never deletes remote data. */
|
|
227
|
-
remove(): Promise<void>;
|
|
228
|
-
/** Silent reboot: re-attach the copy recorded by a past session, if any.
|
|
229
|
-
* Never throws - an unreachable destination retries at the next boot. */
|
|
230
|
-
restore(): Promise<void>;
|
|
231
|
-
/** Detach from the engine (the replica itself stays attached). */
|
|
232
|
-
dispose(): void;
|
|
233
|
-
}
|
|
234
|
-
declare function replicaFlow(store: StoreLike, targets: ConnectTargets, options?: ReplicaFlowOptions): ReplicaFlow;
|
|
235
|
-
|
|
236
|
-
type ShareLevel = 'read' | 'write';
|
|
237
|
-
interface ShareLinkInfo {
|
|
238
|
-
/** Engine-scoped stable id (revoke keys on it). */
|
|
239
|
-
id: string;
|
|
240
|
-
/** The invitation URL to hand out. */
|
|
241
|
-
url: string;
|
|
242
|
-
level: ShareLevel;
|
|
243
|
-
}
|
|
244
|
-
interface ShareMemberInfo {
|
|
245
|
-
/** Engine-scoped stable id (removeMember keys on it). */
|
|
246
|
-
id: string;
|
|
247
|
-
label?: string;
|
|
248
|
-
/** This row is the local user. */
|
|
249
|
-
self?: boolean;
|
|
250
|
-
/** This row owns the share (the app may render a badge, the flow does not care). */
|
|
251
|
-
owner?: boolean;
|
|
252
|
-
}
|
|
253
|
-
/** The app-side port the flow drives. Implementations wrap whatever transport
|
|
254
|
-
* the app shares through; every method may throw (SelfstoreError preferred,
|
|
255
|
-
* anything is normalized). */
|
|
256
|
-
interface ShareEngine {
|
|
257
|
-
/** The current truth: active links and members. */
|
|
258
|
-
list(): Promise<{
|
|
259
|
-
links: ShareLinkInfo[];
|
|
260
|
-
members: ShareMemberInfo[];
|
|
261
|
-
}>;
|
|
262
|
-
createLink(opts: {
|
|
263
|
-
level: ShareLevel;
|
|
264
|
-
}): Promise<ShareLinkInfo>;
|
|
265
|
-
revokeLink(id: string): Promise<void>;
|
|
266
|
-
/** Optional: engines without member management simply omit it. */
|
|
267
|
-
removeMember?(id: string): Promise<void>;
|
|
268
|
-
/** Optional: END the whole share in one gesture - every link dead, every
|
|
269
|
-
* member out. Engines whose transport has such a move (an invitation to
|
|
270
|
-
* kill, a file to re-privatize) expose it; the widget renders the action
|
|
271
|
-
* only then. */
|
|
272
|
-
revokeAll?(): Promise<void>;
|
|
273
|
-
}
|
|
274
|
-
type ShareBusy = 'refresh' | 'create' | 'revoke' | 'remove' | 'revoke-all' | null;
|
|
275
|
-
interface ShareSnapshot {
|
|
276
|
-
links: readonly ShareLinkInfo[];
|
|
277
|
-
members: readonly ShareMemberInfo[];
|
|
278
|
-
/** The operation in flight, or null. */
|
|
279
|
-
busy: ShareBusy;
|
|
280
|
-
/** The last refresh failed: the lists shown are the last-known good ones. */
|
|
281
|
-
stale: boolean;
|
|
282
|
-
/** The last operation's problem (the lists are never cleared by an error). */
|
|
283
|
-
error: StoreError | null;
|
|
284
|
-
/** True once the engine offers removeMember (render the row action at all). */
|
|
285
|
-
canRemoveMembers: boolean;
|
|
286
|
-
/** True once the engine offers revokeAll (render the end-the-share action). */
|
|
287
|
-
canRevokeAll: boolean;
|
|
288
|
-
}
|
|
289
|
-
interface ShareFlow extends FlowStore<ShareSnapshot> {
|
|
290
|
-
/** Re-list from the engine. Failure keeps the last-known lists (stale). */
|
|
291
|
-
refresh(): Promise<void>;
|
|
292
|
-
/** Create an invitation link. Resolves to it, or null when refused (an
|
|
293
|
-
* operation was already in flight). */
|
|
294
|
-
createLink(opts: {
|
|
295
|
-
level: ShareLevel;
|
|
296
|
-
}): Promise<ShareLinkInfo | null>;
|
|
297
|
-
/** Revoke a link. The link leaves the snapshot only once the engine
|
|
298
|
-
* confirmed. Resolves to whether it did. */
|
|
299
|
-
revokeLink(id: string): Promise<boolean>;
|
|
300
|
-
/** Remove a member (never yourself - refused up front). Resolves to whether
|
|
301
|
-
* the engine confirmed. */
|
|
302
|
-
removeMember(id: string): Promise<boolean>;
|
|
303
|
-
/** End the whole share: every link and member leaves the snapshot only
|
|
304
|
-
* once the engine confirmed. Resolves to whether it did. */
|
|
305
|
-
revokeAll(): Promise<boolean>;
|
|
306
|
-
}
|
|
307
|
-
declare function shareFlow(engine: ShareEngine, options?: {
|
|
308
|
-
deadlineMs?: number;
|
|
309
|
-
}): ShareFlow;
|
|
310
|
-
|
|
311
|
-
/** What the user is about to join - enough to render an honest question. */
|
|
312
|
-
interface JoinPreview {
|
|
313
|
-
/** The share's display name, when the link carries one. */
|
|
314
|
-
label?: string;
|
|
315
|
-
/** Who shared it (a name, an email - whatever the engine knows). */
|
|
316
|
-
from?: string;
|
|
317
|
-
level?: ShareLevel;
|
|
318
|
-
}
|
|
319
|
-
/** How joining ended, other than plain failure:
|
|
320
|
-
* 'joined' - this device now follows the share.
|
|
321
|
-
* 'mismatch' - this device already follows a DIFFERENT share: joining a
|
|
322
|
-
* second one is refused (leave the first, or use another
|
|
323
|
-
* device/profile).
|
|
324
|
-
* 'no-invite' - the invitation is spent, expired, or aimed at another
|
|
325
|
-
* account (switching accounts may be the fix). */
|
|
326
|
-
type JoinOutcome = 'joined' | 'mismatch' | 'no-invite';
|
|
327
|
-
/** The app-side port: how a link is read and honoured on this transport. */
|
|
328
|
-
interface JoinEngine {
|
|
329
|
-
/** Read-only look at the invitation. Must change NOTHING. */
|
|
330
|
-
preview(link: string): Promise<JoinPreview>;
|
|
331
|
-
/** Consume the invitation and wire the share. Resolve null when the user
|
|
332
|
-
* backed out of a popup the engine had to open (an account chooser, a
|
|
333
|
-
* consent screen): the flow returns to 'ready' silently - backing out of
|
|
334
|
-
* a human gesture is not an error, here as everywhere in these flows. */
|
|
335
|
-
join(link: string): Promise<JoinOutcome | null>;
|
|
336
|
-
/** Optional: re-run the account chooser (the invite may belong to another
|
|
337
|
-
* account). The flow re-previews after it. */
|
|
338
|
-
switchAccount?(): Promise<void>;
|
|
339
|
-
}
|
|
340
|
-
type JoinStep = 'previewing' | 'ready' | 'joining' | 'joined' | 'mismatch' | 'no-invite' | 'error';
|
|
341
|
-
interface JoinSnapshot {
|
|
342
|
-
/** The invitation this flow was opened with - held here so the UI can
|
|
343
|
-
* always find it again. */
|
|
344
|
-
link: string;
|
|
345
|
-
step: JoinStep;
|
|
346
|
-
/** Set once previewed (kept through errors, so retry re-renders context). */
|
|
347
|
-
preview: JoinPreview | null;
|
|
348
|
-
/** The engine offers an account switch. */
|
|
349
|
-
canSwitchAccount: boolean;
|
|
350
|
-
busy: boolean;
|
|
351
|
-
/** Set when step === 'error': show `labelKey`, log `message`. */
|
|
352
|
-
error: StoreError | null;
|
|
353
|
-
}
|
|
354
|
-
interface JoinFlow extends FlowStore<JoinSnapshot> {
|
|
355
|
-
/** Say yes: consume the invitation. Only from 'ready'. */
|
|
356
|
-
accept(): void;
|
|
357
|
-
/** Re-run the account chooser, then preview again under the new account.
|
|
358
|
-
* Available from 'ready', 'no-invite' and 'error' when the engine offers it. */
|
|
359
|
-
switchAccount(): void;
|
|
360
|
-
/** From 'error': preview again and resume the journey. */
|
|
361
|
-
retry(): void;
|
|
362
|
-
}
|
|
363
|
-
declare function joinFlow(link: string, engine: JoinEngine, options?: {
|
|
364
|
-
deadlineMs?: number;
|
|
365
|
-
}): JoinFlow;
|
|
366
|
-
|
|
367
|
-
export { joinFlow as A, replicaFlow as B, type ConnectTargets as C, shareFlow as D, type FlowHost as F, type JoinEngine as J, type ReplicaFlow as R, type StoreLike as S, type ConnectFlowOptions as a, type ConnectKind as b, type ConnectFlow as c, type ShareEngine as d, type ShareLevel as e, type ShareFlow as f, type JoinFlow as g, type ConnectFlowOutcome as h, type ConnectResolution as i, type ConnectSnapshot as j, type ConnectStep as k, type Connector as l, type JoinOutcome as m, type JoinPreview as n, type JoinSnapshot as o, type JoinStep as p, REPLICA_ID as q, type ReplicaFlowOptions as r, type ReplicaSnapshot as s, type ReplicaStep as t, type ResumeOffer as u, type ShareBusy as v, type ShareLinkInfo as w, type ShareMemberInfo as x, type ShareSnapshot as y, connectFlow as z };
|
|
192
|
+
export { type ConnectTargets as C, type FlowHost as F, type ResumeOffer as R, type StoreLike as S, type ConnectFlowOptions as a, type ConnectKind as b, type ConnectFlow as c, type ConnectFlowOutcome as d, type ConnectResolution as e, type ConnectSnapshot as f, type ConnectStep as g, type Connector as h, connectFlow as i };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as BackupTarget } from './store-
|
|
1
|
+
import { B as BackupTarget } from './store-CiLoRJmy.js';
|
|
2
2
|
import { K as KV } from './cache-ilsK3Tki.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -137,4 +137,4 @@ declare function renameBackup(opts: {
|
|
|
137
137
|
fileName: string;
|
|
138
138
|
}): Promise<void>;
|
|
139
139
|
|
|
140
|
-
export { type DriveOptions as D,
|
|
140
|
+
export { type DriveOptions as D, type DriveAuth as a, adopt as b, connect as c, findOrCreateOwnFile as d, createBackup as e, fromSession as f, deleteBackup as g, account as h, type DriveAccount as i, type DriveBackupInfo as j, listBackups as l, preview as p, renameBackup as r };
|
package/dist/flows.d.ts
CHANGED
|
@@ -1,7 +1,186 @@
|
|
|
1
|
-
|
|
2
|
-
export { F as
|
|
3
|
-
import './store-
|
|
1
|
+
import { b as ConnectKind, S as StoreLike, C as ConnectTargets } from './connect-DaZFPJdt.js';
|
|
2
|
+
export { c as ConnectFlow, a as ConnectFlowOptions, d as ConnectFlowOutcome, e as ConnectResolution, f as ConnectSnapshot, g as ConnectStep, h as Connector, F as FlowHost, R as ResumeOffer, i as connectFlow } from './connect-DaZFPJdt.js';
|
|
3
|
+
import { S as StoreError, k as ReplicaState, B as BackupTarget } from './store-CiLoRJmy.js';
|
|
4
|
+
import { F as FlowStore } from './machine-ALMkT3mk.js';
|
|
5
|
+
export { w as withDeadline } from './machine-ALMkT3mk.js';
|
|
6
|
+
import { W as WebdavConfig, S as S3Config } from './s3-DgyTwMRc.js';
|
|
4
7
|
import './cache-ilsK3Tki.js';
|
|
8
|
+
import './drive-B2fm71qD.js';
|
|
5
9
|
import './sync.js';
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
|
|
11
|
+
/** The one replica this flow manages, as its id on the engine. */
|
|
12
|
+
declare const REPLICA_ID = "replica";
|
|
13
|
+
type ReplicaStep = 'idle' | 'choose' | 'form-webdav' | 'form-s3';
|
|
14
|
+
interface ReplicaSnapshot {
|
|
15
|
+
step: ReplicaStep;
|
|
16
|
+
/** The kinds the host offers, in ConnectTargets order. */
|
|
17
|
+
kinds: ConnectKind[];
|
|
18
|
+
busy: boolean;
|
|
19
|
+
error: StoreError | null;
|
|
20
|
+
/** The live engine entry (label, lastPublishAt, lastError), null when none. */
|
|
21
|
+
replica: ReplicaState | null;
|
|
22
|
+
}
|
|
23
|
+
interface ReplicaFlowOptions {
|
|
24
|
+
/** File name of the copy on its destination. Default: the primary backup
|
|
25
|
+
* name with `.replica` before the extension ("App.zip" -> "App.replica.zip"),
|
|
26
|
+
* which a same-account Drive never confuses with the primary file and the
|
|
27
|
+
* backups panel never lists as a backup of its own. */
|
|
28
|
+
fileName?: string;
|
|
29
|
+
/** Rebuild the target of a custom Connector kind on restore() (built-in
|
|
30
|
+
* kinds rebuild by themselves). Without it, custom kinds are not restored. */
|
|
31
|
+
restoreTarget?: (kind: ConnectKind) => Promise<BackupTarget | null>;
|
|
32
|
+
}
|
|
33
|
+
interface ReplicaFlow extends FlowStore<ReplicaSnapshot> {
|
|
34
|
+
/** Show the destination choice (from the user's gesture). */
|
|
35
|
+
open(): void;
|
|
36
|
+
/** Back to idle; never an error. */
|
|
37
|
+
cancel(): void;
|
|
38
|
+
/** Run a destination (inside the user's click - pickers and consent popups
|
|
39
|
+
* open from it). `webdav: true` / `s3: true` route to their form step. */
|
|
40
|
+
pick(kind: ConnectKind): void;
|
|
41
|
+
/** 'form-webdav' step: submit the server config. */
|
|
42
|
+
submitWebdav(config: WebdavConfig): void;
|
|
43
|
+
/** 'form-s3' step: submit the bucket config. */
|
|
44
|
+
submitS3(config: S3Config): void;
|
|
45
|
+
/** Detach the copy and forget its session. Never deletes remote data. */
|
|
46
|
+
remove(): Promise<void>;
|
|
47
|
+
/** Silent reboot: re-attach the copy recorded by a past session, if any.
|
|
48
|
+
* Never throws - an unreachable destination retries at the next boot. */
|
|
49
|
+
restore(): Promise<void>;
|
|
50
|
+
/** Detach from the engine (the replica itself stays attached). */
|
|
51
|
+
dispose(): void;
|
|
52
|
+
}
|
|
53
|
+
declare function replicaFlow(store: StoreLike, targets: ConnectTargets, options?: ReplicaFlowOptions): ReplicaFlow;
|
|
54
|
+
|
|
55
|
+
type ShareLevel = 'read' | 'write';
|
|
56
|
+
interface ShareLinkInfo {
|
|
57
|
+
/** Engine-scoped stable id (revoke keys on it). */
|
|
58
|
+
id: string;
|
|
59
|
+
/** The invitation URL to hand out. */
|
|
60
|
+
url: string;
|
|
61
|
+
level: ShareLevel;
|
|
62
|
+
}
|
|
63
|
+
interface ShareMemberInfo {
|
|
64
|
+
/** Engine-scoped stable id (removeMember keys on it). */
|
|
65
|
+
id: string;
|
|
66
|
+
label?: string;
|
|
67
|
+
/** This row is the local user. */
|
|
68
|
+
self?: boolean;
|
|
69
|
+
/** This row owns the share (the app may render a badge, the flow does not care). */
|
|
70
|
+
owner?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/** The app-side port the flow drives. Implementations wrap whatever transport
|
|
73
|
+
* the app shares through; every method may throw (SelfstoreError preferred,
|
|
74
|
+
* anything is normalized). */
|
|
75
|
+
interface ShareEngine {
|
|
76
|
+
/** The current truth: active links and members. */
|
|
77
|
+
list(): Promise<{
|
|
78
|
+
links: ShareLinkInfo[];
|
|
79
|
+
members: ShareMemberInfo[];
|
|
80
|
+
}>;
|
|
81
|
+
createLink(opts: {
|
|
82
|
+
level: ShareLevel;
|
|
83
|
+
}): Promise<ShareLinkInfo>;
|
|
84
|
+
revokeLink(id: string): Promise<void>;
|
|
85
|
+
/** Optional: engines without member management simply omit it. */
|
|
86
|
+
removeMember?(id: string): Promise<void>;
|
|
87
|
+
/** Optional: END the whole share in one gesture - every link dead, every
|
|
88
|
+
* member out. Engines whose transport has such a move (an invitation to
|
|
89
|
+
* kill, a file to re-privatize) expose it; the widget renders the action
|
|
90
|
+
* only then. */
|
|
91
|
+
revokeAll?(): Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
type ShareBusy = 'refresh' | 'create' | 'revoke' | 'remove' | 'revoke-all' | null;
|
|
94
|
+
interface ShareSnapshot {
|
|
95
|
+
links: readonly ShareLinkInfo[];
|
|
96
|
+
members: readonly ShareMemberInfo[];
|
|
97
|
+
/** The operation in flight, or null. */
|
|
98
|
+
busy: ShareBusy;
|
|
99
|
+
/** The last refresh failed: the lists shown are the last-known good ones. */
|
|
100
|
+
stale: boolean;
|
|
101
|
+
/** The last operation's problem (the lists are never cleared by an error). */
|
|
102
|
+
error: StoreError | null;
|
|
103
|
+
/** True once the engine offers removeMember (render the row action at all). */
|
|
104
|
+
canRemoveMembers: boolean;
|
|
105
|
+
/** True once the engine offers revokeAll (render the end-the-share action). */
|
|
106
|
+
canRevokeAll: boolean;
|
|
107
|
+
}
|
|
108
|
+
interface ShareFlow extends FlowStore<ShareSnapshot> {
|
|
109
|
+
/** Re-list from the engine. Failure keeps the last-known lists (stale). */
|
|
110
|
+
refresh(): Promise<void>;
|
|
111
|
+
/** Create an invitation link. Resolves to it, or null when refused (an
|
|
112
|
+
* operation was already in flight). */
|
|
113
|
+
createLink(opts: {
|
|
114
|
+
level: ShareLevel;
|
|
115
|
+
}): Promise<ShareLinkInfo | null>;
|
|
116
|
+
/** Revoke a link. The link leaves the snapshot only once the engine
|
|
117
|
+
* confirmed. Resolves to whether it did. */
|
|
118
|
+
revokeLink(id: string): Promise<boolean>;
|
|
119
|
+
/** Remove a member (never yourself - refused up front). Resolves to whether
|
|
120
|
+
* the engine confirmed. */
|
|
121
|
+
removeMember(id: string): Promise<boolean>;
|
|
122
|
+
/** End the whole share: every link and member leaves the snapshot only
|
|
123
|
+
* once the engine confirmed. Resolves to whether it did. */
|
|
124
|
+
revokeAll(): Promise<boolean>;
|
|
125
|
+
}
|
|
126
|
+
declare function shareFlow(engine: ShareEngine, options?: {
|
|
127
|
+
deadlineMs?: number;
|
|
128
|
+
}): ShareFlow;
|
|
129
|
+
|
|
130
|
+
/** What the user is about to join - enough to render an honest question. */
|
|
131
|
+
interface JoinPreview {
|
|
132
|
+
/** The share's display name, when the link carries one. */
|
|
133
|
+
label?: string;
|
|
134
|
+
/** Who shared it (a name, an email - whatever the engine knows). */
|
|
135
|
+
from?: string;
|
|
136
|
+
level?: ShareLevel;
|
|
137
|
+
}
|
|
138
|
+
/** How joining ended, other than plain failure:
|
|
139
|
+
* 'joined' - this device now follows the share.
|
|
140
|
+
* 'mismatch' - this device already follows a DIFFERENT share: joining a
|
|
141
|
+
* second one is refused (leave the first, or use another
|
|
142
|
+
* device/profile).
|
|
143
|
+
* 'no-invite' - the invitation is spent, expired, or aimed at another
|
|
144
|
+
* account (switching accounts may be the fix). */
|
|
145
|
+
type JoinOutcome = 'joined' | 'mismatch' | 'no-invite';
|
|
146
|
+
/** The app-side port: how a link is read and honoured on this transport. */
|
|
147
|
+
interface JoinEngine {
|
|
148
|
+
/** Read-only look at the invitation. Must change NOTHING. */
|
|
149
|
+
preview(link: string): Promise<JoinPreview>;
|
|
150
|
+
/** Consume the invitation and wire the share. Resolve null when the user
|
|
151
|
+
* backed out of a popup the engine had to open (an account chooser, a
|
|
152
|
+
* consent screen): the flow returns to 'ready' silently - backing out of
|
|
153
|
+
* a human gesture is not an error, here as everywhere in these flows. */
|
|
154
|
+
join(link: string): Promise<JoinOutcome | null>;
|
|
155
|
+
/** Optional: re-run the account chooser (the invite may belong to another
|
|
156
|
+
* account). The flow re-previews after it. */
|
|
157
|
+
switchAccount?(): Promise<void>;
|
|
158
|
+
}
|
|
159
|
+
type JoinStep = 'previewing' | 'ready' | 'joining' | 'joined' | 'mismatch' | 'no-invite' | 'error';
|
|
160
|
+
interface JoinSnapshot {
|
|
161
|
+
/** The invitation this flow was opened with - held here so the UI can
|
|
162
|
+
* always find it again. */
|
|
163
|
+
link: string;
|
|
164
|
+
step: JoinStep;
|
|
165
|
+
/** Set once previewed (kept through errors, so retry re-renders context). */
|
|
166
|
+
preview: JoinPreview | null;
|
|
167
|
+
/** The engine offers an account switch. */
|
|
168
|
+
canSwitchAccount: boolean;
|
|
169
|
+
busy: boolean;
|
|
170
|
+
/** Set when step === 'error': show `labelKey`, log `message`. */
|
|
171
|
+
error: StoreError | null;
|
|
172
|
+
}
|
|
173
|
+
interface JoinFlow extends FlowStore<JoinSnapshot> {
|
|
174
|
+
/** Say yes: consume the invitation. Only from 'ready'. */
|
|
175
|
+
accept(): void;
|
|
176
|
+
/** Re-run the account chooser, then preview again under the new account.
|
|
177
|
+
* Available from 'ready', 'no-invite' and 'error' when the engine offers it. */
|
|
178
|
+
switchAccount(): void;
|
|
179
|
+
/** From 'error': preview again and resume the journey. */
|
|
180
|
+
retry(): void;
|
|
181
|
+
}
|
|
182
|
+
declare function joinFlow(link: string, engine: JoinEngine, options?: {
|
|
183
|
+
deadlineMs?: number;
|
|
184
|
+
}): JoinFlow;
|
|
185
|
+
|
|
186
|
+
export { ConnectKind, ConnectTargets, FlowStore, type JoinEngine, type JoinFlow, type JoinOutcome, type JoinPreview, type JoinSnapshot, type JoinStep, REPLICA_ID, type ReplicaFlow, type ReplicaFlowOptions, type ReplicaSnapshot, type ReplicaStep, type ShareBusy, type ShareEngine, type ShareFlow, type ShareLevel, type ShareLinkInfo, type ShareMemberInfo, type ShareSnapshot, joinFlow, replicaFlow, shareFlow };
|
package/dist/households.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { d as Mode, e as PasswordCheck, g as PasswordRequirement,
|
|
1
|
+
import { o as Snapshot, E as EncodeOptions, H as Header, f as PasswordPolicy, B as BackupTarget, r as StatusDescriptor, S as StoreError, c as LocalStoreState, L as LocalStore } from './store-CiLoRJmy.js';
|
|
2
|
+
export { d as Mode, e as PasswordCheck, g as PasswordRequirement, l as SelfstoreError, m as SelfstoreErrorCode, n as Severity, p as SnapshotFile, q as StatusAction, t as StorageState, T as TargetKind, x as checkPasswordPolicy, C as errorLabelKey, G as isSelfstoreError } from './store-CiLoRJmy.js';
|
|
3
3
|
import { L as LocalCache, K as KV } from './cache-ilsK3Tki.js';
|
|
4
4
|
import { SyncConfig } from './sync.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
5
|
+
import { R as ResumeOffer, C as ConnectTargets } from './connect-DaZFPJdt.js';
|
|
6
|
+
import { a as DriveAuth } from './drive-B2fm71qD.js';
|
|
7
|
+
import { W as WebdavConfig, S as S3Config } from './s3-DgyTwMRc.js';
|
|
8
|
+
export { f as changePassword, g as gisDriveAuth, p as pickFromDisk, s as saveToDisk } from './local-CldSa9EY.js';
|
|
9
|
+
import './machine-ALMkT3mk.js';
|
|
8
10
|
|
|
9
11
|
declare const BACKUP_EXTENSION = ".zip";
|
|
10
12
|
declare const BACKUP_MIME = "application/zip";
|
|
@@ -112,9 +114,25 @@ interface SimpleOptions {
|
|
|
112
114
|
/** Per-collection merge tuning (id field mapping, strategies). The default -
|
|
113
115
|
* records keyed by `id`, later edit wins, deletes propagate - fits most apps. */
|
|
114
116
|
sync?: SyncConfig;
|
|
115
|
-
/**
|
|
116
|
-
*
|
|
117
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Google Drive, when this app uses it. Two shapes for two situations:
|
|
119
|
+
*
|
|
120
|
+
* `{ clientId }` is the whole wiring - the library builds the browser
|
|
121
|
+
* connection, keeps ONE session for the app (several would mean several
|
|
122
|
+
* consent screens), reuses its token across a reload, remembers which
|
|
123
|
+
* account holds the backup and hands that back to Google so the chooser
|
|
124
|
+
* stops appearing. Nothing else to write.
|
|
125
|
+
*
|
|
126
|
+
* A `DriveAuth` instead, for an app that gets its tokens elsewhere - a
|
|
127
|
+
* server broker holding a refresh token, a native shell.
|
|
128
|
+
*
|
|
129
|
+
* Either way, providing it here is also what lets a connected Drive backup
|
|
130
|
+
* restore itself on the next start.
|
|
131
|
+
*/
|
|
132
|
+
drive?: DriveAuth | {
|
|
133
|
+
clientId: string;
|
|
134
|
+
scope?: string;
|
|
135
|
+
};
|
|
118
136
|
/** Where the working copy lives (default: IndexedDB named after the app;
|
|
119
137
|
* in-memory when IndexedDB does not exist, e.g. tests or SSR). */
|
|
120
138
|
cache?: LocalCache;
|
|
@@ -236,6 +254,28 @@ interface SimpleStore<S extends Record<string, SimpleRecord> = Record<string, Si
|
|
|
236
254
|
kv: KV;
|
|
237
255
|
backupName: string;
|
|
238
256
|
};
|
|
257
|
+
/** Who holds the destination, when it is known - the Google address behind a
|
|
258
|
+
* Drive backup. Learned on connect and remembered across sessions, so a
|
|
259
|
+
* surface can NAME the destination ("Google Drive" is not an address) and a
|
|
260
|
+
* re-grant can skip the account chooser. Null for a file, or before a first
|
|
261
|
+
* connect. Reading it costs nothing: no call goes out. */
|
|
262
|
+
readonly account: string | null;
|
|
263
|
+
/** The destination this device already used, ready to hand to a connect flow
|
|
264
|
+
* as `options.resume` - so a returning visitor is offered "reopen my backup"
|
|
265
|
+
* ahead of the plain destinations, instead of re-deriving a decision the
|
|
266
|
+
* library already has on file. Null when there is nothing to resume. */
|
|
267
|
+
resumeOffer(): ResumeOffer | null;
|
|
268
|
+
/**
|
|
269
|
+
* The destinations this store can offer, ready for a connect flow or widget:
|
|
270
|
+
* Drive first when the app configured it, a file always.
|
|
271
|
+
*
|
|
272
|
+
* Consumers were assembling this by hand from the very session the store
|
|
273
|
+
* built - and the order and the "no client id means no Drive card" rule were
|
|
274
|
+
* rediscovered each time. An app wanting a different offer (a WebDAV server,
|
|
275
|
+
* its own target) still writes its own object; this is the default, not a
|
|
276
|
+
* ceiling.
|
|
277
|
+
*/
|
|
278
|
+
destinations(): ConnectTargets;
|
|
239
279
|
}
|
|
240
280
|
/**
|
|
241
281
|
* Open (or create) the app's local store. Awaits the initial load, so the
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { indexedDbCache, memoryCache, isLockableCache, createLocalStore } from './chunk-TXAMWBG5.js';
|
|
1
|
+
import { indexedDbCache, memoryCache, gisDriveAuth, isLockableCache, createLocalStore } from './chunk-TXAMWBG5.js';
|
|
2
2
|
export { gisDriveAuth } from './chunk-TXAMWBG5.js';
|
|
3
3
|
import './chunk-SKWHKM25.js';
|
|
4
4
|
import { saveToDisk } from './chunk-DCEXWSM6.js';
|
|
5
5
|
export { pickFromDisk, saveToDisk } from './chunk-DCEXWSM6.js';
|
|
6
6
|
import { fromSession as fromSession$1, fromSession2, isSupported, connect3, connect2, connect } from './chunk-TKWU52LK.js';
|
|
7
7
|
export { hasDesktopFiles, useDesktopFiles } from './chunk-TKWU52LK.js';
|
|
8
|
-
import { fromSession, connect as connect$1 } from './chunk-J5MFXJU6.js';
|
|
8
|
+
import { fromSession, connect as connect$1, account } from './chunk-J5MFXJU6.js';
|
|
9
9
|
import { restore } from './chunk-MGDXR3RB.js';
|
|
10
10
|
export { BACKUP_EXTENSION, BACKUP_MIME, backup, changePassword, checkPasswordPolicy, restore } from './chunk-MGDXR3RB.js';
|
|
11
11
|
import './chunk-QBCU7OOP.js';
|
|
@@ -32,6 +32,28 @@ function requireStringId(record, field, collection) {
|
|
|
32
32
|
function hasIndexedDb() {
|
|
33
33
|
return typeof indexedDB !== "undefined";
|
|
34
34
|
}
|
|
35
|
+
function isDriveAuth(v) {
|
|
36
|
+
return !!v && typeof v.token === "function";
|
|
37
|
+
}
|
|
38
|
+
var driveAccountKey = (app) => `selfstore.drive.account.${app}`;
|
|
39
|
+
function localStore(job) {
|
|
40
|
+
try {
|
|
41
|
+
const store = globalThis.localStorage;
|
|
42
|
+
return store ? job(store) : void 0;
|
|
43
|
+
} catch {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function rememberedDriveAccount(app) {
|
|
48
|
+
return localStore((s) => s.getItem(driveAccountKey(app))) ?? void 0;
|
|
49
|
+
}
|
|
50
|
+
async function learnDriveAccount(app, auth) {
|
|
51
|
+
try {
|
|
52
|
+
const who = await account({ auth });
|
|
53
|
+
if (who.email) localStore((s) => s.setItem(driveAccountKey(app), who.email));
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
35
57
|
async function selfstore(app, options = {}) {
|
|
36
58
|
if (typeof app !== "string" || app.length === 0) {
|
|
37
59
|
throw new TypeError('selfstore: pass your app name, e.g. selfstore("my-app").');
|
|
@@ -42,7 +64,12 @@ async function selfstore(app, options = {}) {
|
|
|
42
64
|
const emitData = () => dataSubs.forEach((fn) => fn());
|
|
43
65
|
const cache = options.cache ?? (hasIndexedDb() ? indexedDbCache(app, options.cacheLock ? { lock: true } : void 0) : memoryCache());
|
|
44
66
|
const backupName = `${app}.zip`;
|
|
45
|
-
let driveAuth = options.drive
|
|
67
|
+
let driveAuth = isDriveAuth(options.drive) ? options.drive : options.drive ? gisDriveAuth({
|
|
68
|
+
clientId: options.drive.clientId,
|
|
69
|
+
scope: options.drive.scope,
|
|
70
|
+
persist: "session",
|
|
71
|
+
hint: () => rememberedDriveAccount(app)
|
|
72
|
+
}) : null;
|
|
46
73
|
if (options.cacheLock && isLockableCache(cache)) {
|
|
47
74
|
let failed = false;
|
|
48
75
|
while (!await cache.unlock(await options.cacheLock({ failed }))) failed = true;
|
|
@@ -180,7 +207,9 @@ async function selfstore(app, options = {}) {
|
|
|
180
207
|
driveAuth = auth;
|
|
181
208
|
const target = await connect$1({ auth, kv: cache.kv, fileName: backupName });
|
|
182
209
|
if (!target) return "cancelled";
|
|
183
|
-
|
|
210
|
+
const outcome = await connectTarget(target, opts);
|
|
211
|
+
if (outcome !== "cancelled") void learnDriveAccount(app, auth);
|
|
212
|
+
return outcome;
|
|
184
213
|
},
|
|
185
214
|
async connectFile(opts) {
|
|
186
215
|
if (isSupported()) {
|
|
@@ -253,7 +282,26 @@ async function selfstore(app, options = {}) {
|
|
|
253
282
|
store.dispose();
|
|
254
283
|
},
|
|
255
284
|
advanced: store,
|
|
256
|
-
flowHost: { engine: store, kv: cache.kv, backupName }
|
|
285
|
+
flowHost: { engine: store, kv: cache.kv, backupName },
|
|
286
|
+
get account() {
|
|
287
|
+
return rememberedDriveAccount(app) ?? null;
|
|
288
|
+
},
|
|
289
|
+
destinations() {
|
|
290
|
+
return driveAuth ? { drive: driveAuth, file: true } : { file: true };
|
|
291
|
+
},
|
|
292
|
+
resumeOffer() {
|
|
293
|
+
const detail = rememberedDriveAccount(app);
|
|
294
|
+
if (!driveAuth || !detail) return null;
|
|
295
|
+
const auth = driveAuth;
|
|
296
|
+
return {
|
|
297
|
+
kind: "drive",
|
|
298
|
+
detail,
|
|
299
|
+
// Reopening is not searching: fromSession takes the file id already
|
|
300
|
+
// remembered, where a fresh connect resolves by name and could land on
|
|
301
|
+
// another file carrying the same one.
|
|
302
|
+
connect: () => fromSession({ auth, kv: cache.kv, fileName: backupName })
|
|
303
|
+
};
|
|
304
|
+
}
|
|
257
305
|
};
|
|
258
306
|
return simple;
|
|
259
307
|
}
|