@prabhask5/stellar-engine 1.1.7 → 1.1.8

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 (191) hide show
  1. package/README.md +4 -1
  2. package/dist/actions/remoteChange.d.ts +143 -18
  3. package/dist/actions/remoteChange.d.ts.map +1 -1
  4. package/dist/actions/remoteChange.js +182 -58
  5. package/dist/actions/remoteChange.js.map +1 -1
  6. package/dist/actions/truncateTooltip.d.ts +26 -12
  7. package/dist/actions/truncateTooltip.d.ts.map +1 -1
  8. package/dist/actions/truncateTooltip.js +89 -34
  9. package/dist/actions/truncateTooltip.js.map +1 -1
  10. package/dist/auth/admin.d.ts +40 -3
  11. package/dist/auth/admin.d.ts.map +1 -1
  12. package/dist/auth/admin.js +45 -5
  13. package/dist/auth/admin.js.map +1 -1
  14. package/dist/auth/crypto.d.ts +55 -5
  15. package/dist/auth/crypto.d.ts.map +1 -1
  16. package/dist/auth/crypto.js +58 -5
  17. package/dist/auth/crypto.js.map +1 -1
  18. package/dist/auth/deviceVerification.d.ts +236 -20
  19. package/dist/auth/deviceVerification.d.ts.map +1 -1
  20. package/dist/auth/deviceVerification.js +293 -40
  21. package/dist/auth/deviceVerification.js.map +1 -1
  22. package/dist/auth/displayUtils.d.ts +98 -0
  23. package/dist/auth/displayUtils.d.ts.map +1 -0
  24. package/dist/auth/displayUtils.js +133 -0
  25. package/dist/auth/displayUtils.js.map +1 -0
  26. package/dist/auth/loginGuard.d.ts +108 -14
  27. package/dist/auth/loginGuard.d.ts.map +1 -1
  28. package/dist/auth/loginGuard.js +153 -31
  29. package/dist/auth/loginGuard.js.map +1 -1
  30. package/dist/auth/offlineCredentials.d.ts +132 -15
  31. package/dist/auth/offlineCredentials.d.ts.map +1 -1
  32. package/dist/auth/offlineCredentials.js +167 -23
  33. package/dist/auth/offlineCredentials.js.map +1 -1
  34. package/dist/auth/offlineLogin.d.ts +96 -10
  35. package/dist/auth/offlineLogin.d.ts.map +1 -1
  36. package/dist/auth/offlineLogin.js +82 -15
  37. package/dist/auth/offlineLogin.js.map +1 -1
  38. package/dist/auth/offlineSession.d.ts +83 -9
  39. package/dist/auth/offlineSession.d.ts.map +1 -1
  40. package/dist/auth/offlineSession.js +104 -13
  41. package/dist/auth/offlineSession.js.map +1 -1
  42. package/dist/auth/resolveAuthState.d.ts +70 -8
  43. package/dist/auth/resolveAuthState.d.ts.map +1 -1
  44. package/dist/auth/resolveAuthState.js +142 -46
  45. package/dist/auth/resolveAuthState.js.map +1 -1
  46. package/dist/auth/singleUser.d.ts +390 -37
  47. package/dist/auth/singleUser.d.ts.map +1 -1
  48. package/dist/auth/singleUser.js +500 -99
  49. package/dist/auth/singleUser.js.map +1 -1
  50. package/dist/bin/install-pwa.d.ts +18 -2
  51. package/dist/bin/install-pwa.d.ts.map +1 -1
  52. package/dist/bin/install-pwa.js +801 -25
  53. package/dist/bin/install-pwa.js.map +1 -1
  54. package/dist/config.d.ts +132 -12
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +87 -9
  57. package/dist/config.js.map +1 -1
  58. package/dist/conflicts.d.ts +246 -23
  59. package/dist/conflicts.d.ts.map +1 -1
  60. package/dist/conflicts.js +495 -46
  61. package/dist/conflicts.js.map +1 -1
  62. package/dist/data.d.ts +338 -18
  63. package/dist/data.d.ts.map +1 -1
  64. package/dist/data.js +385 -34
  65. package/dist/data.js.map +1 -1
  66. package/dist/database.d.ts +72 -14
  67. package/dist/database.d.ts.map +1 -1
  68. package/dist/database.js +120 -29
  69. package/dist/database.js.map +1 -1
  70. package/dist/debug.d.ts +77 -1
  71. package/dist/debug.d.ts.map +1 -1
  72. package/dist/debug.js +88 -1
  73. package/dist/debug.js.map +1 -1
  74. package/dist/deviceId.d.ts +38 -7
  75. package/dist/deviceId.d.ts.map +1 -1
  76. package/dist/deviceId.js +68 -10
  77. package/dist/deviceId.js.map +1 -1
  78. package/dist/engine.d.ts +175 -3
  79. package/dist/engine.d.ts.map +1 -1
  80. package/dist/engine.js +756 -109
  81. package/dist/engine.js.map +1 -1
  82. package/dist/entries/actions.d.ts +13 -0
  83. package/dist/entries/actions.d.ts.map +1 -1
  84. package/dist/entries/actions.js +26 -1
  85. package/dist/entries/actions.js.map +1 -1
  86. package/dist/entries/auth.d.ts +16 -0
  87. package/dist/entries/auth.d.ts.map +1 -1
  88. package/dist/entries/auth.js +73 -1
  89. package/dist/entries/auth.js.map +1 -1
  90. package/dist/entries/config.d.ts +12 -0
  91. package/dist/entries/config.d.ts.map +1 -1
  92. package/dist/entries/config.js +18 -1
  93. package/dist/entries/config.js.map +1 -1
  94. package/dist/entries/kit.d.ts +11 -0
  95. package/dist/entries/kit.d.ts.map +1 -1
  96. package/dist/entries/kit.js +52 -2
  97. package/dist/entries/kit.js.map +1 -1
  98. package/dist/entries/stores.d.ts +11 -0
  99. package/dist/entries/stores.d.ts.map +1 -1
  100. package/dist/entries/stores.js +43 -2
  101. package/dist/entries/stores.js.map +1 -1
  102. package/dist/entries/types.d.ts +10 -0
  103. package/dist/entries/types.d.ts.map +1 -1
  104. package/dist/entries/types.js +10 -0
  105. package/dist/entries/types.js.map +1 -1
  106. package/dist/entries/utils.d.ts +6 -0
  107. package/dist/entries/utils.d.ts.map +1 -1
  108. package/dist/entries/utils.js +22 -1
  109. package/dist/entries/utils.js.map +1 -1
  110. package/dist/entries/vite.d.ts +17 -0
  111. package/dist/entries/vite.d.ts.map +1 -1
  112. package/dist/entries/vite.js +24 -1
  113. package/dist/entries/vite.js.map +1 -1
  114. package/dist/index.d.ts +31 -0
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +175 -20
  117. package/dist/index.js.map +1 -1
  118. package/dist/kit/auth.d.ts +60 -5
  119. package/dist/kit/auth.d.ts.map +1 -1
  120. package/dist/kit/auth.js +45 -4
  121. package/dist/kit/auth.js.map +1 -1
  122. package/dist/kit/confirm.d.ts +93 -12
  123. package/dist/kit/confirm.d.ts.map +1 -1
  124. package/dist/kit/confirm.js +103 -16
  125. package/dist/kit/confirm.js.map +1 -1
  126. package/dist/kit/loads.d.ts +150 -23
  127. package/dist/kit/loads.d.ts.map +1 -1
  128. package/dist/kit/loads.js +140 -24
  129. package/dist/kit/loads.js.map +1 -1
  130. package/dist/kit/server.d.ts +142 -10
  131. package/dist/kit/server.d.ts.map +1 -1
  132. package/dist/kit/server.js +158 -15
  133. package/dist/kit/server.js.map +1 -1
  134. package/dist/kit/sw.d.ts +152 -23
  135. package/dist/kit/sw.d.ts.map +1 -1
  136. package/dist/kit/sw.js +182 -26
  137. package/dist/kit/sw.js.map +1 -1
  138. package/dist/queue.d.ts +274 -0
  139. package/dist/queue.d.ts.map +1 -1
  140. package/dist/queue.js +556 -38
  141. package/dist/queue.js.map +1 -1
  142. package/dist/realtime.d.ts +241 -27
  143. package/dist/realtime.d.ts.map +1 -1
  144. package/dist/realtime.js +633 -109
  145. package/dist/realtime.js.map +1 -1
  146. package/dist/runtime/runtimeConfig.d.ts +91 -8
  147. package/dist/runtime/runtimeConfig.d.ts.map +1 -1
  148. package/dist/runtime/runtimeConfig.js +146 -19
  149. package/dist/runtime/runtimeConfig.js.map +1 -1
  150. package/dist/stores/authState.d.ts +150 -11
  151. package/dist/stores/authState.d.ts.map +1 -1
  152. package/dist/stores/authState.js +169 -17
  153. package/dist/stores/authState.js.map +1 -1
  154. package/dist/stores/network.d.ts +39 -0
  155. package/dist/stores/network.d.ts.map +1 -1
  156. package/dist/stores/network.js +169 -16
  157. package/dist/stores/network.js.map +1 -1
  158. package/dist/stores/remoteChanges.d.ts +327 -52
  159. package/dist/stores/remoteChanges.d.ts.map +1 -1
  160. package/dist/stores/remoteChanges.js +337 -75
  161. package/dist/stores/remoteChanges.js.map +1 -1
  162. package/dist/stores/sync.d.ts +130 -0
  163. package/dist/stores/sync.d.ts.map +1 -1
  164. package/dist/stores/sync.js +167 -7
  165. package/dist/stores/sync.js.map +1 -1
  166. package/dist/supabase/auth.d.ts +325 -18
  167. package/dist/supabase/auth.d.ts.map +1 -1
  168. package/dist/supabase/auth.js +374 -26
  169. package/dist/supabase/auth.js.map +1 -1
  170. package/dist/supabase/client.d.ts +79 -6
  171. package/dist/supabase/client.d.ts.map +1 -1
  172. package/dist/supabase/client.js +158 -15
  173. package/dist/supabase/client.js.map +1 -1
  174. package/dist/supabase/validate.d.ts +101 -7
  175. package/dist/supabase/validate.d.ts.map +1 -1
  176. package/dist/supabase/validate.js +117 -8
  177. package/dist/supabase/validate.js.map +1 -1
  178. package/dist/sw/build/vite-plugin.d.ts +55 -10
  179. package/dist/sw/build/vite-plugin.d.ts.map +1 -1
  180. package/dist/sw/build/vite-plugin.js +77 -18
  181. package/dist/sw/build/vite-plugin.js.map +1 -1
  182. package/dist/sw/sw.js +99 -44
  183. package/dist/types.d.ts +150 -26
  184. package/dist/types.d.ts.map +1 -1
  185. package/dist/types.js +12 -10
  186. package/dist/types.js.map +1 -1
  187. package/dist/utils.d.ts +55 -13
  188. package/dist/utils.d.ts.map +1 -1
  189. package/dist/utils.js +83 -22
  190. package/dist/utils.js.map +1 -1
  191. package/package.json +1 -1
