selfstore 1.8.19 → 1.8.21

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.
Files changed (89) hide show
  1. package/README.md +107 -12
  2. package/dist/advanced.d.ts +23 -8
  3. package/dist/advanced.js +23 -12
  4. package/dist/advanced.js.map +1 -1
  5. package/dist/backups.d.ts +4 -4
  6. package/dist/backups.js +8 -6
  7. package/dist/{cache-lock-KWJUORTS.js → cache-lock-5RNG6CIK.js} +4 -3
  8. package/dist/cache-lock-5RNG6CIK.js.map +1 -0
  9. package/dist/{chunk-SKWHKM25.js → chunk-23UAUYSW.js} +40 -4
  10. package/dist/chunk-23UAUYSW.js.map +1 -0
  11. package/dist/chunk-3BWBBGFW.js +29 -0
  12. package/dist/chunk-3BWBBGFW.js.map +1 -0
  13. package/dist/{chunk-W22V5CRM.js → chunk-3KAAPYPO.js} +3 -3
  14. package/dist/{chunk-W22V5CRM.js.map → chunk-3KAAPYPO.js.map} +1 -1
  15. package/dist/chunk-757ZOSUI.js +27 -0
  16. package/dist/chunk-757ZOSUI.js.map +1 -0
  17. package/dist/{chunk-DCEXWSM6.js → chunk-AUH35AAQ.js} +3 -3
  18. package/dist/{chunk-DCEXWSM6.js.map → chunk-AUH35AAQ.js.map} +1 -1
  19. package/dist/{chunk-TQH7ZYID.js → chunk-DJZ5S3FI.js} +31 -14
  20. package/dist/chunk-DJZ5S3FI.js.map +1 -0
  21. package/dist/{chunk-HOG2IKEP.js → chunk-EBCQ7ZG7.js} +4 -4
  22. package/dist/{chunk-HOG2IKEP.js.map → chunk-EBCQ7ZG7.js.map} +1 -1
  23. package/dist/chunk-FJGWTBAL.js +6 -0
  24. package/dist/chunk-FJGWTBAL.js.map +1 -0
  25. package/dist/chunk-GW5CYP4C.js +212 -0
  26. package/dist/chunk-GW5CYP4C.js.map +1 -0
  27. package/dist/{chunk-MGDXR3RB.js → chunk-HHPJPEEG.js} +6 -5
  28. package/dist/chunk-HHPJPEEG.js.map +1 -0
  29. package/dist/{chunk-J5MFXJU6.js → chunk-JTNFZV2B.js} +78 -26
  30. package/dist/chunk-JTNFZV2B.js.map +1 -0
  31. package/dist/chunk-JZHWAX34.js +178 -0
  32. package/dist/chunk-JZHWAX34.js.map +1 -0
  33. package/dist/chunk-LUNYYH6D.js +223 -0
  34. package/dist/chunk-LUNYYH6D.js.map +1 -0
  35. package/dist/{chunk-LKIRWVXM.js → chunk-LYO36VYB.js} +12 -11
  36. package/dist/chunk-LYO36VYB.js.map +1 -0
  37. package/dist/{chunk-O3Y6FORN.js → chunk-OY2A5DCB.js} +4 -3
  38. package/dist/chunk-OY2A5DCB.js.map +1 -0
  39. package/dist/chunk-QSLHEE2L.js +13 -0
  40. package/dist/chunk-QSLHEE2L.js.map +1 -0
  41. package/dist/{chunk-3OBJOMQ2.js → chunk-RREJ2MFN.js} +4 -28
  42. package/dist/chunk-RREJ2MFN.js.map +1 -0
  43. package/dist/chunk-XMC67RNM.js +29 -0
  44. package/dist/chunk-XMC67RNM.js.map +1 -0
  45. package/dist/{connect-BTVzRJY8.d.ts → connect-Bob2mofK.d.ts} +3 -3
  46. package/dist/{drive-CY_Vsj7V.d.ts → drive-86CHuTij.d.ts} +63 -2
  47. package/dist/flows.d.ts +5 -5
  48. package/dist/flows.js +17 -15
  49. package/dist/flows.js.map +1 -1
  50. package/dist/groups.js +4 -3
  51. package/dist/groups.js.map +1 -1
  52. package/dist/households.d.ts +1 -1
  53. package/dist/index.d.ts +66 -10
  54. package/dist/index.js +73 -18
  55. package/dist/index.js.map +1 -1
  56. package/dist/kdf-worker.js +7 -2
  57. package/dist/kdf-worker.js.map +1 -1
  58. package/dist/{local-Dh6eGiK9.d.ts → local-8H61XxbL.d.ts} +2 -2
  59. package/dist/local-XET4G32B.js +7 -0
  60. package/dist/{local-DPS35F5C.js.map → local-XET4G32B.js.map} +1 -1
  61. package/dist/{manager-DhoIbJyg.d.ts → manager-Di6lNE4E.d.ts} +1 -1
  62. package/dist/manager-drive-YLSLQ63O.js +10 -0
  63. package/dist/{manager-drive-4WLKOOXO.js.map → manager-drive-YLSLQ63O.js.map} +1 -1
  64. package/dist/s3-43RWNCV3.js +11 -0
  65. package/dist/s3-43RWNCV3.js.map +1 -0
  66. package/dist/{s3-0qqIyphl.d.ts → s3-BsbVn3fw.d.ts} +1 -1
  67. package/dist/{store-Cs6QIzzG.d.ts → store-CIbiNoiE.d.ts} +11 -3
  68. package/dist/sync.d.ts +7 -6
  69. package/dist/sync.js +3 -1
  70. package/dist/webdav-EEQKX5TZ.js +9 -0
  71. package/dist/webdav-EEQKX5TZ.js.map +1 -0
  72. package/dist/widgets.d.ts +51 -10
  73. package/dist/widgets.js +134 -34
  74. package/dist/widgets.js.map +1 -1
  75. package/llms.txt +51 -4
  76. package/package.json +12 -5
  77. package/skills/selfstore/SKILL.md +115 -0
  78. package/dist/cache-lock-KWJUORTS.js.map +0 -1
  79. package/dist/chunk-3OBJOMQ2.js.map +0 -1
  80. package/dist/chunk-J5MFXJU6.js.map +0 -1
  81. package/dist/chunk-LKIRWVXM.js.map +0 -1
  82. package/dist/chunk-MGDXR3RB.js.map +0 -1
  83. package/dist/chunk-O3Y6FORN.js.map +0 -1
  84. package/dist/chunk-SKWHKM25.js.map +0 -1
  85. package/dist/chunk-TKWU52LK.js +0 -607
  86. package/dist/chunk-TKWU52LK.js.map +0 -1
  87. package/dist/chunk-TQH7ZYID.js.map +0 -1
  88. package/dist/local-DPS35F5C.js +0 -6
  89. package/dist/manager-drive-4WLKOOXO.js +0 -8
