@interop/was-react 0.1.0

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 (223) hide show
  1. package/LICENSE.md +20 -0
  2. package/README.md +410 -0
  3. package/dist/auth/chapi.d.ts +43 -0
  4. package/dist/auth/chapi.d.ts.map +1 -0
  5. package/dist/auth/chapi.js +107 -0
  6. package/dist/auth/chapi.js.map +1 -0
  7. package/dist/auth/loginFlow.d.ts +93 -0
  8. package/dist/auth/loginFlow.d.ts.map +1 -0
  9. package/dist/auth/loginFlow.js +149 -0
  10. package/dist/auth/loginFlow.js.map +1 -0
  11. package/dist/auth/loginRequest.d.ts +66 -0
  12. package/dist/auth/loginRequest.d.ts.map +1 -0
  13. package/dist/auth/loginRequest.js +83 -0
  14. package/dist/auth/loginRequest.js.map +1 -0
  15. package/dist/auth/verifyResponse.d.ts +52 -0
  16. package/dist/auth/verifyResponse.d.ts.map +1 -0
  17. package/dist/auth/verifyResponse.js +138 -0
  18. package/dist/auth/verifyResponse.js.map +1 -0
  19. package/dist/auth/verifyResponse.test.d.ts +2 -0
  20. package/dist/auth/verifyResponse.test.d.ts.map +1 -0
  21. package/dist/auth/verifyResponse.test.js +282 -0
  22. package/dist/auth/verifyResponse.test.js.map +1 -0
  23. package/dist/auth/walletRequestTypes.d.ts +143 -0
  24. package/dist/auth/walletRequestTypes.d.ts.map +1 -0
  25. package/dist/auth/walletRequestTypes.js +2 -0
  26. package/dist/auth/walletRequestTypes.js.map +1 -0
  27. package/dist/config.d.ts +150 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +27 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/dev/cli.d.ts +16 -0
  32. package/dist/dev/cli.d.ts.map +1 -0
  33. package/dist/dev/cli.js +122 -0
  34. package/dist/dev/cli.js.map +1 -0
  35. package/dist/dev/cli.test.d.ts +2 -0
  36. package/dist/dev/cli.test.d.ts.map +1 -0
  37. package/dist/dev/cli.test.js +39 -0
  38. package/dist/dev/cli.test.js.map +1 -0
  39. package/dist/dev/index.d.ts +10 -0
  40. package/dist/dev/index.d.ts.map +1 -0
  41. package/dist/dev/index.js +10 -0
  42. package/dist/dev/index.js.map +1 -0
  43. package/dist/dev/provisionDevGrants.d.ts +73 -0
  44. package/dist/dev/provisionDevGrants.d.ts.map +1 -0
  45. package/dist/dev/provisionDevGrants.js +176 -0
  46. package/dist/dev/provisionDevGrants.js.map +1 -0
  47. package/dist/grants.d.ts +59 -0
  48. package/dist/grants.d.ts.map +1 -0
  49. package/dist/grants.js +82 -0
  50. package/dist/grants.js.map +1 -0
  51. package/dist/grants.test.d.ts +2 -0
  52. package/dist/grants.test.d.ts.map +1 -0
  53. package/dist/grants.test.js +79 -0
  54. package/dist/grants.test.js.map +1 -0
  55. package/dist/identity/agents.d.ts +99 -0
  56. package/dist/identity/agents.d.ts.map +1 -0
  57. package/dist/identity/agents.js +132 -0
  58. package/dist/identity/agents.js.map +1 -0
  59. package/dist/identity/appSession.d.ts +78 -0
  60. package/dist/identity/appSession.d.ts.map +1 -0
  61. package/dist/identity/appSession.js +93 -0
  62. package/dist/identity/appSession.js.map +1 -0
  63. package/dist/identity/documentLoader.d.ts +20 -0
  64. package/dist/identity/documentLoader.d.ts.map +1 -0
  65. package/dist/identity/documentLoader.js +99 -0
  66. package/dist/identity/documentLoader.js.map +1 -0
  67. package/dist/identity/initAppSession.d.ts +27 -0
  68. package/dist/identity/initAppSession.d.ts.map +1 -0
  69. package/dist/identity/initAppSession.js +30 -0
  70. package/dist/identity/initAppSession.js.map +1 -0
  71. package/dist/identity/seedCredential.d.ts +74 -0
  72. package/dist/identity/seedCredential.d.ts.map +1 -0
  73. package/dist/identity/seedCredential.js +165 -0
  74. package/dist/identity/seedCredential.js.map +1 -0
  75. package/dist/identity/seedCredential.test.d.ts +2 -0
  76. package/dist/identity/seedCredential.test.d.ts.map +1 -0
  77. package/dist/identity/seedCredential.test.js +205 -0
  78. package/dist/identity/seedCredential.test.js.map +1 -0
  79. package/dist/identity/seedStore.d.ts +27 -0
  80. package/dist/identity/seedStore.d.ts.map +1 -0
  81. package/dist/identity/seedStore.js +74 -0
  82. package/dist/identity/seedStore.js.map +1 -0
  83. package/dist/index.d.ts +37 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +46 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/mui/ProtectedRoute.d.ts +10 -0
  88. package/dist/mui/ProtectedRoute.d.ts.map +1 -0
  89. package/dist/mui/ProtectedRoute.js +54 -0
  90. package/dist/mui/ProtectedRoute.js.map +1 -0
  91. package/dist/mui/ReconnectBanner.d.ts +2 -0
  92. package/dist/mui/ReconnectBanner.d.ts.map +1 -0
  93. package/dist/mui/ReconnectBanner.js +20 -0
  94. package/dist/mui/ReconnectBanner.js.map +1 -0
  95. package/dist/mui/SyncStatusChip.d.ts +2 -0
  96. package/dist/mui/SyncStatusChip.d.ts.map +1 -0
  97. package/dist/mui/SyncStatusChip.js +27 -0
  98. package/dist/mui/SyncStatusChip.js.map +1 -0
  99. package/dist/mui/index.d.ts +12 -0
  100. package/dist/mui/index.d.ts.map +1 -0
  101. package/dist/mui/index.js +12 -0
  102. package/dist/mui/index.js.map +1 -0
  103. package/dist/react/WasSessionProvider.d.ts +36 -0
  104. package/dist/react/WasSessionProvider.d.ts.map +1 -0
  105. package/dist/react/WasSessionProvider.js +35 -0
  106. package/dist/react/WasSessionProvider.js.map +1 -0
  107. package/dist/react/hooks.d.ts +66 -0
  108. package/dist/react/hooks.d.ts.map +1 -0
  109. package/dist/react/hooks.js +121 -0
  110. package/dist/react/hooks.js.map +1 -0
  111. package/dist/react/index.d.ts +11 -0
  112. package/dist/react/index.d.ts.map +1 -0
  113. package/dist/react/index.js +11 -0
  114. package/dist/react/index.js.map +1 -0
  115. package/dist/session/appReadyStore.d.ts +10 -0
  116. package/dist/session/appReadyStore.d.ts.map +1 -0
  117. package/dist/session/appReadyStore.js +22 -0
  118. package/dist/session/appReadyStore.js.map +1 -0
  119. package/dist/session/authStore.d.ts +71 -0
  120. package/dist/session/authStore.d.ts.map +1 -0
  121. package/dist/session/authStore.js +347 -0
  122. package/dist/session/authStore.js.map +1 -0
  123. package/dist/session/index.d.ts +10 -0
  124. package/dist/session/index.d.ts.map +1 -0
  125. package/dist/session/index.js +10 -0
  126. package/dist/session/index.js.map +1 -0
  127. package/dist/storage/entityStore.d.ts +51 -0
  128. package/dist/storage/entityStore.d.ts.map +1 -0
  129. package/dist/storage/entityStore.js +78 -0
  130. package/dist/storage/entityStore.js.map +1 -0
  131. package/dist/storage/localStore.d.ts +144 -0
  132. package/dist/storage/localStore.d.ts.map +1 -0
  133. package/dist/storage/localStore.js +289 -0
  134. package/dist/storage/localStore.js.map +1 -0
  135. package/dist/storage/rehydrate.d.ts +56 -0
  136. package/dist/storage/rehydrate.d.ts.map +1 -0
  137. package/dist/storage/rehydrate.js +87 -0
  138. package/dist/storage/rehydrate.js.map +1 -0
  139. package/dist/storage/rehydrate.test.d.ts +2 -0
  140. package/dist/storage/rehydrate.test.d.ts.map +1 -0
  141. package/dist/storage/rehydrate.test.js +172 -0
  142. package/dist/storage/rehydrate.test.js.map +1 -0
  143. package/dist/storage/storageManager.d.ts +39 -0
  144. package/dist/storage/storageManager.d.ts.map +1 -0
  145. package/dist/storage/storageManager.js +68 -0
  146. package/dist/storage/storageManager.js.map +1 -0
  147. package/dist/storage/syncController.d.ts +79 -0
  148. package/dist/storage/syncController.d.ts.map +1 -0
  149. package/dist/storage/syncController.js +189 -0
  150. package/dist/storage/syncController.js.map +1 -0
  151. package/dist/storage/syncStatusStore.d.ts +17 -0
  152. package/dist/storage/syncStatusStore.d.ts.map +1 -0
  153. package/dist/storage/syncStatusStore.js +19 -0
  154. package/dist/storage/syncStatusStore.js.map +1 -0
  155. package/dist/storage/wasRemoteStore.d.ts +73 -0
  156. package/dist/storage/wasRemoteStore.d.ts.map +1 -0
  157. package/dist/storage/wasRemoteStore.js +76 -0
  158. package/dist/storage/wasRemoteStore.js.map +1 -0
  159. package/dist/storage/wasSync.d.ts +42 -0
  160. package/dist/storage/wasSync.d.ts.map +1 -0
  161. package/dist/storage/wasSync.js +34 -0
  162. package/dist/storage/wasSync.js.map +1 -0
  163. package/dist/sync/changesQuery.d.ts +44 -0
  164. package/dist/sync/changesQuery.d.ts.map +1 -0
  165. package/dist/sync/changesQuery.js +61 -0
  166. package/dist/sync/changesQuery.js.map +1 -0
  167. package/dist/sync/changesQuery.test.d.ts +2 -0
  168. package/dist/sync/changesQuery.test.d.ts.map +1 -0
  169. package/dist/sync/changesQuery.test.js +145 -0
  170. package/dist/sync/changesQuery.test.js.map +1 -0
  171. package/dist/sync/docCipher.d.ts +68 -0
  172. package/dist/sync/docCipher.d.ts.map +1 -0
  173. package/dist/sync/docCipher.js +89 -0
  174. package/dist/sync/docCipher.js.map +1 -0
  175. package/dist/sync/feedMasterPort.d.ts +30 -0
  176. package/dist/sync/feedMasterPort.d.ts.map +1 -0
  177. package/dist/sync/feedMasterPort.js +58 -0
  178. package/dist/sync/feedMasterPort.js.map +1 -0
  179. package/dist/sync/index.d.ts +21 -0
  180. package/dist/sync/index.d.ts.map +1 -0
  181. package/dist/sync/index.js +21 -0
  182. package/dist/sync/index.js.map +1 -0
  183. package/dist/sync/lww.d.ts +29 -0
  184. package/dist/sync/lww.d.ts.map +1 -0
  185. package/dist/sync/lww.js +28 -0
  186. package/dist/sync/lww.js.map +1 -0
  187. package/dist/sync/lww.test.d.ts +2 -0
  188. package/dist/sync/lww.test.d.ts.map +1 -0
  189. package/dist/sync/lww.test.js +28 -0
  190. package/dist/sync/lww.test.js.map +1 -0
  191. package/dist/sync/lwwConflictHandler.d.ts +49 -0
  192. package/dist/sync/lwwConflictHandler.d.ts.map +1 -0
  193. package/dist/sync/lwwConflictHandler.js +65 -0
  194. package/dist/sync/lwwConflictHandler.js.map +1 -0
  195. package/dist/sync/lwwConflictHandler.test.d.ts +2 -0
  196. package/dist/sync/lwwConflictHandler.test.d.ts.map +1 -0
  197. package/dist/sync/lwwConflictHandler.test.js +78 -0
  198. package/dist/sync/lwwConflictHandler.test.js.map +1 -0
  199. package/dist/sync/pushWrites.d.ts +57 -0
  200. package/dist/sync/pushWrites.d.ts.map +1 -0
  201. package/dist/sync/pushWrites.js +159 -0
  202. package/dist/sync/pushWrites.js.map +1 -0
  203. package/dist/sync/pushWrites.test.d.ts +2 -0
  204. package/dist/sync/pushWrites.test.d.ts.map +1 -0
  205. package/dist/sync/pushWrites.test.js +287 -0
  206. package/dist/sync/pushWrites.test.js.map +1 -0
  207. package/dist/sync/syncedDocSchema.d.ts +22 -0
  208. package/dist/sync/syncedDocSchema.d.ts.map +1 -0
  209. package/dist/sync/syncedDocSchema.js +26 -0
  210. package/dist/sync/syncedDocSchema.js.map +1 -0
  211. package/dist/sync/types.d.ts +194 -0
  212. package/dist/sync/types.d.ts.map +1 -0
  213. package/dist/sync/types.js +36 -0
  214. package/dist/sync/types.js.map +1 -0
  215. package/dist/sync/wasReplication.d.ts +47 -0
  216. package/dist/sync/wasReplication.d.ts.map +1 -0
  217. package/dist/sync/wasReplication.js +55 -0
  218. package/dist/sync/wasReplication.js.map +1 -0
  219. package/dist/sync/wasSyncPort.d.ts +45 -0
  220. package/dist/sync/wasSyncPort.d.ts.map +1 -0
  221. package/dist/sync/wasSyncPort.js +170 -0
  222. package/dist/sync/wasSyncPort.js.map +1 -0
  223. package/package.json +142 -0