@@ -1,36 +1,119 @@
1
1
  /**
2
- * Device Verification Module
2
+ * @fileoverview Device Verification Module
3
3
  *
4
- * Manages trusted devices for single-user and multi-user modes.
5
- * Uses Supabase `trusted_devices` table and `signInWithOtp()` for email-based
6
- * device verification on untrusted devices.
4
+ * Manages the trusted device registry and email-based OTP verification flow
5
+ * for both single-user and multi-user modes. When device verification is
6
+ * enabled, only devices present in the Supabase `trusted_devices` table (with
7
+ * a recent `last_used_at` timestamp) are allowed to proceed after
8
+ * authentication. Untrusted devices must complete an email OTP challenge.
9
+ *
10
+ * ## Architecture
11
+ *
12
+ * - **Device identification**: Each browser/device is assigned a persistent
13
+ * unique ID via {@link getDeviceId} (stored in localStorage). This ID is
14
+ * used as the key in the `trusted_devices` table.
15
+ * - **Trust expiry**: Trusted devices expire after a configurable number of
16
+ * days (default: 90). The `last_used_at` column is refreshed on each
17
+ * successful login via {@link touchTrustedDevice}.
18
+ * - **OTP flow**: Uses Supabase `signInWithOtp()` with `shouldCreateUser: false`
19
+ * to send a magic link email. The confirm page verifies the token and trusts
20
+ * both the originating device and the confirming device.
21
+ * - **Cross-device verification**: The originating device's ID is stored in
22
+ * `user_metadata` as `pending_device_id` so the confirm page can trust it
23
+ * even when opened on a different device (e.g., phone).
24
+ *
25
+ * ## Database Schema
26
+ *
27
+ * The `trusted_devices` table has a unique constraint on `(user_id, device_id)`:
28
+ *
29
+ * | Column | Type | Description |
30
+ * |-------------|-----------|---------------------------------------|
31
+ * | id | uuid | Primary key |
32
+ * | user_id | uuid | FK to auth.users |
33
+ * | device_id | text | Persistent browser/device identifier |
34
+ * | device_label| text | Human-readable label (e.g., "Chrome on macOS") |
35
+ * | trusted_at | timestamp | When the device was first trusted |
36
+ * | last_used_at| timestamp | Last successful login from this device |
37
+ *
38
+ * ## Security Considerations
39
+ *
40
+ * - **Device ID spoofing**: The device ID is stored in localStorage and can be
41
+ * copied. This provides convenience-level trust, not cryptographic assurance.
42
+ * An attacker who clones localStorage can impersonate a trusted device.
43
+ * - **OTP security**: OTP tokens are single-use and time-limited (configured
44
+ * in Supabase). The `shouldCreateUser: false` flag prevents account creation
45
+ * via the OTP endpoint.
46
+ * - **Trust duration**: The default 90-day trust window balances convenience
47
+ * and security. Reduce this for higher-security applications.
48
+ * - **RLS**: The `trusted_devices` table should have Row Level Security
49
+ * policies ensuring users can only read/write their own device records.
50
+ *
51
+ * @module deviceVerification
52
+ * @see {@link singleUser} for how device verification integrates into the auth flow
7
53
  */