@@ -1,5 +1,5 @@
1
- import { o as Snapshot, E as EncodeOptions, H as Header } from './store-Cs6QIzzG.js';
2
- import { a as DriveAuth } from './drive-CY_Vsj7V.js';
1
+ import { o as Snapshot, E as EncodeOptions, H as Header } from './store-CIbiNoiE.js';
2
+ import { a as DriveAuth } from './drive-86CHuTij.js';
3
3
 
4
4
  /** Serialize a snapshot to a portable backup blob (compressed; encrypted if a password is given). */
5
5
  declare function exportSnapshot(snapshot: Snapshot, opts: EncodeOptions): Promise<Blob>;
@@ -0,0 +1,7 @@
1
+ export { datedName, downloadBlob, pickFromDisk, pickSaveHandle, saveToDisk, writeToHandle } from './chunk-AUH35AAQ.js';
2
+ import './chunk-HHPJPEEG.js';
3
+ import './chunk-OY2A5DCB.js';
4
+ import './chunk-RREJ2MFN.js';
5
+ import './chunk-XMC67RNM.js';
6
+ //# sourceMappingURL=local-XET4G32B.js.map
7
+ //# sourceMappingURL=local-XET4G32B.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"local-DPS35F5C.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"local-XET4G32B.js"}
@@ -1,5 +1,5 @@
1
1
  import { K as KV } from './cache-ilsK3Tki.js';
2
- import { B as BackupTarget, L as LocalStore } from './store-Cs6QIzzG.js';
2
+ import { B as BackupTarget, L as LocalStore } from './store-CIbiNoiE.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). */
@@ -0,0 +1,10 @@
1
+ export { createBackupsManager, driveBackupsHost } from './chunk-EBCQ7ZG7.js';
2
+ import './chunk-3KAAPYPO.js';
3
+ import './chunk-JTNFZV2B.js';
4
+ import './chunk-757ZOSUI.js';
5
+ import './chunk-HHPJPEEG.js';
6
+ import './chunk-OY2A5DCB.js';
7
+ import './chunk-RREJ2MFN.js';
8
+ import './chunk-XMC67RNM.js';
9
+ //# sourceMappingURL=manager-drive-YLSLQ63O.js.map
10
+ //# sourceMappingURL=manager-drive-YLSLQ63O.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"manager-drive-4WLKOOXO.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"manager-drive-YLSLQ63O.js"}
@@ -0,0 +1,11 @@
1
+ export { connect, fromSession } from './chunk-LUNYYH6D.js';
2
+ import './chunk-QSLHEE2L.js';
3
+ import './chunk-757ZOSUI.js';
4
+ import './chunk-HHPJPEEG.js';
5
+ import './chunk-QBCU7OOP.js';
6
+ import './chunk-OY2A5DCB.js';
7
+ import './chunk-RREJ2MFN.js';
8
+ import './chunk-FJGWTBAL.js';
9
+ import './chunk-XMC67RNM.js';
10
+ //# sourceMappingURL=s3-43RWNCV3.js.map
11
+ //# sourceMappingURL=s3-43RWNCV3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"s3-43RWNCV3.js"}
@@ -1,4 +1,4 @@
1
- import { B as BackupTarget, P as PeerSource } from './store-Cs6QIzzG.js';
1
+ import { B as BackupTarget, P as PeerSource } from './store-CIbiNoiE.js';
2
2
  import { K as KV } from './cache-ilsK3Tki.js';