@@ -0,0 +1,22 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The app-ready gate: a tiny shared zustand store the auth store flips once the
6
+ * session seed has opened the local store and hydrated every entity store. The
7
+ * router gate (`ProtectedRoute` / the `useAppReady` hook) waits on it before
8
+ * rendering the app.
9
+ *
10
+ * This is only the ready-flag store extracted from the app-side bootstrap; the
11
+ * dev-mode `initApp` open/hydrate driver stays app-side. In wallet mode the auth
12
+ * store owns the open/hydrate ordering and reuses this same gate.
13
+ */
14
+ import { create } from 'zustand';
15
+ export const useAppReady = create(set => ({
16
+ ready: false,
17
+ error: null,
18
+ setReady: () => set({ ready: true, error: null }),
19
+ setError: message => set({ error: message }),
20
+ reset: () => set({ ready: false, error: null })
21
+ }));
22
+ //# sourceMappingURL=appReadyStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appReadyStore.js","sourceRoot":"","sources":["../../src/session/appReadyStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAUhC,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAgB,GAAG,CAAC,EAAE,CAAC,CAAC;IACvD,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,IAAI;IACX,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACjD,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC5C,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;CAChD,CAAC,CAAC,CAAA"}
@@ -0,0 +1,71 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The wallet-mode auth store (zustand): owns the session lifecycle -- hot
6
+ * restore (zero popups), Login With Wallet, logout, and the expired-access
7
+ * reconnect -- plus the open/hydrate/sync ordering.
8
+ *
9
+ * On a successful login/restore it opens the encrypted {@link LocalStore} from
10
+ * the session seed (a per-controller database name, so two wallet users on one
11
+ * browser never collide), hydrates the entity stores, flips the shared
12
+ * `useAppReady` gate, and starts WAS replication from the granted zcaps.
13
+ *
14
+ * `status` is the router gate: `ProtectedRoute` waits for the restore attempt to
15
+ * settle before deciding between the app and the login page.
16
+ *
17
+ * The library cannot bind a module-level store to app config, so this is a
18
+ * FACTORY: {@link createAuthStore} captures the app's {@link WasAppConfig} and
19
+ * {@link StoreRegistry} once (the React provider calls it once) and returns a
20
+ * vanilla zustand store the hooks consume through context.
21
+ */
22
+ import { type StoreApi } from 'zustand/vanilla';
23
+ import type { RxStorage } from 'rxdb/plugins/core';
24
+ import { type StoreRegistry, type WasAppConfig } from '../config.js';
25
+ import { type SeedStore } from '../identity/seedStore.js';
26
+ import { type LoginPhase } from '../auth/loginFlow.js';
27
+ export type AuthStatus = 'idle' | 'restoring' | 'unauthenticated' | 'authenticating' | 'authenticated';
28
+ export interface AuthState {
29
+ status: AuthStatus;
30
+ /** The current login phase, for the login page's progress line. */
31
+ phase: LoginPhase | null;
32
+ error: string | null;
33
+ controllerDid: string | null;
34
+ /** ISO expiry of the current grant set (earliest zcap expiry). */
35
+ expires: string | null;
36
+ /** A live 401/403 was seen mid-session: show the reconnect banner. */
37
+ accessExpired: boolean;
38
+ reconnecting: boolean;
39
+ /** Hot restore from the persisted session; falls to `unauthenticated`. */
40
+ restore: () => Promise<void>;
41
+ /** Full Login With Wallet (first-run or returning). */
42
+ login: () => Promise<void>;
43
+ /** Re-run the grants flow with the existing seed (expired access). */
44
+ reconnect: () => Promise<void>;
45
+ logout: () => Promise<void>;
46
+ notifyAccessExpired: () => void;
47
+ }
48
+ /** The vanilla zustand store returned by {@link createAuthStore}. */
49
+ export type WasAuthStore = StoreApi<AuthState>;
50
+ /**
51
+ * Builds the wallet-mode auth store bound to an app's config and store registry.
52
+ * Call once (the React provider does) and share the returned store through
53
+ * context; the hooks read it via `useStore`.
54
+ *
55
+ * @param options {object}
56
+ * @param options.config {WasAppConfig} the app-wide configuration
57
+ * @param options.registry {StoreRegistry} the per-collection hydrate/patch
58
+ * handlers the rehydrate mechanism drives
59
+ * @param [options.seedStore] {SeedStore} the session IndexedDB persistence
60
+ * (defaults to one bound to `<dbName>-session`; inject a fake for tests)
61
+ * @param [options.storage] {RxStorage} the RxDB storage for the local store
62
+ * (defaults to Dexie/IndexedDB; inject a fake for tests)
63
+ * @returns {WasAuthStore}
64
+ */
65
+ export declare function createAuthStore({ config, registry, seedStore, storage }: {
66
+ config: WasAppConfig;
67
+ registry: StoreRegistry;
68
+ seedStore?: SeedStore;
69
+ storage?: RxStorage<unknown, unknown>;
70
+ }): WasAuthStore;
71
+ //# sourceMappingURL=authStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authStore.d.ts","sourceRoot":"","sources":["../../src/session/authStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAElD,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAA;AAIrB,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAO1E,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAA;AAsB7B,MAAM,MAAM,UAAU,GACpB,MAAM,GAAG,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,eAAe,CAAA;AAU/E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,UAAU,CAAA;IAClB,mEAAmE;IACnE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,kEAAkE;IAClE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,sEAAsE;IACtE,aAAa,EAAE,OAAO,CAAA;IACtB,YAAY,EAAE,OAAO,CAAA;IACrB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,uDAAuD;IACvD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,sEAAsE;IACtE,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,mBAAmB,EAAE,MAAM,IAAI,CAAA;CAChC;AAED,qEAAqE;AACrE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAA;AAE9C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,QAAQ,EACR,SAAS,EACT,OAAO,EACR,EAAE;IACD,MAAM,EAAE,YAAY,CAAA;IACpB,QAAQ,EAAE,aAAa,CAAA;IACvB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;CACtC,GAAG,YAAY,CAkUf"}
@@ -0,0 +1,347 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The wallet-mode auth store (zustand): owns the session lifecycle -- hot
6
+ * restore (zero popups), Login With Wallet, logout, and the expired-access
7
+ * reconnect -- plus the open/hydrate/sync ordering.
8
+ *
9
+ * On a successful login/restore it opens the encrypted {@link LocalStore} from
10
+ * the session seed (a per-controller database name, so two wallet users on one
11
+ * browser never collide), hydrates the entity stores, flips the shared
12
+ * `useAppReady` gate, and starts WAS replication from the granted zcaps.
13
+ *
14
+ * `status` is the router gate: `ProtectedRoute` waits for the restore attempt to
15
+ * settle before deciding between the app and the login page.
16
+ *
17
+ * The library cannot bind a module-level store to app config, so this is a
18
+ * FACTORY: {@link createAuthStore} captures the app's {@link WasAppConfig} and
19
+ * {@link StoreRegistry} once (the React provider calls it once) and returns a
20
+ * vanilla zustand store the hooks consume through context.
21
+ */
22
+ import { createStore } from 'zustand/vanilla';
23
+ import { DEFAULT_DB_NAME, DEFAULT_EXPIRY_WARNING_MS, DEFAULT_EXPIRY_WATCH_MS } from '../config.js';
24
+ import { createDocumentLoader } from '../identity/documentLoader.js';
25
+ import { initAppSession } from '../identity/initAppSession.js';
26
+ import { createSeedStore } from '../identity/seedStore.js';
27
+ import { clearAppSession, persistAppSession, restoreAppSession, isNearExpiry } from '../identity/appSession.js';
28
+ import { loginWithWallet, requestGrants, LoginCancelledError } from '../auth/loginFlow.js';
29
+ import { parseGrants } from '../grants.js';
30
+ import { LocalStore } from '../storage/localStore.js';
31
+ import { clearLocalStore, hasStore, requireStore, setLocalStore } from '../storage/storageManager.js';
32
+ import { clearAllEntityStores, hydrateAll, patchFromChange } from '../storage/rehydrate.js';
33
+ import { startWasSync } from '../storage/wasSync.js';
34
+ import { createSyncController } from '../storage/syncController.js';
35
+ import { useSyncStatusStore } from '../storage/syncStatusStore.js';
36
+ import { useAppReady } from './appReadyStore.js';
37
+ /**
38
+ * Builds the wallet-mode auth store bound to an app's config and store registry.
39
+ * Call once (the React provider does) and share the returned store through
40
+ * context; the hooks read it via `useStore`.
41
+ *
42
+ * @param options {object}
43
+ * @param options.config {WasAppConfig} the app-wide configuration
44
+ * @param options.registry {StoreRegistry} the per-collection hydrate/patch
45
+ * handlers the rehydrate mechanism drives
46
+ * @param [options.seedStore] {SeedStore} the session IndexedDB persistence
47
+ * (defaults to one bound to `<dbName>-session`; inject a fake for tests)
48
+ * @param [options.storage] {RxStorage} the RxDB storage for the local store
49
+ * (defaults to Dexie/IndexedDB; inject a fake for tests)
50
+ * @returns {WasAuthStore}
51
+ */
52
+ export function createAuthStore({ config, registry, seedStore, storage }) {
53
+ const dbName = config.dbName ?? DEFAULT_DB_NAME;
54
+ const sessionStore = seedStore ?? createSeedStore({ dbName: `${dbName}-session` });
55
+ const documentLoader = createDocumentLoader(config.wasServerUrl !== undefined
56
+ ? { wasServerUrl: config.wasServerUrl }
57
+ : {});
58
+ // The login flow consumes only the WAS collection ids; this config layer owns
59
+ // the `{ key, id }` registry.
60
+ const loginConfig = {
61
+ appOrigin: config.appOrigin,
62
+ appName: config.appName,
63
+ collections: config.collections.map(collection => collection.id),
64
+ credential: config.credential,
65
+ documentLoader,
66
+ ...(config.wasServerUrl !== undefined && {
67
+ wasServerUrl: config.wasServerUrl
68
+ }),
69
+ ...(config.mediatorBase !== undefined && {
70
+ mediatorBase: config.mediatorBase
71
+ })
72
+ };
73
+ /**
74
+ * How close to grant expiry the reconnect banner is raised proactively (so the
75
+ * user re-grants before a live request fails). Wallet grants default to a long
76
+ * TTL, so a short lead time never fires spuriously mid-session.
77
+ */
78
+ const warningMs = config.expiry?.warningMs ?? DEFAULT_EXPIRY_WARNING_MS;
79
+ /** Poll interval for the near-expiry watch (grant expiry is coarse-grained). */
80
+ const watchMs = config.expiry?.watchMs ?? DEFAULT_EXPIRY_WATCH_MS;
81
+ let expiryTimer;
82
+ // The per-session controller: single-use, stopped on logout and replaced on a
83
+ // reconnect (started once per grant set).
84
+ let controller = null;
85
+ /** Stops the near-expiry watch (logout / re-grant). */
86
+ function disarmExpiryWatch() {
87
+ if (expiryTimer) {
88
+ clearInterval(expiryTimer);
89
+ expiryTimer = undefined;
90
+ }
91
+ }
92
+ /**
93
+ * Watches the session's earliest grant expiry and raises the reconnect banner
94
+ * once it is within `warningMs` (or already past). Checks immediately, then on
95
+ * a coarse interval; re-armed with the fresh expiry after a reconnect.
96
+ */
97
+ function armExpiryWatch(expires) {
98
+ disarmExpiryWatch();
99
+ const check = () => {
100
+ if (isNearExpiry(expires, warningMs)) {
101
+ store.getState().notifyAccessExpired();
102
+ }
103
+ };
104
+ check();
105
+ expiryTimer = setInterval(check, watchMs);
106
+ }
107
+ /** A stable, RxDB-safe database name per controller DID (FNV-1a hex). */
108
+ function dbNameForController(controllerDid) {
109
+ let hash = 0x811c9dc5;
110
+ for (let i = 0; i < controllerDid.length; i++) {
111
+ hash ^= controllerDid.charCodeAt(i);
112
+ hash = Math.imul(hash, 0x01000193) >>> 0;
113
+ }
114
+ return `${dbName}-${hash.toString(16).padStart(8, '0')}`;
115
+ }
116
+ /**
117
+ * Starts a fresh per-session controller replicating the granted collections,
118
+ * wiring reactive per-doc store patching and the auth-error (401/403) signal.
119
+ */
120
+ function beginSync({ parsed, zcapClient }) {
121
+ controller = createSyncController({
122
+ collections: config.collections,
123
+ ...(config.sync && { sync: config.sync })
124
+ });
125
+ return startWasSync({
126
+ parsed,
127
+ zcapClient,
128
+ localStore: requireStore(),
129
+ syncController: controller,
130
+ onRemoteChange: (key, event) => void patchFromChange(registry, key, event),
131
+ onAuthError: () => store.getState().notifyAccessExpired()
132
+ });
133
+ }
134
+ /**
135
+ * Opens storage + hydrates + starts sync for a validated session, persists it,
136
+ * and flips the ready gate. Shared by login and restore.
137
+ */
138
+ async function activateSession(session) {
139
+ if (!hasStore()) {
140
+ const local = await LocalStore.init({
141
+ seed: session.seed,
142
+ collections: config.collections,
143
+ dbName: dbNameForController(session.identity.controllerDid),
144
+ ...(storage && { storage })
145
+ });
146
+ setLocalStore(local);
147
+ }
148
+ await hydrateAll(registry);
149
+ useAppReady.getState().setReady();
150
+ await persistAppSession({
151
+ session: {
152
+ seed: session.seed,
153
+ controllerDid: session.identity.controllerDid,
154
+ serverUrl: session.parsed.serverUrl,
155
+ spaceId: session.parsed.spaceId,
156
+ grants: session.grants,
157
+ expires: session.expires
158
+ },
159
+ store: sessionStore
160
+ });
161
+ // Replication starts in the background; a down server never blocks entry.
162
+ void beginSync({
163
+ parsed: session.parsed,
164
+ zcapClient: session.identity.zcapClient
165
+ }).catch(err => console.warn('WAS sync failed to start:', err));
166
+ armExpiryWatch(session.expires);
167
+ }
168
+ /** Tears down storage + sync + entity stores (logout and re-login paths). */
169
+ async function deactivateSession() {
170
+ disarmExpiryWatch();
171
+ if (controller) {
172
+ await controller.stop();
173
+ controller = null;
174
+ }
175
+ if (hasStore()) {
176
+ try {
177
+ await requireStore().close();
178
+ }
179
+ catch (err) {
180
+ console.warn('Error closing the local store:', err);
181
+ }
182
+ clearLocalStore();
183
+ }
184
+ clearAllEntityStores(registry);
185
+ useSyncStatusStore.getState().reset();
186
+ useAppReady.getState().reset();
187
+ }
188
+ // Declared last so `prefer-const` is satisfied; the lifecycle closures above
189
+ // only dereference `store` at call time, by which point it is assigned.
190
+ const store = createStore()((set, get) => ({
191
+ status: 'idle',
192
+ phase: null,
193
+ error: null,
194
+ controllerDid: null,
195
+ expires: null,
196
+ accessExpired: false,
197
+ reconnecting: false,
198
+ restore: async () => {
199
+ if (get().status !== 'idle') {
200
+ return;
201
+ }
202
+ set({ status: 'restoring' });
203
+ try {
204
+ const restored = await restoreAppSession({ store: sessionStore });
205
+ if (!restored) {
206
+ set({ status: 'unauthenticated' });
207
+ return;
208
+ }
209
+ const identity = await initAppSession({ seed: restored.seed });
210
+ if (identity.controllerDid !== restored.controllerDid) {
211
+ // A corrupt record; treat as logged out.
212
+ await clearAppSession({ store: sessionStore });
213
+ set({ status: 'unauthenticated' });
214
+ return;
215
+ }
216
+ const parsed = parseGrants(restored.grants);
217
+ if (config.wasServerUrl !== undefined &&
218
+ parsed.serverUrl !== config.wasServerUrl) {
219
+ await clearAppSession({ store: sessionStore });
220
+ set({ status: 'unauthenticated' });
221
+ return;
222
+ }
223
+ await activateSession({
224
+ seed: restored.seed,
225
+ identity,
226
+ parsed,
227
+ grants: restored.grants,
228
+ expires: restored.expires
229
+ });
230
+ set({
231
+ status: 'authenticated',
232
+ controllerDid: identity.controllerDid,
233
+ expires: restored.expires,
234
+ error: null
235
+ });
236
+ }
237
+ catch (err) {
238
+ console.warn('Session restore failed:', err);
239
+ set({ status: 'unauthenticated' });
240
+ }
241
+ },
242
+ login: async () => {
243
+ const { status } = get();
244
+ if (status === 'authenticating' || status === 'authenticated') {
245
+ return;
246
+ }
247
+ set({ status: 'authenticating', error: null, phase: 'probing' });
248
+ try {
249
+ const outcome = await loginWithWallet({
250
+ config: loginConfig,
251
+ onPhase: phase => set({ phase })
252
+ });
253
+ await activateSession({
254
+ seed: outcome.seed,
255
+ identity: outcome.identity,
256
+ parsed: outcome.parsed,
257
+ grants: outcome.grants,
258
+ expires: outcome.expires
259
+ });
260
+ set({
261
+ status: 'authenticated',
262
+ controllerDid: outcome.identity.controllerDid,
263
+ expires: outcome.expires,
264
+ phase: null,
265
+ error: null,
266
+ accessExpired: false
267
+ });
268
+ }
269
+ catch (err) {
270
+ const message = err instanceof LoginCancelledError
271
+ ? err.message
272
+ : err instanceof Error
273
+ ? `Login failed: ${err.message}`
274
+ : 'Login failed.';
275
+ set({ status: 'unauthenticated', phase: null, error: message });
276
+ }
277
+ },
278
+ reconnect: async () => {
279
+ const { reconnecting, status } = get();
280
+ if (reconnecting || status !== 'authenticated') {
281
+ return;
282
+ }
283
+ set({ reconnecting: true, error: null });
284
+ try {
285
+ const restored = await restoreAppSession({ store: sessionStore });
286
+ // The seed survives grant expiry; only the grants need renewing. A
287
+ // missing seed means the session is unrecoverable in place.
288
+ const seed = restored?.seed;
289
+ if (!seed) {
290
+ await get().logout();
291
+ return;
292
+ }
293
+ const identity = await initAppSession({ seed });
294
+ const checked = await requestGrants({ identity, config: loginConfig });
295
+ if (controller) {
296
+ await controller.stop();
297
+ controller = null;
298
+ }
299
+ await persistAppSession({
300
+ session: {
301
+ seed,
302
+ controllerDid: identity.controllerDid,
303
+ serverUrl: checked.parsed.serverUrl,
304
+ spaceId: checked.parsed.spaceId,
305
+ grants: checked.grants,
306
+ expires: checked.expires
307
+ },
308
+ store: sessionStore
309
+ });
310
+ void beginSync({
311
+ parsed: checked.parsed,
312
+ zcapClient: identity.zcapClient
313
+ }).catch(err => console.warn('WAS sync failed to restart:', err));
314
+ armExpiryWatch(checked.expires);
315
+ set({
316
+ accessExpired: false,
317
+ expires: checked.expires,
318
+ reconnecting: false
319
+ });
320
+ }
321
+ catch (err) {
322
+ const message = err instanceof Error ? err.message : 'Reconnect failed.';
323
+ set({ reconnecting: false, error: message });
324
+ }
325
+ },
326
+ logout: async () => {
327
+ await deactivateSession();
328
+ await clearAppSession({ store: sessionStore });
329
+ set({
330
+ status: 'unauthenticated',
331
+ phase: null,
332
+ error: null,
333
+ controllerDid: null,
334
+ expires: null,
335
+ accessExpired: false,
336
+ reconnecting: false
337
+ });
338
+ },
339
+ notifyAccessExpired: () => {
340
+ if (!get().accessExpired) {
341
+ set({ accessExpired: true });
342
+ }
343
+ }
344
+ }));
345
+ return store;
346
+ }
347
+ //# sourceMappingURL=authStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authStore.js","sourceRoot":"","sources":["../../src/session/authStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The session lifecycle layer: the wallet-mode auth store factory and the shared
6
+ * app-ready gate.
7
+ */
8
+ export { createAuthStore, type AuthStatus, type AuthState, type WasAuthStore } from './authStore.js';
9
+ export { useAppReady } from './appReadyStore.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;GAGG;AACH,OAAO,EACL,eAAe,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,10 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The session lifecycle layer: the wallet-mode auth store factory and the shared
6
+ * app-ready gate.
7
+ */
8
+ export { createAuthStore } from './authStore.js';
9
+ export { useAppReady } from './appReadyStore.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;GAGG;AACH,OAAO,EACL,eAAe,EAIhB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,51 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * A generic zustand store over one localStore collection. Holds the decrypted
6
+ * payloads as a `Map<uuid, Doc>` and exposes the CRUD verbs that (1) persist
7
+ * through the encrypted {@link LocalStore} and (2) patch the in-memory Map. UI
8
+ * reads through selectors and applies the app's own comparators/filters; this
9
+ * layer stays domain-agnostic so every entity shares it.
10
+ *
11
+ * Reactivity note: local writes patch the Map optimistically after the localStore
12
+ * write resolves. Pulled remote changes are applied per-doc by the sync layer
13
+ * through `patch` / `drop` (no whole-collection re-hydrate), keeping multi-device
14
+ * edits and tombstones live without re-hydrate storms.
15
+ */
16
+ import { type UseBoundStore, type StoreApi } from 'zustand';
17
+ export interface EntityStore<T extends {
18
+ id: string;
19
+ }> {
20
+ /** Decrypted payloads keyed by logical uuid. */
21
+ byId: Map<string, T>;
22
+ hydrated: boolean;
23
+ /** Decrypt every live row of the collection into the Map. */
24
+ hydrate: () => Promise<void>;
25
+ /** Encrypt+insert a new doc, then add it to the Map. */
26
+ insert: (doc: T) => Promise<void>;
27
+ /** Re-encrypt a doc in place (sequence+1), then replace it in the Map. */
28
+ update: (doc: T) => Promise<void>;
29
+ /** Tombstone a doc, then drop it from the Map. */
30
+ remove: (uuid: string) => Promise<void>;
31
+ /** Replace the whole Map (used by hydrate and, later, the sync stream). */
32
+ replaceAll: (docs: T[]) => void;
33
+ /**
34
+ * Upsert one already-decrypted doc into the Map WITHOUT persisting (the sync
35
+ * stream owns the persisted row already). Used for per-doc reactive patching
36
+ * of pulled/conflict-resolved remote changes.
37
+ */
38
+ patch: (doc: T) => void;
39
+ /** Drop one doc from the Map WITHOUT persisting (remote tombstone patch). */
40
+ drop: (uuid: string) => void;
41
+ }
42
+ /**
43
+ * Builds a zustand hook for the collection whose localStore key is `collectionKey`.
44
+ *
45
+ * @param collectionKey {string}
46
+ * @returns {UseBoundStore<StoreApi<EntityStore<T>>>}
47
+ */
48
+ export declare function createEntityStore<T extends {
49
+ id: string;
50
+ }>(collectionKey: string): UseBoundStore<StoreApi<EntityStore<T>>>;
51
+ //# sourceMappingURL=entityStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityStore.d.ts","sourceRoot":"","sources":["../../src/storage/entityStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;GAWG;AACH,OAAO,EAAU,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AAGnE,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;IACnD,gDAAgD;IAChD,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,wDAAwD;IACxD,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,kDAAkD;IAClD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,2EAA2E;IAC3E,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;IAC/B;;;;OAIG;IACH,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAA;IACvB,6EAA6E;IAC7E,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACxD,aAAa,EAAE,MAAM,GACpB,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAqDzC"}
@@ -0,0 +1,78 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * A generic zustand store over one localStore collection. Holds the decrypted
6
+ * payloads as a `Map<uuid, Doc>` and exposes the CRUD verbs that (1) persist
7
+ * through the encrypted {@link LocalStore} and (2) patch the in-memory Map. UI
8
+ * reads through selectors and applies the app's own comparators/filters; this
9
+ * layer stays domain-agnostic so every entity shares it.
10
+ *
11
+ * Reactivity note: local writes patch the Map optimistically after the localStore
12
+ * write resolves. Pulled remote changes are applied per-doc by the sync layer
13
+ * through `patch` / `drop` (no whole-collection re-hydrate), keeping multi-device
14
+ * edits and tombstones live without re-hydrate storms.
15
+ */
16
+ import { create } from 'zustand';
17
+ import { requireStore } from './storageManager.js';
18
+ /**
19
+ * Builds a zustand hook for the collection whose localStore key is `collectionKey`.
20
+ *
21
+ * @param collectionKey {string}
22
+ * @returns {UseBoundStore<StoreApi<EntityStore<T>>>}
23
+ */
24
+ export function createEntityStore(collectionKey) {
25
+ return create(set => ({
26
+ byId: new Map(),
27
+ hydrated: false,
28
+ hydrate: async () => {
29
+ const docs = await requireStore().listEntities(collectionKey);
30
+ set({ byId: new Map(docs.map(d => [d.id, d])), hydrated: true });
31
+ },
32
+ insert: async (doc) => {
33
+ await requireStore().insertEntity(collectionKey, doc);
34
+ set(state => {
35
+ const byId = new Map(state.byId);
36
+ byId.set(doc.id, doc);
37
+ return { byId };
38
+ });
39
+ },
40
+ update: async (doc) => {
41
+ await requireStore().updateEntity(collectionKey, doc);
42
+ set(state => {
43
+ const byId = new Map(state.byId);
44
+ byId.set(doc.id, doc);
45
+ return { byId };
46
+ });
47
+ },
48
+ remove: async (uuid) => {
49
+ await requireStore().deleteEntity(collectionKey, uuid);
50
+ set(state => {
51
+ const byId = new Map(state.byId);
52
+ byId.delete(uuid);
53
+ return { byId };
54
+ });
55
+ },
56
+ replaceAll: docs => {
57
+ set({ byId: new Map(docs.map(d => [d.id, d])), hydrated: true });
58
+ },
59
+ patch: doc => {
60
+ set(state => {
61
+ const byId = new Map(state.byId);
62
+ byId.set(doc.id, doc);
63
+ return { byId };
64
+ });
65
+ },
66
+ drop: uuid => {
67
+ set(state => {
68
+ if (!state.byId.has(uuid)) {
69
+ return state;
70
+ }
71
+ const byId = new Map(state.byId);
72
+ byId.delete(uuid);
73
+ return { byId };
74
+ });
75
+ }
76
+ }));
77
+ }
78
+ //# sourceMappingURL=entityStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityStore.js","sourceRoot":"","sources":["../../src/storage/entityStore.ts"],"names":[],"mappings":"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"}