8
54
  import { getEngineConfig } from '../config';
9
55
  import { supabase } from '../supabase/client';
10
56
  import { getDeviceId } from '../deviceId';
11
57
  import { debugLog, debugWarn, debugError } from '../debug';
58
+ /** Default number of days a device remains trusted before requiring re-verification. */
12
59
  const DEFAULT_TRUST_DURATION_DAYS = 90;
13
- // ============================================================
60
+ // =============================================================================
14
61
  // HELPERS
15
- // ============================================================
62
+ // =============================================================================
63
+ /**
64
+ * Get the configured trust duration in days.
65
+ *
66
+ * Falls back to {@link DEFAULT_TRUST_DURATION_DAYS} (90) if not configured.
67
+ *
68
+ * @returns The number of days a device should remain trusted.
69
+ */
16
70
  function getTrustDurationDays() {
17
71
  return (getEngineConfig().auth?.deviceVerification?.trustDurationDays ?? DEFAULT_TRUST_DURATION_DAYS);
18
72
  }
73
+ /**
74
+ * Convert a snake_case database row into a camelCase {@link TrustedDevice} object.
75
+ *
76
+ * Supabase returns rows with snake_case column names, but the TypeScript
77
+ * interface uses camelCase. This function performs the field mapping.
78
+ *
79
+ * @param row - A raw database row from the `trusted_devices` table.
80
+ * @returns A properly typed {@link TrustedDevice} object.
81
+ */
19
82
  function snakeToCamelDevice(row) {
20
83
  return {
84
+ /** Primary key (UUID). */
21
85
  id: row.id,
86
+ /** The Supabase user ID that owns this device record. */
22
87
  userId: row.user_id,
88
+ /** The persistent device identifier from localStorage. */
23
89
  deviceId: row.device_id,
90
+ /** Human-readable label (e.g., "Chrome on macOS"). */
24
91
  deviceLabel: row.device_label,
92
+ /** ISO timestamp of when the device was first trusted. */
25
93
  trustedAt: row.trusted_at,
94
+ /** ISO timestamp of the most recent successful login from this device. */
26
95
  lastUsedAt: row.last_used_at
27
96
  };
28
97
  }