3
3
 
4
4
  /**
@@ -149,7 +149,7 @@ interface EncodeOptions {
149
149
  extraSecrets?: string[];
150
150
  }
151
151
 
152
- type SelfstoreErrorCode = 'BAD_FORMAT' | 'UNSUPPORTED_VERSION' | 'PASSWORD_REQUIRED' | 'DECRYPT_FAILED' | 'TOO_LARGE' | 'VERIFY_FAILED' | 'FOREIGN_BACKUP' | 'AUTH_EXPIRED' | 'TARGET_UNAVAILABLE' | 'TARGET_WRITE_FAILED' | 'TARGET_GONE' | 'NOT_CONNECTED' | 'WEAK_PASSWORD' | 'ENCRYPTION_REQUIRED' | 'UNEXPECTEDLY_UNENCRYPTED' | 'SCHEMA_TOO_NEW' | 'IDENTITY_REQUIRED' | 'SIGNATURE_INVALID' | 'NOT_A_RECIPIENT' | 'MANIFEST_ROLLBACK';
152
+ type SelfstoreErrorCode = 'BAD_FORMAT' | 'UNSUPPORTED_VERSION' | 'PASSWORD_REQUIRED' | 'DECRYPT_FAILED' | 'TOO_LARGE' | 'VERIFY_FAILED' | 'FOREIGN_BACKUP' | 'AUTH_EXPIRED' | 'TARGET_UNAVAILABLE' | 'TARGET_WRITE_FAILED' | 'TARGET_GONE' | 'NOT_CONNECTED' | 'WEAK_PASSWORD' | 'ENCRYPTION_REQUIRED' | 'UNEXPECTEDLY_UNENCRYPTED' | 'SCHEMA_TOO_NEW' | 'IDENTITY_REQUIRED' | 'SIGNATURE_INVALID' | 'NOT_A_RECIPIENT' | 'MANIFEST_ROLLBACK' | 'CLOCK_DRIFT';
153
153
  /**
154
154
  * i18n key for an error code: lower-camel-cased under `error.`, e.g.
155
155
  * 'error.authExpired'. The library ships the key, the app owns the copy;
@@ -566,8 +566,16 @@ interface LocalStore {
566
566
  detachTarget(opts?: {
567
567
  keepSession?: boolean;
568
568
  }): Promise<void>;
569
- /** Build the portable .selfstore blob (for a manual download or dated copy). */
570
- exportBlob(): Promise<Blob>;
569
+ /** Build the portable .selfstore blob (for a manual download or dated copy).
570
+ *
571
+ * `plaintext` writes a READABLE copy even when the store is protected: the
572
+ * same ZIP, with `selfstore.json` in the clear, for someone who wants to
573
+ * read, inspect or move their own data. It changes nothing about the store
574
+ * or its destination - the real backup stays encrypted. Refused while
575
+ * locked, and refused outright on a `requireEncryption` store. */
576
+ exportBlob(opts?: {
577
+ plaintext?: boolean;
578
+ }): Promise<Blob>;
571
579
  /** Mark the file-manual pending download as resolved. */
572
580
  markDownloaded(): void;
573
581
  /** Stop persisting (shared computer). */
package/dist/sync.d.ts CHANGED
@@ -4,7 +4,13 @@
4
4
  * string so a plain string comparison equals causal order.
5
5
  */
6
6
  type Hlc = string;
7
- /** A fresh random replica id (one per device). */
7
+ /**
8
+ * A fresh random replica id (one per device). Not a secret - but two replicas
9
+ * sharing an id lose the tiebreak that makes the order total, so it comes from
10
+ * the same source as everything else here. `randomUUID` is exposed only in a
11
+ * secure context; `getRandomValues` is not, which is why the fallback is that
12
+ * one and never `Math.random`.
13
+ */
8
14
  declare function createNode(): string;
9
15
 
10
16
  /**
@@ -79,11 +85,6 @@ interface ReplicaState {
79
85
  meta: SyncMeta;
80
86
  }
81
87
  type State = ReplicaState;
82
- /**
83
- * Merge replica `b` into `a` (commutative for the convergent strategies). The
84
- * optional `base` lets 'manual' tell a true concurrent conflict from a one-sided
85
- * change; without it, 'manual' errs toward surfacing.
86
- */
87
88
  declare function merge(a: State, b: State, config: SyncConfig, base?: SyncMeta): MergeResult;
