stellar-drive 1.0.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 (246) hide show
  1. package/README.md +607 -0
  2. package/dist/actions/remoteChange.d.ts +204 -0
  3. package/dist/actions/remoteChange.d.ts.map +1 -0
  4. package/dist/actions/remoteChange.js +424 -0
  5. package/dist/actions/remoteChange.js.map +1 -0
  6. package/dist/actions/truncateTooltip.d.ts +56 -0
  7. package/dist/actions/truncateTooltip.d.ts.map +1 -0
  8. package/dist/actions/truncateTooltip.js +312 -0
  9. package/dist/actions/truncateTooltip.js.map +1 -0
  10. package/dist/auth/crypto.d.ts +41 -0
  11. package/dist/auth/crypto.d.ts.map +1 -0
  12. package/dist/auth/crypto.js +50 -0
  13. package/dist/auth/crypto.js.map +1 -0
  14. package/dist/auth/deviceVerification.d.ts +283 -0
  15. package/dist/auth/deviceVerification.d.ts.map +1 -0
  16. package/dist/auth/deviceVerification.js +575 -0
  17. package/dist/auth/deviceVerification.js.map +1 -0
  18. package/dist/auth/displayUtils.d.ts +98 -0
  19. package/dist/auth/displayUtils.d.ts.map +1 -0
  20. package/dist/auth/displayUtils.js +145 -0
  21. package/dist/auth/displayUtils.js.map +1 -0
  22. package/dist/auth/loginGuard.d.ts +134 -0
  23. package/dist/auth/loginGuard.d.ts.map +1 -0
  24. package/dist/auth/loginGuard.js +276 -0
  25. package/dist/auth/loginGuard.js.map +1 -0
  26. package/dist/auth/offlineCredentials.d.ts +105 -0
  27. package/dist/auth/offlineCredentials.d.ts.map +1 -0
  28. package/dist/auth/offlineCredentials.js +176 -0
  29. package/dist/auth/offlineCredentials.js.map +1 -0
  30. package/dist/auth/offlineSession.d.ts +96 -0
  31. package/dist/auth/offlineSession.d.ts.map +1 -0
  32. package/dist/auth/offlineSession.js +145 -0
  33. package/dist/auth/offlineSession.js.map +1 -0
  34. package/dist/auth/resolveAuthState.d.ts +85 -0
  35. package/dist/auth/resolveAuthState.d.ts.map +1 -0
  36. package/dist/auth/resolveAuthState.js +249 -0
  37. package/dist/auth/resolveAuthState.js.map +1 -0
  38. package/dist/auth/singleUser.d.ts +498 -0
  39. package/dist/auth/singleUser.d.ts.map +1 -0
  40. package/dist/auth/singleUser.js +1282 -0
  41. package/dist/auth/singleUser.js.map +1 -0
  42. package/dist/bin/commands.d.ts +14 -0
  43. package/dist/bin/commands.d.ts.map +1 -0
  44. package/dist/bin/commands.js +68 -0
  45. package/dist/bin/commands.js.map +1 -0
  46. package/dist/bin/install-pwa.d.ts +41 -0
  47. package/dist/bin/install-pwa.d.ts.map +1 -0
  48. package/dist/bin/install-pwa.js +4594 -0
  49. package/dist/bin/install-pwa.js.map +1 -0
  50. package/dist/config.d.ts +249 -0
  51. package/dist/config.d.ts.map +1 -0
  52. package/dist/config.js +395 -0
  53. package/dist/config.js.map +1 -0
  54. package/dist/conflicts.d.ts +306 -0
  55. package/dist/conflicts.d.ts.map +1 -0
  56. package/dist/conflicts.js +807 -0
  57. package/dist/conflicts.js.map +1 -0
  58. package/dist/crdt/awareness.d.ts +128 -0
  59. package/dist/crdt/awareness.d.ts.map +1 -0
  60. package/dist/crdt/awareness.js +284 -0
  61. package/dist/crdt/awareness.js.map +1 -0
  62. package/dist/crdt/channel.d.ts +165 -0
  63. package/dist/crdt/channel.d.ts.map +1 -0
  64. package/dist/crdt/channel.js +522 -0
  65. package/dist/crdt/channel.js.map +1 -0
  66. package/dist/crdt/config.d.ts +58 -0
  67. package/dist/crdt/config.d.ts.map +1 -0
  68. package/dist/crdt/config.js +123 -0
  69. package/dist/crdt/config.js.map +1 -0
  70. package/dist/crdt/helpers.d.ts +104 -0
  71. package/dist/crdt/helpers.d.ts.map +1 -0
  72. package/dist/crdt/helpers.js +116 -0
  73. package/dist/crdt/helpers.js.map +1 -0
  74. package/dist/crdt/offline.d.ts +58 -0
  75. package/dist/crdt/offline.d.ts.map +1 -0
  76. package/dist/crdt/offline.js +130 -0
  77. package/dist/crdt/offline.js.map +1 -0
  78. package/dist/crdt/persistence.d.ts +65 -0
  79. package/dist/crdt/persistence.d.ts.map +1 -0
  80. package/dist/crdt/persistence.js +171 -0
  81. package/dist/crdt/persistence.js.map +1 -0
  82. package/dist/crdt/provider.d.ts +109 -0
  83. package/dist/crdt/provider.d.ts.map +1 -0
  84. package/dist/crdt/provider.js +543 -0
  85. package/dist/crdt/provider.js.map +1 -0
  86. package/dist/crdt/store.d.ts +111 -0
  87. package/dist/crdt/store.d.ts.map +1 -0
  88. package/dist/crdt/store.js +158 -0
  89. package/dist/crdt/store.js.map +1 -0
  90. package/dist/crdt/types.d.ts +281 -0
  91. package/dist/crdt/types.d.ts.map +1 -0
  92. package/dist/crdt/types.js +26 -0
  93. package/dist/crdt/types.js.map +1 -0
  94. package/dist/data.d.ts +502 -0
  95. package/dist/data.d.ts.map +1 -0
  96. package/dist/data.js +862 -0
  97. package/dist/data.js.map +1 -0
  98. package/dist/database.d.ts +153 -0
  99. package/dist/database.d.ts.map +1 -0
  100. package/dist/database.js +325 -0
  101. package/dist/database.js.map +1 -0
  102. package/dist/debug.d.ts +87 -0
  103. package/dist/debug.d.ts.map +1 -0
  104. package/dist/debug.js +135 -0
  105. package/dist/debug.js.map +1 -0
  106. package/dist/demo.d.ts +131 -0
  107. package/dist/demo.d.ts.map +1 -0
  108. package/dist/demo.js +168 -0
  109. package/dist/demo.js.map +1 -0
  110. package/dist/deviceId.d.ts +47 -0
  111. package/dist/deviceId.d.ts.map +1 -0
  112. package/dist/deviceId.js +106 -0
  113. package/dist/deviceId.js.map +1 -0
  114. package/dist/diagnostics.d.ts +292 -0
  115. package/dist/diagnostics.d.ts.map +1 -0
  116. package/dist/diagnostics.js +378 -0
  117. package/dist/diagnostics.js.map +1 -0
  118. package/dist/engine.d.ts +230 -0
  119. package/dist/engine.d.ts.map +1 -0
  120. package/dist/engine.js +2636 -0
  121. package/dist/engine.js.map +1 -0
  122. package/dist/entries/actions.d.ts +16 -0
  123. package/dist/entries/actions.d.ts.map +1 -0
  124. package/dist/entries/actions.js +29 -0
  125. package/dist/entries/actions.js.map +1 -0
  126. package/dist/entries/auth.d.ts +19 -0
  127. package/dist/entries/auth.d.ts.map +1 -0
  128. package/dist/entries/auth.js +50 -0
  129. package/dist/entries/auth.js.map +1 -0
  130. package/dist/entries/config.d.ts +15 -0
  131. package/dist/entries/config.d.ts.map +1 -0
  132. package/dist/entries/config.js +20 -0
  133. package/dist/entries/config.js.map +1 -0
  134. package/dist/entries/crdt.d.ts +32 -0
  135. package/dist/entries/crdt.d.ts.map +1 -0
  136. package/dist/entries/crdt.js +52 -0
  137. package/dist/entries/crdt.js.map +1 -0
  138. package/dist/entries/kit.d.ts +22 -0
  139. package/dist/entries/kit.d.ts.map +1 -0
  140. package/dist/entries/kit.js +58 -0
  141. package/dist/entries/kit.js.map +1 -0
  142. package/dist/entries/stores.d.ts +22 -0
  143. package/dist/entries/stores.d.ts.map +1 -0
  144. package/dist/entries/stores.js +57 -0
  145. package/dist/entries/stores.js.map +1 -0
  146. package/dist/entries/types.d.ts +23 -0
  147. package/dist/entries/types.d.ts.map +1 -0
  148. package/dist/entries/types.js +12 -0
  149. package/dist/entries/types.js.map +1 -0
  150. package/dist/entries/utils.d.ts +12 -0
  151. package/dist/entries/utils.d.ts.map +1 -0
  152. package/dist/entries/utils.js +42 -0
  153. package/dist/entries/utils.js.map +1 -0
  154. package/dist/entries/vite.d.ts +20 -0
  155. package/dist/entries/vite.d.ts.map +1 -0
  156. package/dist/entries/vite.js +26 -0
  157. package/dist/entries/vite.js.map +1 -0
  158. package/dist/index.d.ts +77 -0
  159. package/dist/index.d.ts.map +1 -0
  160. package/dist/index.js +234 -0
  161. package/dist/index.js.map +1 -0
  162. package/dist/kit/auth.d.ts +80 -0
  163. package/dist/kit/auth.d.ts.map +1 -0
  164. package/dist/kit/auth.js +75 -0
  165. package/dist/kit/auth.js.map +1 -0
  166. package/dist/kit/confirm.d.ts +111 -0
  167. package/dist/kit/confirm.d.ts.map +1 -0
  168. package/dist/kit/confirm.js +169 -0
  169. package/dist/kit/confirm.js.map +1 -0
  170. package/dist/kit/loads.d.ts +187 -0
  171. package/dist/kit/loads.d.ts.map +1 -0
  172. package/dist/kit/loads.js +208 -0
  173. package/dist/kit/loads.js.map +1 -0
  174. package/dist/kit/server.d.ts +175 -0
  175. package/dist/kit/server.d.ts.map +1 -0
  176. package/dist/kit/server.js +297 -0
  177. package/dist/kit/server.js.map +1 -0
  178. package/dist/kit/sw.d.ts +176 -0
  179. package/dist/kit/sw.d.ts.map +1 -0
  180. package/dist/kit/sw.js +320 -0
  181. package/dist/kit/sw.js.map +1 -0
  182. package/dist/queue.d.ts +306 -0
  183. package/dist/queue.d.ts.map +1 -0
  184. package/dist/queue.js +925 -0
  185. package/dist/queue.js.map +1 -0
  186. package/dist/realtime.d.ts +280 -0
  187. package/dist/realtime.d.ts.map +1 -0
  188. package/dist/realtime.js +1031 -0
  189. package/dist/realtime.js.map +1 -0
  190. package/dist/runtime/runtimeConfig.d.ts +110 -0
  191. package/dist/runtime/runtimeConfig.d.ts.map +1 -0
  192. package/dist/runtime/runtimeConfig.js +260 -0
  193. package/dist/runtime/runtimeConfig.js.map +1 -0
  194. package/dist/schema.d.ts +150 -0
  195. package/dist/schema.d.ts.map +1 -0
  196. package/dist/schema.js +891 -0
  197. package/dist/schema.js.map +1 -0
  198. package/dist/stores/authState.d.ts +204 -0
  199. package/dist/stores/authState.d.ts.map +1 -0
  200. package/dist/stores/authState.js +336 -0
  201. package/dist/stores/authState.js.map +1 -0
  202. package/dist/stores/factories.d.ts +140 -0
  203. package/dist/stores/factories.d.ts.map +1 -0
  204. package/dist/stores/factories.js +157 -0
  205. package/dist/stores/factories.js.map +1 -0
  206. package/dist/stores/network.d.ts +48 -0
  207. package/dist/stores/network.d.ts.map +1 -0
  208. package/dist/stores/network.js +261 -0
  209. package/dist/stores/network.js.map +1 -0
  210. package/dist/stores/remoteChanges.d.ts +417 -0
  211. package/dist/stores/remoteChanges.d.ts.map +1 -0
  212. package/dist/stores/remoteChanges.js +626 -0
  213. package/dist/stores/remoteChanges.js.map +1 -0
  214. package/dist/stores/sync.d.ts +165 -0
  215. package/dist/stores/sync.d.ts.map +1 -0
  216. package/dist/stores/sync.js +275 -0
  217. package/dist/stores/sync.js.map +1 -0
  218. package/dist/supabase/auth.d.ts +219 -0
  219. package/dist/supabase/auth.d.ts.map +1 -0
  220. package/dist/supabase/auth.js +459 -0
  221. package/dist/supabase/auth.js.map +1 -0
  222. package/dist/supabase/client.d.ts +88 -0
  223. package/dist/supabase/client.d.ts.map +1 -0
  224. package/dist/supabase/client.js +313 -0
  225. package/dist/supabase/client.js.map +1 -0
  226. package/dist/supabase/validate.d.ts +118 -0
  227. package/dist/supabase/validate.d.ts.map +1 -0
  228. package/dist/supabase/validate.js +208 -0
  229. package/dist/supabase/validate.js.map +1 -0
  230. package/dist/sw/build/vite-plugin.d.ts +149 -0
  231. package/dist/sw/build/vite-plugin.d.ts.map +1 -0
  232. package/dist/sw/build/vite-plugin.js +517 -0
  233. package/dist/sw/build/vite-plugin.js.map +1 -0
  234. package/dist/sw/sw.js +664 -0
  235. package/dist/types.d.ts +363 -0
  236. package/dist/types.d.ts.map +1 -0
  237. package/dist/types.js +18 -0
  238. package/dist/types.js.map +1 -0
  239. package/dist/utils.d.ts +85 -0
  240. package/dist/utils.d.ts.map +1 -0
  241. package/dist/utils.js +156 -0
  242. package/dist/utils.js.map +1 -0
  243. package/package.json +117 -0
  244. package/src/components/DeferredChangesBanner.svelte +477 -0
  245. package/src/components/DemoBanner.svelte +110 -0
  246. package/src/components/SyncStatus.svelte +1732 -0
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @fileoverview Auth hydration helper for the root layout component.
3
+ *
4
+ * This module bridges the gap between SvelteKit's server-side load data and
5
+ * the client-side reactive auth store (`authState`). When the root layout
6
+ * receives auth-related data from a load function, this helper inspects the
7
+ * `authMode` discriminator and calls the corresponding `authState.set*()`
8
+ * setter so that every downstream component gets reactive access to the
9
+ * current authentication state without needing to know the hydration details.
10
+ *
11
+ * @module kit/auth
12
+ *
13
+ * @example
14
+ * ```svelte
15
+ * <!-- +layout.svelte -->
16
+ * <script lang="ts">
17
+ * import { hydrateAuthState } from 'stellar-drive/kit/auth';
18
+ * let { data } = $props();
19
+ * $effect(() => { hydrateAuthState(data); });
20
+ * </script>
21
+ * ```
22
+ *
23
+ * @see {@link authState} for the reactive store being hydrated
24
+ * @see {@link resolveAuthState} in `auth/resolveAuthState.ts` for how auth
25
+ * state is determined on the server/load side
26
+ */
27
+ import { authState } from '../stores/authState.js';
28
+ // =============================================================================
29
+ // PUBLIC API
30
+ // =============================================================================
31
+ /**
32
+ * Reads layout load data (`{ authMode, session, offlineProfile }`) and calls
33
+ * the appropriate `authState.set*()` method to hydrate the client-side
34
+ * reactive auth store.
35
+ *
36
+ * The function acts as a switchboard: it inspects `authMode` and delegates to
37
+ * the matching setter on the `authState` store. This keeps the root layout
38
+ * component free of branching logic and ensures a single source of truth for
39
+ * how layout data maps to reactive state.
40
+ *
41
+ * Call this from a Svelte 5 `$effect()` in your root `+layout.svelte` so it
42
+ * re-runs whenever the layout data changes (e.g. after a login or logout):
43
+ *
44
+ * @param layoutData - The auth-related subset of root layout load data.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * // In +layout.svelte
49
+ * $effect(() => { hydrateAuthState(data); });
50
+ * ```
51
+ *
52
+ * @see {@link AuthLayoutData} for the expected shape of `layoutData`
53
+ * @see {@link authState} for the store methods being invoked
54
+ */
55
+ export function hydrateAuthState(layoutData) {
56
+ /* Supabase mode requires both the mode flag AND a valid session object;
57
+ if the session is null the user has been logged out server-side. */
58
+ if (layoutData.authMode === 'demo') {
59
+ authState.setDemoAuth();
60
+ }
61
+ else if (layoutData.authMode === 'supabase' && layoutData.session) {
62
+ authState.setSupabaseAuth(layoutData.session);
63
+ }
64
+ else if (layoutData.authMode === 'offline' && layoutData.offlineProfile) {
65
+ /* Offline mode requires a locally-stored profile to be present;
66
+ without it we fall through to the unauthenticated state. */
67
+ authState.setOfflineAuth(layoutData.offlineProfile);
68
+ }
69
+ else {
70
+ /* Catch-all: covers 'none' mode as well as edge cases where the mode
71
+ flag is set but the corresponding payload is missing. */
72
+ authState.setNoAuth();
73
+ }
74
+ }
75
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/kit/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAqCnD,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAA0B;IACzD;0EACsE;IACtE,IAAI,UAAU,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACnC,SAAS,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC;SAAM,IAAI,UAAU,CAAC,QAAQ,KAAK,UAAU,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACpE,SAAS,CAAC,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;SAAM,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,cAAc,EAAE,CAAC;QAC1E;sEAC8D;QAC9D,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACN;mEAC2D;QAC3D,SAAS,CAAC,SAAS,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @fileoverview Email confirmation helpers for the `/confirm` route.
3
+ *
4
+ * This module extracts the OTP verification, device trust, error translation,
5
+ * and cross-tab broadcast logic so that the scaffolded confirmation page can
6
+ * focus purely on UI rendering. It handles the full lifecycle of an email
7
+ * confirmation link click:
8
+ *
9
+ * 1. Verify the OTP token hash with Supabase
10
+ * 2. Trust the originating device (for device-verification flows)
11
+ * 3. Translate raw Supabase errors into user-friendly messages
12
+ * 4. Broadcast the confirmation to other open tabs via BroadcastChannel
13
+ * 5. Attempt to auto-close the confirmation tab
14
+ *
15
+ * @module kit/confirm
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * // In /confirm/+page.svelte onMount
20
+ * const result = await handleEmailConfirmation(tokenHash, type);
21
+ * if (result.success) {
22
+ * await broadcastAuthConfirmed('auth-channel', type);
23
+ * }
24
+ * ```
25
+ *
26
+ * @see {@link verifyOtp} in `supabase/auth.ts` for the underlying OTP call
27
+ * @see {@link trustPendingDevice} in `auth/deviceVerification.ts` for device trust logic
28
+ */
29
+ /**
30
+ * Result of an email confirmation attempt.
31
+ *
32
+ * Provides a simple success/failure discriminator with an optional
33
+ * user-friendly error message when the confirmation fails.
34
+ */
35
+ export interface ConfirmResult {
36
+ /** Whether the OTP verification completed successfully. */
37
+ success: boolean;
38
+ /**
39
+ * A user-facing error message explaining why confirmation failed.
40
+ * Only present when `success` is `false`.
41
+ */
42
+ error?: string;
43
+ }
44
+ /**
45
+ * Handles the full email confirmation flow: verifies the OTP token hash,
46
+ * optionally trusts the pending device, and translates Supabase error
47
+ * messages into user-friendly strings.
48
+ *
49
+ * The function normalizes the `type` parameter before passing it to Supabase
50
+ * (e.g. `'magiclink'` maps to `'email'` for OTP verification purposes) and
51
+ * applies a tiered error classification to produce contextual error messages.
52
+ *
53
+ * @param tokenHash - The `token_hash` extracted from the confirmation URL
54
+ * query parameters (provided by Supabase in the email link).
55
+ * @param type - The verification type from Supabase, indicating what kind
56
+ * of email action triggered the confirmation. One of:
57
+ * - `'signup'` — new account registration
58
+ * - `'email'` — email change or device verification
59
+ * - `'email_change'` — explicit email address change
60
+ * - `'magiclink'` — passwordless login link
61
+ *
62
+ * @returns A promise resolving to `{ success: true }` on successful
63
+ * verification, or `{ success: false, error: string }` on failure
64
+ * with a translated error message.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const result = await handleEmailConfirmation(tokenHash, 'signup');
69
+ * if (!result.success) {
70
+ * showError(result.error);
71
+ * }
72
+ * ```
73
+ *
74
+ * @see {@link ConfirmResult} for the return type shape
75
+ * @see {@link verifyOtp} for the underlying Supabase OTP verification
76
+ */
77
+ export declare function handleEmailConfirmation(tokenHash: string, type: 'signup' | 'email' | 'email_change' | 'magiclink'): Promise<ConfirmResult>;
78
+ /**
79
+ * Broadcasts an auth confirmation event via `BroadcastChannel` so other
80
+ * open tabs (e.g. the login page that initiated the email flow) can detect
81
+ * the completed authentication and update their UI accordingly.
82
+ *
83
+ * After broadcasting, the function waits briefly for the receiving tab to
84
+ * process the message, then attempts to auto-close this confirmation tab.
85
+ * If the browser blocks `window.close()` (common for tabs not opened via
86
+ * `window.open()`), the function returns `'can_close'` so the UI can show
87
+ * a "you may close this tab" message instead.
88
+ *
89
+ * @param channelName - The `BroadcastChannel` name. Must match the channel
90
+ * name used by the login page listener.
91
+ * @param type - The verification type to include in the broadcast
92
+ * message payload, so the receiver knows which flow
93
+ * completed.
94
+ *
95
+ * @returns A promise resolving to one of:
96
+ * - `'closed'` — tab was successfully closed (caller won't see this)
97
+ * - `'can_close'` — broadcast sent but tab could not auto-close
98
+ * - `'no_broadcast'` — BroadcastChannel API not available (SSR or old browser)
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * const status = await broadcastAuthConfirmed('stellar-auth', 'signup');
103
+ * if (status === 'can_close') {
104
+ * showMessage('You can close this tab.');
105
+ * }
106
+ * ```
107
+ *
108
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel}
109
+ */
110
+ export declare function broadcastAuthConfirmed(channelName: string, type: string): Promise<'closed' | 'can_close' | 'no_broadcast'>;
111
+ //# sourceMappingURL=confirm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.d.ts","sourceRoot":"","sources":["../../src/kit/confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AASH;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,cAAc,GAAG,WAAW,GACtD,OAAO,CAAC,aAAa,CAAC,CA4CxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,QAAQ,GAAG,WAAW,GAAG,cAAc,CAAC,CA+BlD"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @fileoverview Email confirmation helpers for the `/confirm` route.
3
+ *
4
+ * This module extracts the OTP verification, device trust, error translation,
5
+ * and cross-tab broadcast logic so that the scaffolded confirmation page can
6
+ * focus purely on UI rendering. It handles the full lifecycle of an email
7
+ * confirmation link click:
8
+ *
9
+ * 1. Verify the OTP token hash with Supabase
10
+ * 2. Trust the originating device (for device-verification flows)
11
+ * 3. Translate raw Supabase errors into user-friendly messages
12
+ * 4. Broadcast the confirmation to other open tabs via BroadcastChannel
13
+ * 5. Attempt to auto-close the confirmation tab
14
+ *
15
+ * @module kit/confirm
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * // In /confirm/+page.svelte onMount
20
+ * const result = await handleEmailConfirmation(tokenHash, type);
21
+ * if (result.success) {
22
+ * await broadcastAuthConfirmed('auth-channel', type);
23
+ * }
24
+ * ```
25
+ *
26
+ * @see {@link verifyOtp} in `supabase/auth.ts` for the underlying OTP call
27
+ * @see {@link trustPendingDevice} in `auth/deviceVerification.ts` for device trust logic
28
+ */
29
+ import { verifyOtp } from '../supabase/auth.js';
30
+ import { trustPendingDevice } from '../auth/deviceVerification.js';
31
+ // =============================================================================
32
+ // PUBLIC API
33
+ // =============================================================================
34
+ /**
35
+ * Handles the full email confirmation flow: verifies the OTP token hash,
36
+ * optionally trusts the pending device, and translates Supabase error
37
+ * messages into user-friendly strings.
38
+ *
39
+ * The function normalizes the `type` parameter before passing it to Supabase
40
+ * (e.g. `'magiclink'` maps to `'email'` for OTP verification purposes) and
41
+ * applies a tiered error classification to produce contextual error messages.
42
+ *
43
+ * @param tokenHash - The `token_hash` extracted from the confirmation URL
44
+ * query parameters (provided by Supabase in the email link).
45
+ * @param type - The verification type from Supabase, indicating what kind
46
+ * of email action triggered the confirmation. One of:
47
+ * - `'signup'` — new account registration
48
+ * - `'email'` — email change or device verification
49
+ * - `'email_change'` — explicit email address change
50
+ * - `'magiclink'` — passwordless login link
51
+ *
52
+ * @returns A promise resolving to `{ success: true }` on successful
53
+ * verification, or `{ success: false, error: string }` on failure
54
+ * with a translated error message.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const result = await handleEmailConfirmation(tokenHash, 'signup');
59
+ * if (!result.success) {
60
+ * showError(result.error);
61
+ * }
62
+ * ```
63
+ *
64
+ * @see {@link ConfirmResult} for the return type shape
65
+ * @see {@link verifyOtp} for the underlying Supabase OTP verification
66
+ */
67
+ export async function handleEmailConfirmation(tokenHash, type) {
68
+ try {
69
+ /* Supabase's verifyOtp does not accept 'magiclink' as a type;
70
+ it expects 'email' for both magic link and email verification flows. */
71
+ const otpType = type === 'magiclink' ? 'email' : type;
72
+ const { error } = await verifyOtp(tokenHash, otpType);
73
+ /* For device-verification OTPs (email or magiclink), trust the device
74
+ that initiated the confirmation so it won't be challenged again. */
75
+ if (!error && (type === 'email' || type === 'magiclink')) {
76
+ await trustPendingDevice();
77
+ }
78
+ if (error) {
79
+ /* Tiered error classification: check for common Supabase error patterns
80
+ and translate them to actionable user-facing messages rather than
81
+ exposing raw API error strings. */
82
+ const errorLower = error.toLowerCase();
83
+ if (errorLower.includes('already') ||
84
+ errorLower.includes('confirmed') ||
85
+ errorLower.includes('used')) {
86
+ return {
87
+ success: false,
88
+ error: 'This email has already been confirmed. You can sign in to your account.'
89
+ };
90
+ }
91
+ else if (errorLower.includes('expired') || errorLower.includes('invalid')) {
92
+ return {
93
+ success: false,
94
+ error: 'This confirmation link has expired. Please request a new one from the login page.'
95
+ };
96
+ }
97
+ /* Unrecognized error pattern — pass through the raw message as a
98
+ last resort; this should be rare in production. */
99
+ return { success: false, error };
100
+ }
101
+ return { success: true };
102
+ }
103
+ catch {
104
+ /* Catch network failures, unexpected exceptions, etc. The user sees
105
+ a generic message rather than a stack trace. */
106
+ return { success: false, error: 'An unexpected error occurred. Please try again.' };
107
+ }
108
+ }
109
+ /**
110
+ * Broadcasts an auth confirmation event via `BroadcastChannel` so other
111
+ * open tabs (e.g. the login page that initiated the email flow) can detect
112
+ * the completed authentication and update their UI accordingly.
113
+ *
114
+ * After broadcasting, the function waits briefly for the receiving tab to
115
+ * process the message, then attempts to auto-close this confirmation tab.
116
+ * If the browser blocks `window.close()` (common for tabs not opened via
117
+ * `window.open()`), the function returns `'can_close'` so the UI can show
118
+ * a "you may close this tab" message instead.
119
+ *
120
+ * @param channelName - The `BroadcastChannel` name. Must match the channel
121
+ * name used by the login page listener.
122
+ * @param type - The verification type to include in the broadcast
123
+ * message payload, so the receiver knows which flow
124
+ * completed.
125
+ *
126
+ * @returns A promise resolving to one of:
127
+ * - `'closed'` — tab was successfully closed (caller won't see this)
128
+ * - `'can_close'` — broadcast sent but tab could not auto-close
129
+ * - `'no_broadcast'` — BroadcastChannel API not available (SSR or old browser)
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * const status = await broadcastAuthConfirmed('stellar-auth', 'signup');
134
+ * if (status === 'can_close') {
135
+ * showMessage('You can close this tab.');
136
+ * }
137
+ * ```
138
+ *
139
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel}
140
+ */
141
+ export async function broadcastAuthConfirmed(channelName, type) {
142
+ /* Guard against SSR and browsers lacking BroadcastChannel support
143
+ (notably some older mobile browsers). */
144
+ if (typeof window === 'undefined' || !('BroadcastChannel' in window)) {
145
+ return 'no_broadcast';
146
+ }
147
+ const channel = new BroadcastChannel(channelName);
148
+ channel.postMessage({
149
+ type: 'AUTH_CONFIRMED',
150
+ verificationType: type
151
+ });
152
+ /* Give the original tab time to process the message before closing
153
+ the channel — 500ms is sufficient for the receiver's event loop
154
+ to fire the handler and update its state. */
155
+ await new Promise((resolve) => setTimeout(resolve, 500));
156
+ channel.close();
157
+ /* Attempt to close this confirmation tab — browsers generally only
158
+ allow window.close() for tabs opened programmatically via
159
+ window.open(), so this may silently fail. */
160
+ try {
161
+ window.close();
162
+ }
163
+ catch {
164
+ /* Browser policy may block window.close() — expected behavior */
165
+ }
166
+ /* If execution reaches here, the tab is still open (close was blocked) */
167
+ return 'can_close';
168
+ }
169
+ //# sourceMappingURL=confirm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/kit/confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAuBnE,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,SAAiB,EACjB,IAAuD;IAEvD,IAAI,CAAC;QACH;kFAC0E;QAC1E,MAAM,OAAO,GAAG,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QACtD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,OAA8C,CAAC,CAAC;QAE7F;8EACsE;QACtE,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;YACzD,MAAM,kBAAkB,EAAE,CAAC;QAC7B,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACV;;iDAEqC;YACrC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YACvC,IACE,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAC9B,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAChC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC3B,CAAC;gBACD,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,yEAAyE;iBACjF,CAAC;YACJ,CAAC;iBAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC5E,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,mFAAmF;iBAC3F,CAAC;YACJ,CAAC;YACD;iEACqD;YACrD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACnC,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP;0DACkD;QAClD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,iDAAiD,EAAE,CAAC;IACtF,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,WAAmB,EACnB,IAAY;IAEZ;+CAC2C;IAC3C,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,kBAAkB,IAAI,MAAM,CAAC,EAAE,CAAC;QACrE,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAElD,OAAO,CAAC,WAAW,CAAC;QAClB,IAAI,EAAE,gBAAgB;QACtB,gBAAgB,EAAE,IAAI;KACvB,CAAC,CAAC;IAEH;;mDAE+C;IAC/C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB;;mDAE+C;IAC/C,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;IAED,0EAA0E;IAC1E,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * @fileoverview SvelteKit load function helpers.
3
+ *
4
+ * This module extracts orchestration logic from layout and page load functions
5
+ * so that scaffolded routes can be thin wrappers around these helpers. Each
6
+ * exported function encapsulates a specific load concern:
7
+ *
8
+ * - `resolveRootLayout` — full app initialization sequence (config,
9
+ * auth, sync engine startup)
10
+ * - `resolveProtectedLayout` — auth guard for protected route groups
11
+ * - `resolveSetupAccess` — access control for the `/setup` wizard
12
+ *
13
+ * By centralizing this logic in the engine, consuming apps avoid duplicating
14
+ * the initialization ordering and redirect logic across their route tree.
15
+ *
16
+ * @module kit/loads
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // In +layout.ts (root)
21
+ * import { resolveRootLayout } from 'stellar-drive/kit/loads';
22
+ * export async function load({ url }) {
23
+ * return resolveRootLayout(url);
24
+ * }
25
+ * ```
26
+ *
27
+ * @see {@link initConfig} for runtime configuration bootstrap
28
+ * @see {@link resolveAuthState} for auth mode determination
29
+ * @see {@link startSyncEngine} for offline-first sync initialization
30
+ */
31
+ import type { AuthStateResult } from '../auth/resolveAuthState.js';
32
+ /**
33
+ * Data returned by `resolveRootLayout`.
34
+ *
35
+ * Extends the base auth state with an optional `singleUserSetUp` flag
36
+ * indicating whether the app has completed initial configuration.
37
+ */
38
+ export interface RootLayoutData extends AuthStateResult {
39
+ /**
40
+ * Indicates whether the single-user setup wizard has been completed.
41
+ * When `false` and no config exists, the app should redirect to `/setup`.
42
+ */
43
+ singleUserSetUp?: boolean;
44
+ }
45
+ /**
46
+ * Data returned by `resolveProtectedLayout`.
47
+ *
48
+ * A narrowed subset of auth state fields needed by protected route groups
49
+ * to render authenticated content.
50
+ */
51
+ export interface ProtectedLayoutData {
52
+ /** The Supabase session, or `null` if using offline/no auth. */
53
+ session: AuthStateResult['session'];
54
+ /** The active authentication mode discriminator. */
55
+ authMode: AuthStateResult['authMode'];
56
+ /** The offline profile credentials, if in offline mode. */
57
+ offlineProfile: AuthStateResult['offlineProfile'];
58
+ }
59
+ /**
60
+ * Data returned by `resolveSetupAccess`.
61
+ *
62
+ * Tells the setup page whether this is a first-time configuration
63
+ * (public access) or a reconfiguration (authenticated users only).
64
+ */
65
+ export interface SetupAccessData {
66
+ /**
67
+ * `true` when no configuration exists yet — the setup page should
68
+ * render the full first-time wizard without requiring authentication.
69
+ */
70
+ isFirstSetup: boolean;
71
+ }
72
+ /**
73
+ * Orchestrates the root layout load sequence, which is the critical
74
+ * initialization path that runs on every page load:
75
+ *
76
+ * 1. Calls the app's `initEngine` function (for database schema setup)
77
+ * 2. Runs `initConfig()` — loads runtime config from storage; if no
78
+ * config exists and the user is not already on `/setup`, returns a
79
+ * blank state so the layout can redirect to the setup wizard
80
+ * 3. Resolves auth state — determines whether the user is authenticated
81
+ * via Supabase, offline credentials, or not at all
82
+ * 4. Starts the sync engine if the user is authenticated, enabling
83
+ * offline-first data synchronization
84
+ *
85
+ * @param url - The current page URL object. Only `pathname` is
86
+ * inspected, to detect whether the user is already
87
+ * on the `/setup` page.
88
+ * @param _initEngineFn - (Optional) The app's `initEngine()` call, executed
89
+ * before config init. Typically already called at
90
+ * module scope in the browser; this parameter exists
91
+ * for explicit invocation in SSR contexts.
92
+ *
93
+ * @returns Layout data containing session, auth mode, offline profile,
94
+ * and setup status. The consuming layout uses these to hydrate
95
+ * the auth store and conditionally render the app shell.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * // +layout.ts
100
+ * export async function load({ url }) {
101
+ * return resolveRootLayout(url);
102
+ * }
103
+ * ```
104
+ *
105
+ * @see {@link RootLayoutData} for the return type shape
106
+ * @see {@link initConfig} for config bootstrapping details
107
+ * @see {@link resolveAuthState} for auth resolution logic
108
+ */
109
+ export declare function resolveRootLayout(url: {
110
+ pathname: string;
111
+ }, _initEngineFn?: () => void): Promise<RootLayoutData>;
112
+ /**
113
+ * Auth guard for protected routes. Resolves auth state and, if the user
114
+ * is unauthenticated, computes a redirect URL to the login page with a
115
+ * `redirect` query parameter so the user can be sent back after login.
116
+ *
117
+ * The caller is responsible for performing the actual redirect (typically
118
+ * via SvelteKit's `throw redirect(302, redirectUrl)`), since this helper
119
+ * is framework-agnostic in its return value.
120
+ *
121
+ * @param url - The current page URL object with `pathname` and `search`
122
+ * properties, used to construct the post-login return URL.
123
+ *
124
+ * @returns An object containing:
125
+ * - `data` — the auth state payload for the layout
126
+ * - `redirectUrl` — a login URL string if unauthenticated, or `null`
127
+ * if the user is authenticated and should proceed normally.
128
+ * When non-null, the caller should `throw redirect(302, redirectUrl)`.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * // /(protected)/+layout.ts
133
+ * import { redirect } from '@sveltejs/kit';
134
+ * import { resolveProtectedLayout } from 'stellar-drive/kit/loads';
135
+ *
136
+ * export async function load({ url }) {
137
+ * const { data, redirectUrl } = await resolveProtectedLayout(url);
138
+ * if (redirectUrl) throw redirect(302, redirectUrl);
139
+ * return data;
140
+ * }
141
+ * ```
142
+ *
143
+ * @see {@link ProtectedLayoutData} for the return data shape
144
+ * @see {@link resolveAuthState} for the underlying auth resolution
145
+ */
146
+ export declare function resolveProtectedLayout(url: {
147
+ pathname: string;
148
+ search: string;
149
+ }): Promise<{
150
+ data: ProtectedLayoutData;
151
+ redirectUrl: string | null;
152
+ }>;
153
+ /**
154
+ * Setup page guard implementing a two-tier access model:
155
+ *
156
+ * - **Unconfigured app** (first-time setup): public access, no auth required.
157
+ * Returns `{ isFirstSetup: true }`.
158
+ * - **Configured app** (reconfiguration): any authenticated user may access.
159
+ * Unauthenticated users are redirected to `/login`.
160
+ *
161
+ * @returns An object containing:
162
+ * - `data` — setup access info (`{ isFirstSetup }`)
163
+ * - `redirectUrl` — a redirect path if the user lacks access, or `null`
164
+ * if access is granted. When non-null, the caller should
165
+ * `throw redirect(302, redirectUrl)`.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * // /setup/+page.ts
170
+ * import { redirect } from '@sveltejs/kit';
171
+ * import { resolveSetupAccess } from 'stellar-drive/kit/loads';
172
+ *
173
+ * export async function load() {
174
+ * const { data, redirectUrl } = await resolveSetupAccess();
175
+ * if (redirectUrl) throw redirect(302, redirectUrl);
176
+ * return data;
177
+ * }
178
+ * ```
179
+ *
180
+ * @see {@link SetupAccessData} for the return data shape
181
+ * @see {@link getConfig} for checking whether config exists
182
+ */
183
+ export declare function resolveSetupAccess(): Promise<{
184
+ data: SetupAccessData;
185
+ redirectUrl: string | null;
186
+ }>;
187
+ //# sourceMappingURL=loads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loads.d.ts","sourceRoot":"","sources":["../../src/kit/loads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAMnE;;;;;GAKG;AACH,MAAM,WAAW,cAAe,SAAQ,eAAe;IACrD;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IAEpC,oDAAoD;IACpD,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IAEtC,2DAA2D;IAC3D,cAAc,EAAE,eAAe,CAAC,gBAAgB,CAAC,CAAC;CACnD;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,YAAY,EAAE,OAAO,CAAC;CACvB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EACzB,aAAa,CAAC,EAAE,MAAM,IAAI,GACzB,OAAO,CAAC,cAAc,CAAC,CAmCzB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAgBrE;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC;IAClD,IAAI,EAAE,eAAe,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC,CAqBD"}