29
- // ============================================================
98
+ // =============================================================================
30
99
  // DEVICE LABEL
31
- // ============================================================
100
+ // =============================================================================
32
101
  /**
33
- * Generate a human-readable device label (e.g. "Chrome on macOS").
102
+ * Generate a human-readable device label from the browser's User-Agent string.
103
+ *
104
+ * Detects common browsers (Chrome, Firefox, Edge, Safari) and operating systems
105
+ * (macOS, Windows, Linux, iOS, Android, ChromeOS). Returns a combined label
106
+ * like "Chrome on macOS" for display in device management UIs.
107
+ *
108
+ * @returns A human-readable label describing the current browser and OS, or
109
+ * "Unknown device" in non-browser environments.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * getDeviceLabel(); // => "Chrome on macOS"
114
+ * getDeviceLabel(); // => "Safari on iOS"
115
+ * getDeviceLabel(); // => "Firefox on Linux"
116
+ * ```
34
117
  */
35
118
  export function getDeviceLabel() {
36
119
  if (typeof navigator === 'undefined')
@@ -38,7 +121,8 @@ export function getDeviceLabel() {
38
121
  const ua = navigator.userAgent;
39
122
  let browser = 'Browser';
40
123
  let os = '';
41
- // Detect browser
124
+ /* Detect browser — order matters: Edge contains "Chrome" in its UA,
125
+ so Edge must be checked before Chrome */
42
126
  if (ua.includes('Firefox'))
43
127
  browser = 'Firefox';
44
128
  else if (ua.includes('Edg/'))
@@ -47,9 +131,9 @@ export function getDeviceLabel() {
47
131
  browser = 'Chrome';
48
132
  else if (ua.includes('Safari') && !ua.includes('Chrome'))
49
133
  browser = 'Safari';
50
- // Detect OS — mobile checks must come before desktop checks because
51
- // mobile UA strings often contain desktop OS identifiers
52
- // (e.g. iPhone UA contains "like Mac OS X", Android UA contains "Linux")
134
+ /* Detect OS — mobile checks must come before desktop checks because
135
+ mobile UA strings often contain desktop OS identifiers
136
+ (e.g., iPhone UA contains "like Mac OS X", Android UA contains "Linux") */
53
137
  if (ua.includes('iPhone') || ua.includes('iPad') || ua.includes('iPod'))
54
138
  os = 'iOS';
55
139
  else if (ua.includes('Android'))
@@ -64,32 +148,70 @@ export function getDeviceLabel() {
64
148
  os = 'Linux';
65
149
  return os ? `${browser} on ${os}` : browser;
66
150
  }
67
- // ============================================================
151
+ // =============================================================================
68
152
  // EMAIL MASKING
69
- // ============================================================
153
+ // =============================================================================
70
154
  /**
71
- * Mask an email address for display (e.g. "pr••••@gmail.com").
155
+ * Mask an email address for safe display in the UI.
156
+ *
157
+ * Shows the first 2 characters of the local part, replaces the rest with
158
+ * bullet characters, and preserves the full domain. This prevents shoulder-
159
+ * surfing while still letting the user confirm it's the right email.
160
+ *
161
+ * @param email - The full email address to mask.
162
+ * @returns The masked email string (e.g., "pr\u2022\u2022\u2022\u2022@gmail.com").
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * maskEmail('prabhask@gmail.com'); // => "pr••••••@gmail.com"
167
+ * maskEmail('ab@example.com'); // => "ab@example.com"
168
+ * maskEmail('a@test.io'); // => "a•@test.io"
169
+ * ```
170
+ *
171
+ * @security This is a display-only mask. The original email should never be
172
+ * exposed in logs or error messages shown to untrusted contexts.
72
173
  */
73
174
  export function maskEmail(email) {
74
175
  const [local, domain] = email.split('@');
75
176
  if (!domain)
76
177
  return email;
178
+ /* Show at most 2 characters to provide enough recognition without
179
+ revealing the full local part */
77
180
  const visible = Math.min(2, local.length);
78
181
  const masked = local.slice(0, visible) + '\u2022'.repeat(Math.max(1, local.length - visible));
79
182
  return `${masked}@${domain}`;
80
183
  }
81
- // ============================================================
184
+ // =============================================================================
82
185
  // DEVICE TRUST QUERIES
83
- // ============================================================
186
+ // =============================================================================
84
187
  /**
85
188
  * Check if the current device is trusted for a given user.
86
- * A device is trusted if it has a `trusted_devices` row with `last_used_at`
87
- * within the configured trust duration.
189
+ *
190
+ * Queries the `trusted_devices` table for a record matching the current
191
+ * device ID and user ID, with `last_used_at` within the configured trust
192
+ * duration window. Returns `false` on any error (fail-closed).
193
+ *
194
+ * @param userId - The Supabase user ID to check trust for.
195
+ * @returns `true` if the device is trusted and not expired, `false` otherwise.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * if (await isDeviceTrusted(user.id)) {
200
+ * grantAccess();
201
+ * } else {
202
+ * challengeWithOtp();
203
+ * }
204
+ * ```
205
+ *
206
+ * @security Fails closed: any error (network, RLS, etc.) returns `false`,
207
+ * forcing the device verification flow rather than granting access.
88
208
  */
89
209
  export async function isDeviceTrusted(userId) {
90
210
  try {
91
211
  const deviceId = getDeviceId();
92
212
  const trustDays = getTrustDurationDays();
213
+ /* Calculate the cutoff date — devices not used within this window
214
+ are considered expired and must re-verify */
93
215
  const cutoff = new Date();
94
216
  cutoff.setDate(cutoff.getDate() - trustDays);
95
217
  const { data, error } = await supabase
@@ -112,7 +234,20 @@ export async function isDeviceTrusted(userId) {
112
234
  }
113
235
  /**
114
236
  * Trust the current device for a user.
115
- * Uses upsert on (user_id, device_id) unique constraint.
237
+ *
238
+ * Creates or updates a record in the `trusted_devices` table using upsert on
239
+ * the `(user_id, device_id)` unique constraint. Both `trusted_at` and
240
+ * `last_used_at` are set to the current time.
241
+ *
242
+ * @param userId - The Supabase user ID to associate the trust record with.
243
+ *
244
+ * @example
245
+ * ```ts
246
+ * // After successful OTP verification:
247
+ * await trustCurrentDevice(user.id);
248
+ * ```
249
+ *
250
+ * @see {@link trustPendingDevice} for trusting a remote device via user_metadata
116
251
  */
117
252
  export async function trustCurrentDevice(userId) {
118
253
  try {
@@ -139,6 +274,13 @@ export async function trustCurrentDevice(userId) {
139
274
  }
140
275
  /**
141
276
  * Update `last_used_at` for the current device (called on each successful login).
277
+ *
278
+ * This extends the trust window so that frequently-used devices do not expire.
279
+ * Also refreshes the device label in case the browser or OS was updated.
280
+ *
281
+ * @param userId - The Supabase user ID whose device record to update.
282
+ *
283
+ * @see {@link isDeviceTrusted} which checks the `last_used_at` timestamp
142
284
  */
143
285
  export async function touchTrustedDevice(userId) {
144
286
  try {
@@ -157,7 +299,23 @@ export async function touchTrustedDevice(userId) {
157
299
  }
158
300
  }
159
301
  /**
160
- * Get all trusted devices for a user.
302
+ * Get all trusted devices for a user, ordered by most recently used first.
303
+ *
304
+ * Used by device management UIs to display a list of trusted devices with
305
+ * options to revoke trust.
306
+ *
307
+ * @param userId - The Supabase user ID to fetch devices for.
308
+ * @returns An array of {@link TrustedDevice} objects, or an empty array on error.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * const devices = await getTrustedDevices(user.id);
313
+ * devices.forEach(d => {
314
+ * console.log(`${d.deviceLabel} — last used ${d.lastUsedAt}`);
315
+ * });
316
+ * ```
317
+ *
318
+ * @see {@link removeTrustedDevice} for revoking trust on a specific device
161
319
  */
162
320
  export async function getTrustedDevices(userId) {
163
321
  try {
@@ -178,7 +336,21 @@ export async function getTrustedDevices(userId) {
178
336
  }
179
337
  }
180
338
  /**
181
- * Remove a trusted device by ID.
339
+ * Remove a trusted device by its primary key ID.
340
+ *
341
+ * Used by the device management UI to allow users to revoke trust on devices
342
+ * they no longer control (e.g., lost phone, sold laptop). After removal, the
343
+ * device will be challenged with OTP verification on its next login.
344
+ *
345
+ * @param id - The UUID primary key of the `trusted_devices` row to delete.
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * // Revoke trust on a specific device:
350
+ * await removeTrustedDevice('550e8400-e29b-41d4-a716-446655440000');
351
+ * ```
352
+ *
353
+ * @security Ensure RLS policies restrict deletion to the owning user.
182
354
  */
183
355
  export async function removeTrustedDevice(id) {
184
356
  try {
@@ -194,19 +366,39 @@ export async function removeTrustedDevice(id) {
194
366
  debugError('[DeviceVerification] Remove device error:', e);
195
367
  }
196
368
  }
197
- // ============================================================
369
+ // =============================================================================
198
370
  // OTP VERIFICATION FLOW
199
- // ============================================================
371
+ // =============================================================================
200
372
  /**
201
- * Send a device verification OTP email.
373
+ * Send a device verification OTP email to the user.
374
+ *
375
+ * This function performs two actions:
376
+ * 1. **Stores pending device info** in Supabase `user_metadata` so that the
377
+ * confirm page can trust the originating device even if the link is opened
378
+ * on a different device.
379
+ * 2. **Sends an OTP email** via `signInWithOtp()` with `shouldCreateUser: false`
380
+ * to prevent account creation through this endpoint.
381
+ *
382
+ * The existing session is intentionally kept alive so that
383
+ * {@link pollDeviceVerification} can continue checking trust status.
384
+ *
385
+ * @param email - The user's email address to send the OTP to.
386
+ * @returns An object with `error` (string or null).
202
387
  *
203
- * Keeps the session alive (needed for cross-device polling) and stores
204
- * this device's ID in user_metadata so the confirm page can trust it.
388
+ * @throws Never throws directly; all errors are caught and returned.
389
+ *
390
+ * @security The `shouldCreateUser: false` flag prevents this endpoint from
391
+ * being abused to create new accounts. The OTP is time-limited and
392
+ * single-use (configured in Supabase dashboard).
393
+ *
394
+ * @see {@link verifyDeviceCode} for verifying the OTP token
395
+ * @see {@link trustPendingDevice} for trusting the originating device from the confirm page
205
396
  */
206
397
  export async function sendDeviceVerification(email) {
207
398
  try {
208
- // Store the pending device info in user_metadata so the confirm page
209
- // can trust THIS device even if the link is opened on a different one.
399
+ /* Store the pending device info in user_metadata so the confirm page
400
+ can trust THIS device even if the link is opened on a different one.
401
+ This enables the cross-device verification pattern. */
210
402
  const deviceId = getDeviceId();
211
403
  const deviceLabel = getDeviceLabel();
212
404
  await supabase.auth.updateUser({
@@ -229,11 +421,32 @@ export async function sendDeviceVerification(email) {
229
421
  }
230
422
  }
231
423
  /**
232
- * Trust the pending device stored in user_metadata.
424
+ * Trust the pending device stored in `user_metadata`.
425
+ *
426
+ * Called from the confirm page after a device OTP is verified. This function
427
+ * trusts the ORIGINATING device (the one that entered the PIN and triggered
428
+ * verification), not necessarily the device opening the confirmation link.
429
+ *
430
+ * ## Cross-Device Flow
233
431
  *
234
- * Called from the confirm page after a device OTP is verified. This trusts
235
- * the ORIGINATING device (the one that entered the PIN and triggered
236
- * verification), not the device opening the confirmation link.
432
+ * 1. Device A enters the PIN -> untrusted -> OTP sent, device A's ID stored
433
+ * in `user_metadata.pending_device_id`.
434
+ * 2. User opens the OTP link on Device B (or Device A).
435
+ * 3. This function reads `pending_device_id` from metadata and trusts Device A.
436
+ * 4. Device A polls via {@link pollDeviceVerification} and discovers it's now trusted.
437
+ * 5. Both Device A and the confirming device (B) are trusted.
438
+ *
439
+ * If no `pending_device_id` is found in metadata (same-browser case where the
440
+ * link was opened in the same browser), falls back to trusting the current
441
+ * device only.
442
+ *
443
+ * @example
444
+ * ```ts
445
+ * // Called from the /confirm page after OTP verification:
446
+ * await trustPendingDevice();
447
+ * ```
448
+ *
449
+ * @see {@link sendDeviceVerification} which stores the pending device ID
237
450
  */
238
451
  export async function trustPendingDevice() {
239
452
  try {
@@ -245,12 +458,15 @@ export async function trustPendingDevice() {
245
458
  const pendingDeviceId = user.user_metadata?.pending_device_id;
246
459
  const pendingDeviceLabel = user.user_metadata?.pending_device_label;
247
460
  if (!pendingDeviceId) {
248
- // No pending device — fall back to trusting the current device (same-browser case)
461
+ /* No pending device — fall back to trusting the current device.
462
+ This handles the same-browser case where the OTP link is opened
463
+ in the same browser that initiated verification. */
249
464
  await trustCurrentDevice(user.id);
250
465
  return;
251
466
  }
252
467
  const now = new Date().toISOString();
253
- // Trust the originating device
468
+ /* Trust the originating device (the one that entered the PIN) by
469
+ upserting its device ID into the trusted_devices table */
254
470
  const { error: upsertError } = await supabase.from('trusted_devices').upsert({
255
471
  user_id: user.id,
256
472
  device_id: pendingDeviceId,
@@ -264,9 +480,11 @@ export async function trustPendingDevice() {
264
480
  else {
265
481
  debugLog('[DeviceVerification] Pending device trusted:', pendingDeviceLabel);
266
482
  }
267
- // Also trust the current device (the one opening the confirmation link)
483
+ /* Also trust the current device (the one opening the confirmation link),
484
+ since the user has demonstrated control of the email on this device too */
268
485
  await trustCurrentDevice(user.id);
269
- // Clear pending device from metadata
486
+ /* Clear pending device from metadata to prevent stale references.
487
+ Setting to null removes the keys from user_metadata. */
270
488
  await supabase.auth.updateUser({
271
489
  data: { pending_device_id: null, pending_device_label: null }
272
490
  });
@@ -276,7 +494,32 @@ export async function trustPendingDevice() {
276
494
  }
277
495
  }
278
496
  /**
279
- * Verify a device verification OTP token hash (from email link).
497
+ * Verify a device verification OTP token hash from an email link.
498
+ *
499
+ * Called from the confirm page with the `token_hash` query parameter extracted
500
+ * from the magic link URL. On success, Supabase establishes a session for the
501
+ * user, which enables subsequent calls to trust devices.
502
+ *
503
+ * @param tokenHash - The token hash from the email link's URL query parameters.
504
+ * @returns An object with `error` (string or null).
505
+ *
506
+ * @throws Never throws directly; all errors are caught and returned.
507
+ *
508
+ * @example
509
+ * ```ts
510
+ * // On the /confirm page:
511
+ * const params = new URLSearchParams(window.location.search);
512
+ * const tokenHash = params.get('token_hash');
513
+ * if (tokenHash) {
514
+ * const result = await verifyDeviceCode(tokenHash);
515
+ * if (!result.error) {
516
+ * await trustPendingDevice();
517
+ * }
518
+ * }
519
+ * ```
520
+ *
521
+ * @see {@link sendDeviceVerification} which sends the OTP email
522
+ * @see {@link trustPendingDevice} which should be called after successful verification
280
523
  */
281
524
  export async function verifyDeviceCode(tokenHash) {
282
525
  try {
@@ -296,8 +539,18 @@ export async function verifyDeviceCode(tokenHash) {
296
539
  return { error: e instanceof Error ? e.message : 'Verification failed' };
297
540
  }
298
541
  }
542
+ // =============================================================================
543
+ // PUBLIC UTILITIES
544
+ // =============================================================================
299
545
  /**
300
- * Get the current device ID (exposed for consumers).
546
+ * Get the current device's persistent unique identifier.
547
+ *
548
+ * Exposed as a convenience for consumers who need to reference the device ID
549
+ * (e.g., for display in a device management UI or for debugging).
550
+ *
551
+ * @returns The persistent device ID string from localStorage.
552
+ *
553
+ * @see {@link getDeviceId} from the `deviceId` module for the underlying implementation
301
554
  */
302
555
  export function getCurrentDeviceId() {
303
556
  return getDeviceId();
@@ -1 +1 @@
1
- {"version":3,"file":"deviceVerification.js","sourceRoot":"","sources":["../../src/auth/deviceVerification.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deviceVerification.js","sourceRoot":"","sources":["../../src/auth/deviceVerification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @fileoverview Auth Display Utilities
3
+ *
4
+ * Pure helper functions that resolve user-facing display values (first name,
5
+ * user ID, avatar initial) from the auth state. Each function handles the
6
+ * full fallback chain across online (Supabase session) and offline (cached
7
+ * credentials) modes, so consuming components don't need to duplicate the
8
+ * resolution logic.
9
+ *
10
+ * Resolution strategy (consistent across all helpers):
11
+ * 1. Check the Supabase session (`Session.user`) first.
12
+ * 2. Fall back to the offline credential cache (`OfflineCredentials`).
13
+ * 3. Return a caller-provided fallback or a sensible default.
14
+ *
15
+ * These functions are stateless and framework-agnostic — they accept plain
16
+ * data and return plain values. Wrap them in `$derived` / `$derived.by` in
17
+ * Svelte 5 components to make them reactive.
18
+ *
19
+ * @module auth/displayUtils
20
+ */
21
+ import type { Session } from '@supabase/supabase-js';
22
+ import type { OfflineCredentials } from '../types';
23
+ /**
24
+ * Resolve the user's first name for greeting / display purposes.
25
+ *
26
+ * Fallback chain:
27
+ * 1. `firstName` / `first_name` from the Supabase session profile
28
+ * (extracted via `getUserProfile()`, which respects the app's
29
+ * `profileExtractor` config)
30
+ * 2. Email username (everything before `@`) from the Supabase session
31
+ * 3. `firstName` from the offline cached profile
32
+ * 4. Email username from the offline cached profile
33
+ * 5. The provided `fallback` string (default: `'Explorer'`)
34
+ *
35
+ * @param session - The current Supabase session, or `null`.
36
+ * @param offlineProfile - The cached offline credentials, or `null`.
37
+ * @param fallback - Value returned when no name can be resolved.
38
+ * Defaults to `'Explorer'`.
39
+ * @returns The resolved first name string.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * // In a Svelte 5 component:
44
+ * const firstName = $derived(
45
+ * resolveFirstName($authState.session, $authState.offlineProfile)
46
+ * );
47
+ * ```
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * // With a custom fallback:
52
+ * const greeting = resolveFirstName(session, offline, 'there');
53
+ * // → "Hey, there!" when no name is available
54
+ * ```
55
+ */
56
+ export declare function resolveFirstName(session: Session | null, offlineProfile: OfflineCredentials | null, fallback?: string): string;
57
+ /**
58
+ * Resolve the current user's UUID from auth state.
59
+ *
60
+ * Checks the Supabase session first, then falls back to the offline
61
+ * credential cache. Returns an empty string when no user is authenticated.
62
+ *
63
+ * @param session - The current Supabase session, or `null`.
64
+ * @param offlineProfile - The cached offline credentials, or `null`.
65
+ * @returns The user's UUID, or `''` if unauthenticated.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const userId = resolveUserId(data.session, data.offlineProfile);
70
+ * if (!userId) {
71
+ * error = 'Not authenticated';
72
+ * return;
73
+ * }
74
+ * ```
75
+ */
76
+ export declare function resolveUserId(session: Session | null, offlineProfile: OfflineCredentials | null): string;
77
+ /**
78
+ * Resolve a single uppercase initial letter for avatar display.
79
+ *
80
+ * Uses {@link resolveFirstName} to derive the name, then returns the
81
+ * first character uppercased. If the resolved name is empty, returns
82
+ * the `fallback` character.
83
+ *
84
+ * @param session - The current Supabase session, or `null`.
85
+ * @param offlineProfile - The cached offline credentials, or `null`.
86
+ * @param fallback - Character to use when no initial can be derived.
87
+ * Defaults to `'?'`.
88
+ * @returns A single uppercase character.
89
+ *
90
+ * @example
91
+ * ```svelte
92
+ * <span class="avatar">
93
+ * {resolveAvatarInitial($authState.session, $authState.offlineProfile)}
94
+ * </span>
95
+ * ```
96
+ */
97
+ export declare function resolveAvatarInitial(session: Session | null, offlineProfile: OfflineCredentials | null, fallback?: string): string;
98
+ //# sourceMappingURL=displayUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"displayUtils.d.ts","sourceRoot":"","sources":["../../src/auth/displayUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAOnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,cAAc,EAAE,kBAAkB,GAAG,IAAI,EACzC,QAAQ,GAAE,MAAmB,GAC5B,MAAM,CAqBR;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,cAAc,EAAE,kBAAkB,GAAG,IAAI,GACxC,MAAM,CAQR;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,cAAc,EAAE,kBAAkB,GAAG,IAAI,EACzC,QAAQ,GAAE,MAAY,GACrB,MAAM,CAMR"}