88
89
  /**
89
90
  * Concurrent same-id edits that a convergent strategy resolves silently by keeping
package/dist/sync.js CHANGED
@@ -1,3 +1,5 @@
1
- export { changes, createMeta, createNode, detectConflicts, merge, stamp } from './chunk-SKWHKM25.js';
1
+ export { changes, createMeta, createNode, detectConflicts, merge, stamp } from './chunk-23UAUYSW.js';
2
+ import './chunk-FJGWTBAL.js';
3
+ import './chunk-XMC67RNM.js';
2
4
  //# sourceMappingURL=sync.js.map
3
5
  //# sourceMappingURL=sync.js.map
@@ -0,0 +1,9 @@
1
+ export { connect, fromSession, peer } from './chunk-JZHWAX34.js';
2
+ import './chunk-757ZOSUI.js';
3
+ import './chunk-HHPJPEEG.js';
4
+ import './chunk-QBCU7OOP.js';
5
+ import './chunk-OY2A5DCB.js';
6
+ import './chunk-RREJ2MFN.js';
7
+ import './chunk-XMC67RNM.js';
8
+ //# sourceMappingURL=webdav-EEQKX5TZ.js.map
9
+ //# sourceMappingURL=webdav-EEQKX5TZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"webdav-EEQKX5TZ.js"}
package/dist/widgets.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { S as StoreLike, F as FlowHost, C as ConnectTargets, a as ConnectFlowOptions, b as ConnectKind, c as ConnectFlow } from './connect-BTVzRJY8.js';
1
+ import { S as StoreLike, F as FlowHost, C as ConnectTargets, a as ConnectFlowOptions, b as ConnectKind, c as ConnectFlow } from './connect-Bob2mofK.js';
2
2
  import { ShareEngine, ShareLevel, ShareFlow, JoinEngine, JoinFlow, ReplicaFlow } from './flows.js';
3
- import { f as BackupsManager } from './manager-DhoIbJyg.js';
4
- import './store-Cs6QIzzG.js';
3
+ import { f as BackupsManager } from './manager-Di6lNE4E.js';
4
+ import './store-CIbiNoiE.js';
5
5
  import './cache-ilsK3Tki.js';
6
6
  import './sync.js';
7
- import './drive-CY_Vsj7V.js';
8
- import './s3-0qqIyphl.js';
7
+ import './drive-86CHuTij.js';
8
+ import './s3-BsbVn3fw.js';
9
9
  import './machine-ALMkT3mk.js';
10
10
 
11
11
  /** Flat key -> string map; widgets merge a partial override over EN defaults. */
@@ -576,6 +576,7 @@ declare class SelfstoreGateElement extends FlowWidget {
576
576
  constructor();
577
577
  attributeChangedCallback(name: string): void;
578
578
  connectedCallback(): void;
579
+ disconnectedCallback(): void;
579
580
  private host;
580
581
  private wire;
581
582
  /** The library already derives "no durable home yet" - asking the target
@@ -684,6 +685,20 @@ declare class SelfstoreDestinationElement extends FlowWidget {
684
685
  * a host can still mount separately, with every knob they already had. What is
685
686
  * added here is only the CHOICE between them, which follows the engine's own
686
687
  * status - the same signal the gate uses to decide whether to be on screen.
688
+ *
689
+ * WHERE IT FITS, and where it does not. Before a home is chosen this element IS
690
+ * the gate, and the gate is a full-viewport modal (measured: it covers the page
691
+ * at z-index 280 and takes focus). That is right for an app whose data means
692
+ * nothing until the user answers - a wallet, a record, anything the user will
693
+ * be told is safe - and it is the reason the question is asked once, up front,
694
+ * instead of hiding in a settings screen.
695
+ *
696
+ * It is wrong for a page that must work before any answer: a landing demo, a
697
+ * scratchpad, anything whose whole point is that you can type first. There,
698
+ * mount <selfstore-destination> (the panel on its own, no modal) or
699
+ * <selfstore-status> (one line), and offer the connect journey from a control
700
+ * the user reaches deliberately. Both are the same elements this one composes,
701
+ * so nothing is lost by starting there.
687
702
  */
688
703
 
689
704
  declare class SelfstoreStorageElement extends FlowWidget {
@@ -831,10 +846,36 @@ declare class SelfstoreAccountElement extends FlowWidget {
831
846
  * file on the device, a server for WebDAV, a bucket for object storage. */
832
847
  declare const defaultIcons: Record<ConnectKind, string>;
833
848
 
834
- /** Register the elements as <PREFIX-connect>, <PREFIX-share>, <PREFIX-join>,
835
- * <PREFIX-status>, <PREFIX-backups>, <PREFIX-gate> and
836
- * <PREFIX-destination> (default prefix 'selfstore'). Safe to call twice;
837
- * throws in environments without custom elements (browser code only). */
849
+ /** Register <PREFIX-connect>: the "where does my data live" journey. */
850
+ declare function defineConnect(prefix?: string): void;
851
+ /** Register <PREFIX-status>: the live storage status line. */
852
+ declare function defineStatus(prefix?: string): void;
853
+ /** Register <PREFIX-share>: publishing an invitation. */
854
+ declare function defineShare(prefix?: string): void;
855
+ /** Register <PREFIX-join>: accepting an invitation. */
856
+ declare function defineJoin(prefix?: string): void;
857
+ /** Register <PREFIX-backups>: the named-backup manager. */
858
+ declare function defineBackups(prefix?: string): void;
859
+ /** Register <PREFIX-gate>, the blocking first-run screen, with the
860
+ * <PREFIX-connect> child it builds for itself. */
861
+ declare function defineGate(prefix?: string): void;
862
+ /** Register <PREFIX-destination>, the storage panel, with the connect and
863
+ * status elements it composes. */
864
+ declare function defineDestination(prefix?: string): void;
865
+ /** Register <PREFIX-storage>: the whole journey in one tag. It chooses between
866
+ * the gate and the destination panel from the engine's own status, so both
867
+ * come with it. */
868
+ declare function defineStorage(prefix?: string): void;
869
+ /** Register <PREFIX-account>, the header control, with the status row it
870
+ * composes for anything needing attention. */
871
+ declare function defineAccount(prefix?: string): void;
872
+ /** Register all nine elements at once (default prefix 'selfstore'). Safe to
873
+ * call twice; throws in environments without custom elements (browser code
874
+ * only).
875
+ *
876
+ * Convenient, and the reason a small app ships every widget: naming all nine
877
+ * here is what pins them in the bundle. Reach for the single-widget functions
878
+ * above when size matters. */
838
879
  declare function defineSelfstoreWidgets(prefix?: string): void;
839
880
 
840
- export { type BackupsAction, type DestinationAction, FlowWidget, SelfstoreAccountElement, SelfstoreBackupsElement, SelfstoreConnectElement, SelfstoreDestinationElement, SelfstoreGateElement, SelfstoreJoinElement, SelfstoreShareElement, SelfstoreStatusElement, SelfstoreStorageElement, type ShareAction, type WebdavPreset, type WidgetLabels, defaultIcons, defineSelfstoreWidgets };
881
+ export { type BackupsAction, type DestinationAction, FlowWidget, SelfstoreAccountElement, SelfstoreBackupsElement, SelfstoreConnectElement, SelfstoreDestinationElement, SelfstoreGateElement, SelfstoreJoinElement, SelfstoreShareElement, SelfstoreStatusElement, SelfstoreStorageElement, type ShareAction, type WebdavPreset, type WidgetLabels, defaultIcons, defineAccount, defineBackups, defineConnect, defineDestination, defineGate, defineJoin, defineSelfstoreWidgets, defineShare, defineStatus, defineStorage };
package/dist/widgets.js CHANGED
@@ -1,12 +1,14 @@
1
- import { saveToDisk, datedName } from './chunk-DCEXWSM6.js';
2
- import { connectFlow, shareFlow, joinFlow } from './chunk-LKIRWVXM.js';
3
- import { isOpenSupported } from './chunk-TKWU52LK.js';
4
- import './chunk-W22V5CRM.js';
5
- import './chunk-J5MFXJU6.js';
6
- import './chunk-MGDXR3RB.js';
7
- import './chunk-QBCU7OOP.js';
8
- import './chunk-O3Y6FORN.js';
9
- import './chunk-3OBJOMQ2.js';
1
+ import { saveToDisk, datedName } from './chunk-AUH35AAQ.js';
2
+ import { connectFlow, shareFlow, joinFlow } from './chunk-LYO36VYB.js';
3
+ import './chunk-3BWBBGFW.js';
4
+ import { isOpenSupported } from './chunk-GW5CYP4C.js';
5
+ import './chunk-3KAAPYPO.js';
6
+ import './chunk-JTNFZV2B.js';
7
+ import './chunk-757ZOSUI.js';
8
+ import './chunk-HHPJPEEG.js';
9
+ import './chunk-OY2A5DCB.js';
10
+ import './chunk-RREJ2MFN.js';
11
+ import './chunk-XMC67RNM.js';
10
12
 
11
13
  // src/widgets/icons.ts
12
14
  var INK = "#8a8f98";
@@ -38,13 +40,23 @@ var baseStyles = `
38
40
  color: inherit;
39
41
  --_accent: var(--selfstore-accent, #2563eb);
40
42
  --_accent-ink: var(--selfstore-accent-contrast, #ffffff);
41
- --_ink-dim: var(--selfstore-muted, color-mix(in srgb, currentColor 55%, transparent));
43
+ /* Dimmed ink is TEXT too - it words every sub, hint and field label - so it
44
+ answers to 4.5:1, and an alpha over the host background is what decides
45
+ that. At 55% a near-black ink on white composited to 3.99:1 and failed;
46
+ 62% lands at 5.0:1 there and at 6.3:1 for a near-white ink on a near-black
47
+ page, while still reading a clear step below the main ink. */
48
+ --_ink-dim: var(--selfstore-muted, color-mix(in srgb, currentColor 62%, transparent));
42
49
  --_border: var(--selfstore-border, color-mix(in srgb, currentColor 16%, transparent));
43
50
  --_radius: var(--selfstore-radius, 12px);
44
51
  --_gap: var(--selfstore-gap, 0.6rem);
45
52
  --_danger: var(--selfstore-danger, #dc2626);
46
- --_ok: var(--selfstore-ok, #16a34a);
47
- --_warn: var(--selfstore-warn, #d97706);
53
+ /* Severity colors are read as TEXT (see sev-* below), so they answer to the
54
+ 4.5:1 text threshold, not the 3:1 one for a graphic. The obvious green and
55
+ amber of a palette sit at 3.3:1 and 3.2:1 on white and fail it: a status
56
+ line is exactly the sentence someone needs to read. One step darker each
57
+ clears it at 5.0:1 without changing which color anyone thinks they see. */
58
+ --_ok: var(--selfstore-ok, #15803d);
59
+ --_warn: var(--selfstore-warn, #b45309);
48
60
  }
49
61
  /* Status severity, as a text color the dot inherits (background: currentColor). */
50
62
  [part~='sev-ok'] { color: var(--_ok); }
@@ -155,6 +167,12 @@ span[part~='status-glyph'] {
155
167
  animation: ss-spin 0.8s linear infinite;
156
168
  }
157
169
  @keyframes ss-spin { to { transform: rotate(360deg); } }
170
+ /* An endless spin is the one motion here, and it runs during the wait someone
171
+ with vestibular trouble cannot escape. Keep the shape as the busy signal,
172
+ drop the rotation. */
173
+ @media (prefers-reduced-motion: reduce) {
174
+ [part='spinner'] { animation: none; border-top-color: var(--_border); }
175
+ }
158
176
  button[part~='button'] {
159
177
  font: inherit;
160
178
  padding: 0.45rem 0.9rem;
@@ -1019,7 +1037,7 @@ var SelfstoreConnectElement = class extends FlowWidget {
1019
1037
  h("div", { part: "title" }, this.t("connect.password.title")),
1020
1038
  h("div", { part: "hint" }, this.t("connect.password.hint")),
1021
1039
  field,
1022
- s.passwordError ? h("div", { part: "error-note" }, this.t("connect.password.wrong")) : null,
1040
+ s.passwordError ? h("div", { part: "error-note", role: "alert" }, this.t("connect.password.wrong")) : null,
1023
1041
  h(
1024
1042
  "div",
1025
1043
  { part: "row" },
@@ -1632,7 +1650,9 @@ var SelfstoreShareElement = class extends FlowWidget {
1632
1650
  put(into, this.heading("title", "share.title"));
1633
1651
  if (s.stale) into.append(h("div", { part: "hint" }, this.t("share.stale")));
1634
1652
  if (s.error && !s.stale) {
1635
- into.append(h("div", { part: "error-note" }, this.errorText(s.error.labelKey)));
1653
+ into.append(
1654
+ h("div", { part: "error-note", role: "alert" }, this.errorText(s.error.labelKey))
1655
+ );
1636
1656
  }
1637
1657
  if (this.#withCreate) {
1638
1658
  const missing = this.#levels.filter((l) => !s.links.some((k) => k.level === l));
@@ -2118,6 +2138,7 @@ var FR5 = {
2118
2138
  "status.action.reconnect": "Retrouver l'acc\xE8s",
2119
2139
  "status.action.unlock": "D\xE9verrouiller"
2120
2140
  };
2141
+ var GLYPH = { ok: "\u2713", warn: "!", danger: "!", info: "" };
2121
2142
  var SelfstoreStatusElement = class extends FlowWidget {
2122
2143
  static get observedAttributes() {
2123
2144
  return ["variant"];
@@ -2146,6 +2167,7 @@ var SelfstoreStatusElement = class extends FlowWidget {
2146
2167
  }
2147
2168
  connectedCallback() {
2148
2169
  super.connectedCallback();
2170
+ if (!this.hasAttribute("role")) this.setAttribute("role", "status");
2149
2171
  if (this.hasAttribute("variant"))
2150
2172
  this.variant = this.getAttribute("variant");
2151
2173
  this.follow(this.hostOf());
@@ -2174,7 +2196,6 @@ var SelfstoreStatusElement = class extends FlowWidget {
2174
2196
  part: `status-dot sev-${status.severity}`,
2175
2197
  "aria-hidden": "true"
2176
2198
  });
2177
- const GLYPH = { ok: "\u2713", warn: "!", danger: "!", info: "" };
2178
2199
  const glyph = GLYPH[status.severity];
2179
2200
  const sign = glyph ? h("span", { part: `status-glyph sev-${status.severity}`, "aria-hidden": "true" }, glyph) : dot;
2180
2201
  if (this.#variant === "dot") {
@@ -2944,7 +2965,7 @@ var SelfstoreBackupsElement = class extends FlowWidget {
2944
2965
  this.rerender();
2945
2966
  }
2946
2967
  }),
2947
- taken ? h("div", { part: "error-note" }, this.t("backups.taken")) : clean ? h(
2968
+ taken ? h("div", { part: "error-note", role: "alert" }, this.t("backups.taken")) : clean ? h(
2948
2969
  "div",
2949
2970
  { part: "sub" },
2950
2971
  this.ts("backups.willBe", { file: this.#manager?.fileNameFor(clean) ?? "" })
@@ -3002,7 +3023,7 @@ var SelfstoreBackupsElement = class extends FlowWidget {
3002
3023
  this.rerender();
3003
3024
  }
3004
3025
  }),
3005
- taken ? h("div", { part: "error-note" }, this.t("backups.taken")) : clean ? h(
3026
+ taken ? h("div", { part: "error-note", role: "alert" }, this.t("backups.taken")) : clean ? h(
3006
3027
  "div",
3007
3028
  { part: "sub" },
3008
3029
  this.ts("backups.willBe", { file: this.#manager?.fileNameFor(clean) ?? "" })
@@ -3109,7 +3130,7 @@ var SelfstoreBackupsElement = class extends FlowWidget {
3109
3130
  this.t(`backups.replica.dest.${kind}`)
3110
3131
  )
3111
3132
  ),
3112
- snap.error ? h("div", { part: "error-note" }, this.t("error.generic")) : null,
3133
+ snap.error ? h("div", { part: "error-note", role: "alert" }, this.t("error.generic")) : null,
3113
3134
  h(
3114
3135
  "button",
3115
3136
  {
@@ -3161,7 +3182,7 @@ var SelfstoreBackupsElement = class extends FlowWidget {
3161
3182
  c.password,
3162
3183
  (v) => c.password = v
3163
3184
  ),
3164
- snap.error ? h("div", { part: "error-note" }, this.t("error.generic")) : null,
3185
+ snap.error ? h("div", { part: "error-note", role: "alert" }, this.t("error.generic")) : null,
3165
3186
  h(
3166
3187
  "div",
3167
3188
  { part: "row", style: "margin-top:0.45rem" },
@@ -3218,7 +3239,7 @@ var SelfstoreBackupsElement = class extends FlowWidget {
3218
3239
  c.secretAccessKey,
3219
3240
  (v) => c.secretAccessKey = v
3220
3241
  ),
3221
- snap.error ? h("div", { part: "error-note" }, this.t("error.generic")) : null,
3242
+ snap.error ? h("div", { part: "error-note", role: "alert" }, this.t("error.generic")) : null,
3222
3243
  h(
3223
3244
  "div",
3224
3245
  { part: "row", style: "margin-top:0.45rem" },
@@ -3628,6 +3649,11 @@ var SelfstoreGateElement = class extends FlowWidget {
3628
3649
  if (deferrable !== null) this.deferrable = deferrable;
3629
3650
  this.wire();
3630
3651
  }
3652
+ disconnectedCallback() {
3653
+ super.disconnectedCallback();
3654
+ document.removeEventListener("focusin", this.#keepFocus);
3655
+ this.#focusBefore = null;
3656
+ }
3631
3657
  host() {
3632
3658
  const s = this.#store;
3633
3659
  if (!s) return null;
@@ -3650,13 +3676,46 @@ var SelfstoreGateElement = class extends FlowWidget {
3650
3676
  if (!host.engine.state.ready) return false;
3651
3677
  return host.engine.state.status.action === "choose-destination";
3652
3678
  }
3679
+ /** Where focus was when the gate took over, so it can be handed back. */
3680
+ #focusBefore = null;
3681
+ /** `aria-modal` tells assistive tech this is modal; it does NOT stop the Tab
3682
+ * key. Without this, a keyboard user tabs straight out of a screen whose
3683
+ * whole purpose is to block, and lands in the application behind it -
3684
+ * invisibly, since the gate still covers what they are now driving.
3685
+ *
3686
+ * A guard rather than a cycle through the focusable elements: the gate
3687
+ * contains a `<selfstore-connect>` with its own shadow root, and walking
3688
+ * focusables across shadow boundaries is the kind of code that quietly
3689
+ * stops matching the DOM it walks. Anything landing outside comes straight
3690
+ * back to the card, which is correct whatever the widget grows inside. */
3691
+ #pulling = false;
3692
+ #keepFocus = (e) => {
3693
+ if (!this.#open || this.#pulling) return;
3694
+ if (e.composedPath().includes(this)) return;
3695
+ const card = this.root.querySelector('[part~="gate-card"]');
3696
+ if (!card) return;
3697
+ this.#pulling = true;
3698
+ try {
3699
+ card.focus();
3700
+ } finally {
3701
+ this.#pulling = false;
3702
+ }
3703
+ };
3653
3704
  sync() {
3654
3705
  const open = this.shouldOpen();
3655
3706
  if (open === this.#open) return;
3656
3707
  this.#open = open;
3657
3708
  if (!open) this.#connect = null;
3658
3709
  super.rerender();
3659
- if (open) this.root.querySelector('[part~="gate-card"]')?.focus();
3710
+ if (open) {
3711
+ this.#focusBefore = document.activeElement ?? null;
3712
+ document.addEventListener("focusin", this.#keepFocus);
3713
+ this.root.querySelector('[part~="gate-card"]')?.focus();
3714
+ return;
3715
+ }
3716
+ document.removeEventListener("focusin", this.#keepFocus);
3717
+ this.#focusBefore?.focus?.();
3718
+ this.#focusBefore = null;
3660
3719
  }
3661
3720
  /** Rebuilding the frame would re-append the child connect element, and a
3662
3721
  * custom element that leaves the DOM and comes back rebuilds its flow: a
@@ -4529,21 +4588,62 @@ var SelfstoreAccountElement = class extends FlowWidget {
4529
4588
  };
4530
4589
 
4531
4590
  // src/entries/widgets.ts
4591
+ function register(prefix, tags) {
4592
+ for (const [name, ctor] of Object.entries(tags)) {
4593
+ const tag = `${prefix}-${name}`;
4594
+ if (!customElements.get(tag)) customElements.define(tag, ctor);
4595
+ }
4596
+ }
4597
+ function defineConnect(prefix = "selfstore") {
4598
+ register(prefix, { connect: SelfstoreConnectElement });
4599
+ }
4600
+ function defineStatus(prefix = "selfstore") {
4601
+ register(prefix, { status: SelfstoreStatusElement });
4602
+ }
4603
+ function defineShare(prefix = "selfstore") {
4604
+ register(prefix, { share: SelfstoreShareElement });
4605
+ }
4606
+ function defineJoin(prefix = "selfstore") {
4607
+ register(prefix, { join: SelfstoreJoinElement });
4608
+ }
4609
+ function defineBackups(prefix = "selfstore") {
4610
+ register(prefix, { backups: SelfstoreBackupsElement });
4611
+ }
4612
+ function defineGate(prefix = "selfstore") {
4613
+ register(prefix, { connect: SelfstoreConnectElement, gate: SelfstoreGateElement });
4614
+ }
4615
+ function defineDestination(prefix = "selfstore") {
4616
+ register(prefix, {
4617
+ connect: SelfstoreConnectElement,
4618
+ status: SelfstoreStatusElement,
4619
+ destination: SelfstoreDestinationElement
4620
+ });
4621
+ }
4622
+ function defineStorage(prefix = "selfstore") {
4623
+ defineGate(prefix);
4624
+ defineDestination(prefix);
4625
+ register(prefix, { storage: SelfstoreStorageElement });
4626
+ }
4627
+ function defineAccount(prefix = "selfstore") {
4628
+ register(prefix, {
4629
+ status: SelfstoreStatusElement,
4630
+ account: SelfstoreAccountElement
4631
+ });
4632
+ }
4532
4633
  function defineSelfstoreWidgets(prefix = "selfstore") {
4533
- const define = (name, ctor) => {
4534
- if (!customElements.get(name)) customElements.define(name, ctor);
4535
- };
4536
- define(`${prefix}-connect`, SelfstoreConnectElement);
4537
- define(`${prefix}-share`, SelfstoreShareElement);
4538
- define(`${prefix}-join`, SelfstoreJoinElement);
4539
- define(`${prefix}-status`, SelfstoreStatusElement);
4540
- define(`${prefix}-backups`, SelfstoreBackupsElement);
4541
- define(`${prefix}-gate`, SelfstoreGateElement);
4542
- define(`${prefix}-destination`, SelfstoreDestinationElement);
4543
- define(`${prefix}-storage`, SelfstoreStorageElement);
4544
- define(`${prefix}-account`, SelfstoreAccountElement);
4634
+ register(prefix, {
4635
+ connect: SelfstoreConnectElement,
4636
+ share: SelfstoreShareElement,
4637
+ join: SelfstoreJoinElement,
4638
+ status: SelfstoreStatusElement,
4639
+ backups: SelfstoreBackupsElement,
4640
+ gate: SelfstoreGateElement,
4641
+ destination: SelfstoreDestinationElement,
4642
+ storage: SelfstoreStorageElement,
4643
+ account: SelfstoreAccountElement
4644
+ });
4545
4645
  }
4546
4646
 
4547
- export { FlowWidget, SelfstoreAccountElement, SelfstoreBackupsElement, SelfstoreConnectElement, SelfstoreDestinationElement, SelfstoreGateElement, SelfstoreJoinElement, SelfstoreShareElement, SelfstoreStatusElement, SelfstoreStorageElement, defaultIcons, defineSelfstoreWidgets };
4647
+ export { FlowWidget, SelfstoreAccountElement, SelfstoreBackupsElement, SelfstoreConnectElement, SelfstoreDestinationElement, SelfstoreGateElement, SelfstoreJoinElement, SelfstoreShareElement, SelfstoreStatusElement, SelfstoreStorageElement, defaultIcons, defineAccount, defineBackups, defineConnect, defineDestination, defineGate, defineJoin, defineSelfstoreWidgets, defineShare, defineStatus, defineStorage };
4548
4648
  //# sourceMappingURL=widgets.js.map
4549
4649
  //# sourceMappingURL=widgets.js.map