@prabhask5/stellar-engine 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -18
- package/dist/actions/remoteChange.d.ts +143 -18
- package/dist/actions/remoteChange.d.ts.map +1 -1
- package/dist/actions/remoteChange.js +182 -58
- package/dist/actions/remoteChange.js.map +1 -1
- package/dist/actions/truncateTooltip.d.ts +26 -12
- package/dist/actions/truncateTooltip.d.ts.map +1 -1
- package/dist/actions/truncateTooltip.js +89 -34
- package/dist/actions/truncateTooltip.js.map +1 -1
- package/dist/auth/crypto.d.ts +35 -8
- package/dist/auth/crypto.d.ts.map +1 -1
- package/dist/auth/crypto.js +38 -10
- package/dist/auth/crypto.js.map +1 -1
- package/dist/auth/deviceVerification.d.ts +236 -20
- package/dist/auth/deviceVerification.d.ts.map +1 -1
- package/dist/auth/deviceVerification.js +293 -40
- package/dist/auth/deviceVerification.js.map +1 -1
- package/dist/auth/displayUtils.d.ts +98 -0
- package/dist/auth/displayUtils.d.ts.map +1 -0
- package/dist/auth/displayUtils.js +133 -0
- package/dist/auth/displayUtils.js.map +1 -0
- package/dist/auth/loginGuard.d.ts +103 -16
- package/dist/auth/loginGuard.d.ts.map +1 -1
- package/dist/auth/loginGuard.js +163 -76
- package/dist/auth/loginGuard.js.map +1 -1
- package/dist/auth/offlineCredentials.d.ts +88 -24
- package/dist/auth/offlineCredentials.d.ts.map +1 -1
- package/dist/auth/offlineCredentials.js +114 -73
- package/dist/auth/offlineCredentials.js.map +1 -1
- package/dist/auth/offlineSession.d.ts +83 -9
- package/dist/auth/offlineSession.d.ts.map +1 -1
- package/dist/auth/offlineSession.js +104 -13
- package/dist/auth/offlineSession.js.map +1 -1
- package/dist/auth/resolveAuthState.d.ts +67 -9
- package/dist/auth/resolveAuthState.d.ts.map +1 -1
- package/dist/auth/resolveAuthState.js +125 -71
- package/dist/auth/resolveAuthState.js.map +1 -1
- package/dist/auth/singleUser.d.ts +390 -37
- package/dist/auth/singleUser.d.ts.map +1 -1
- package/dist/auth/singleUser.js +504 -103
- package/dist/auth/singleUser.js.map +1 -1
- package/dist/bin/install-pwa.d.ts +18 -2
- package/dist/bin/install-pwa.d.ts.map +1 -1
- package/dist/bin/install-pwa.js +2624 -77
- package/dist/bin/install-pwa.js.map +1 -1
- package/dist/config.d.ts +131 -15
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +87 -9
- package/dist/config.js.map +1 -1
- package/dist/conflicts.d.ts +246 -23
- package/dist/conflicts.d.ts.map +1 -1
- package/dist/conflicts.js +495 -46
- package/dist/conflicts.js.map +1 -1
- package/dist/data.d.ts +338 -18
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +385 -34
- package/dist/data.js.map +1 -1
- package/dist/database.d.ts +72 -14
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +120 -29
- package/dist/database.js.map +1 -1
- package/dist/debug.d.ts +77 -1
- package/dist/debug.d.ts.map +1 -1
- package/dist/debug.js +88 -1
- package/dist/debug.js.map +1 -1
- package/dist/deviceId.d.ts +38 -7
- package/dist/deviceId.d.ts.map +1 -1
- package/dist/deviceId.js +68 -10
- package/dist/deviceId.js.map +1 -1
- package/dist/engine.d.ts +175 -3
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +756 -109
- package/dist/engine.js.map +1 -1
- package/dist/entries/actions.d.ts +13 -0
- package/dist/entries/actions.d.ts.map +1 -1
- package/dist/entries/actions.js +26 -1
- package/dist/entries/actions.js.map +1 -1
- package/dist/entries/auth.d.ts +15 -4
- package/dist/entries/auth.d.ts.map +1 -1
- package/dist/entries/auth.js +47 -4
- package/dist/entries/auth.js.map +1 -1
- package/dist/entries/config.d.ts +12 -0
- package/dist/entries/config.d.ts.map +1 -1
- package/dist/entries/config.js +18 -1
- package/dist/entries/config.js.map +1 -1
- package/dist/entries/kit.d.ts +11 -0
- package/dist/entries/kit.d.ts.map +1 -1
- package/dist/entries/kit.js +52 -2
- package/dist/entries/kit.js.map +1 -1
- package/dist/entries/stores.d.ts +11 -0
- package/dist/entries/stores.d.ts.map +1 -1
- package/dist/entries/stores.js +43 -2
- package/dist/entries/stores.js.map +1 -1
- package/dist/entries/types.d.ts +10 -1
- package/dist/entries/types.d.ts.map +1 -1
- package/dist/entries/types.js +10 -0
- package/dist/entries/types.js.map +1 -1
- package/dist/entries/utils.d.ts +6 -0
- package/dist/entries/utils.d.ts.map +1 -1
- package/dist/entries/utils.js +22 -1
- package/dist/entries/utils.js.map +1 -1
- package/dist/entries/vite.d.ts +17 -0
- package/dist/entries/vite.d.ts.map +1 -1
- package/dist/entries/vite.js +24 -1
- package/dist/entries/vite.js.map +1 -1
- package/dist/index.d.ts +32 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +166 -23
- package/dist/index.js.map +1 -1
- package/dist/kit/auth.d.ts +60 -5
- package/dist/kit/auth.d.ts.map +1 -1
- package/dist/kit/auth.js +45 -4
- package/dist/kit/auth.js.map +1 -1
- package/dist/kit/confirm.d.ts +93 -12
- package/dist/kit/confirm.d.ts.map +1 -1
- package/dist/kit/confirm.js +103 -16
- package/dist/kit/confirm.js.map +1 -1
- package/dist/kit/loads.d.ts +148 -23
- package/dist/kit/loads.d.ts.map +1 -1
- package/dist/kit/loads.js +136 -28
- package/dist/kit/loads.js.map +1 -1
- package/dist/kit/server.d.ts +142 -10
- package/dist/kit/server.d.ts.map +1 -1
- package/dist/kit/server.js +158 -15
- package/dist/kit/server.js.map +1 -1
- package/dist/kit/sw.d.ts +152 -23
- package/dist/kit/sw.d.ts.map +1 -1
- package/dist/kit/sw.js +182 -26
- package/dist/kit/sw.js.map +1 -1
- package/dist/queue.d.ts +274 -0
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +556 -38
- package/dist/queue.js.map +1 -1
- package/dist/realtime.d.ts +241 -27
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +633 -109
- package/dist/realtime.js.map +1 -1
- package/dist/runtime/runtimeConfig.d.ts +91 -8
- package/dist/runtime/runtimeConfig.d.ts.map +1 -1
- package/dist/runtime/runtimeConfig.js +146 -19
- package/dist/runtime/runtimeConfig.js.map +1 -1
- package/dist/stores/authState.d.ts +150 -11
- package/dist/stores/authState.d.ts.map +1 -1
- package/dist/stores/authState.js +169 -17
- package/dist/stores/authState.js.map +1 -1
- package/dist/stores/network.d.ts +39 -0
- package/dist/stores/network.d.ts.map +1 -1
- package/dist/stores/network.js +169 -16
- package/dist/stores/network.js.map +1 -1
- package/dist/stores/remoteChanges.d.ts +327 -52
- package/dist/stores/remoteChanges.d.ts.map +1 -1
- package/dist/stores/remoteChanges.js +337 -75
- package/dist/stores/remoteChanges.js.map +1 -1
- package/dist/stores/sync.d.ts +130 -0
- package/dist/stores/sync.d.ts.map +1 -1
- package/dist/stores/sync.js +167 -7
- package/dist/stores/sync.js.map +1 -1
- package/dist/supabase/auth.d.ts +186 -46
- package/dist/supabase/auth.d.ts.map +1 -1
- package/dist/supabase/auth.js +238 -190
- package/dist/supabase/auth.js.map +1 -1
- package/dist/supabase/client.d.ts +79 -6
- package/dist/supabase/client.d.ts.map +1 -1
- package/dist/supabase/client.js +158 -15
- package/dist/supabase/client.js.map +1 -1
- package/dist/supabase/validate.d.ts +101 -7
- package/dist/supabase/validate.d.ts.map +1 -1
- package/dist/supabase/validate.js +117 -8
- package/dist/supabase/validate.js.map +1 -1
- package/dist/sw/build/vite-plugin.d.ts +55 -10
- package/dist/sw/build/vite-plugin.d.ts.map +1 -1
- package/dist/sw/build/vite-plugin.js +77 -18
- package/dist/sw/build/vite-plugin.js.map +1 -1
- package/dist/sw/sw.js +99 -44
- package/dist/types.d.ts +150 -26
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -10
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +55 -13
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +83 -22
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/dist/auth/admin.d.ts +0 -12
- package/dist/auth/admin.d.ts.map +0 -1
- package/dist/auth/admin.js +0 -26
- package/dist/auth/admin.js.map +0 -1
- package/dist/auth/offlineLogin.d.ts +0 -34
- package/dist/auth/offlineLogin.d.ts.map +0 -1
- package/dist/auth/offlineLogin.js +0 -75
- package/dist/auth/offlineLogin.js.map +0 -1
|
@@ -1,42 +1,161 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Single-User
|
|
2
|
+
* @fileoverview Single-User Authentication Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Provides the complete authentication lifecycle for single-user mode, where a
|
|
5
|
+
* single user account is tied to the application instance. This module handles
|
|
6
|
+
* setup, unlock (login), locking, gate (PIN/password) changes, email changes,
|
|
7
|
+
* profile updates, multi-device linking, and full account reset.
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* ## Architecture
|
|
10
|
+
*
|
|
11
|
+
* Authentication is backed by Supabase email/password auth, where the user's
|
|
12
|
+
* PIN or password is padded (via {@link padPin}) to meet Supabase's minimum
|
|
13
|
+
* password length requirement. A local IndexedDB config store
|
|
14
|
+
* (`singleUserConfig` table) mirrors essential auth metadata for offline
|
|
15
|
+
* fallback and fast reads.
|
|
16
|
+
*
|
|
17
|
+
* ## Auth Flow Summary
|
|
18
|
+
*
|
|
19
|
+
* 1. **Setup** ({@link setupSingleUser}): Creates a Supabase user with
|
|
20
|
+
* `signUp()`. Optionally requires email confirmation.
|
|
21
|
+
* 2. **Unlock** ({@link unlockSingleUser}): Authenticates via
|
|
22
|
+
* `signInWithPassword()`. If device verification is enabled, untrusted
|
|
23
|
+
* devices are challenged with an OTP email before being granted a session.
|
|
24
|
+
* 3. **Offline fallback**: When offline, credentials are verified against a
|
|
25
|
+
* locally-cached SHA-256 hash of the gate. A cached Supabase session is
|
|
26
|
+
* restored if available; otherwise, a synthetic offline session is created.
|
|
27
|
+
* 4. **Lock** ({@link lockSingleUser}): Stops the sync engine and clears
|
|
28
|
+
* in-memory auth state, but preserves the Supabase session and local data.
|
|
29
|
+
*
|
|
30
|
+
* ## Security Considerations
|
|
31
|
+
*
|
|
32
|
+
* - **PIN padding**: PINs are short by design. The {@link padPin} function
|
|
33
|
+
* appends an app-specific suffix to meet Supabase's 6-character minimum,
|
|
34
|
+
* but the effective entropy remains that of the original PIN.
|
|
35
|
+
* - **Offline hash**: The gate hash stored in IndexedDB uses SHA-256 via the
|
|
36
|
+
* Web Crypto API. This is a convenience fallback, NOT a substitute for
|
|
37
|
+
* server-side verification. An attacker with IndexedDB access could
|
|
38
|
+
* brute-force a short PIN.
|
|
39
|
+
* - **Rate limiting**: The {@link preCheckLogin} guard provides client-side
|
|
40
|
+
* rate limiting to slow down brute-force attempts. Server-side rate limiting
|
|
41
|
+
* is handled by Supabase.
|
|
42
|
+
* - **Device verification**: When enabled, untrusted devices must verify via
|
|
43
|
+
* an email OTP before a session is granted. See {@link deviceVerification}.
|
|
44
|
+
*
|
|
45
|
+
* @module singleUser
|
|
46
|
+
* @see {@link deviceVerification} for the device trust and OTP verification layer
|
|
47
|
+
* @see {@link offlineCredentials} for cached credential management
|
|
48
|
+
* @see {@link offlineSession} for synthetic offline session creation
|
|
49
|
+
* @see {@link loginGuard} for pre-check rate limiting
|
|
11
50
|
*/
|
|
12
51
|
import type { SingleUserConfig } from '../types';
|
|
13
52
|
/**
|
|
14
53
|
* Pad a PIN to meet Supabase's minimum password length.
|
|
15
|
-
*
|
|
54
|
+
*
|
|
55
|
+
* Supabase requires passwords of at least 6 characters. Since PINs can be as
|
|
56
|
+
* short as 4 digits, this function appends an app-specific prefix as a suffix
|
|
57
|
+
* to reach a safe length.
|
|
58
|
+
*
|
|
59
|
+
* @param pin - The raw PIN/password entered by the user.
|
|
60
|
+
* @returns The padded string suitable for use as a Supabase password.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* // With default prefix 'app':
|
|
65
|
+
* padPin('1234'); // => '1234_app'
|
|
66
|
+
*
|
|
67
|
+
* // With custom prefix 'stellar':
|
|
68
|
+
* padPin('1234'); // => '1234_stellar'
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @security The padding increases character length but does NOT increase
|
|
72
|
+
* entropy. The suffix is deterministic and app-wide.
|
|
16
73
|
*/
|
|
17
74
|
export declare function padPin(pin: string): string;
|
|
18
75
|
/**
|
|
19
76
|
* Check if single-user mode has been set up (config exists in IndexedDB).
|
|
77
|
+
*
|
|
78
|
+
* This is a lightweight read used by the UI to decide whether to show the
|
|
79
|
+
* setup screen or the unlock screen.
|
|
80
|
+
*
|
|
81
|
+
* @returns `true` if a single-user config record exists, `false` otherwise.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* if (await isSingleUserSetUp()) {
|
|
86
|
+
* showUnlockScreen();
|
|
87
|
+
* } else {
|
|
88
|
+
* showSetupScreen();
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
20
91
|
*/
|
|
21
92
|
export declare function isSingleUserSetUp(): Promise<boolean>;
|
|
22
93
|
/**
|
|
23
94
|
* Get non-sensitive display info about the single user.
|
|
24
|
-
*
|
|
95
|
+
*
|
|
96
|
+
* Returns profile data, gate type, code length, and a masked email suitable
|
|
97
|
+
* for display in the UI. Does NOT return the gate hash or any secrets.
|
|
98
|
+
*
|
|
99
|
+
* @returns An object with display-safe user info, or `null` if not set up.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* const info = await getSingleUserInfo();
|
|
104
|
+
* if (info) {
|
|
105
|
+
* console.log(info.maskedEmail); // "pr••••@gmail.com"
|
|
106
|
+
* console.log(info.gateType); // "code"
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
25
109
|
*/
|
|
26
110
|
export declare function getSingleUserInfo(): Promise<{
|
|
111
|
+
/** Arbitrary user profile data (name, avatar, etc.). */
|
|
27
112
|
profile: Record<string, unknown>;
|
|
113
|
+
/** The type of gate: 'code' for numeric PIN, 'password' for freeform. */
|
|
28
114
|
gateType: SingleUserConfig['gateType'];
|
|
115
|
+
/** Length of the numeric code (4 or 6), if gateType is 'code'. */
|
|
29
116
|
codeLength?: 4 | 6;
|
|
117
|
+
/** The raw email address (included for internal use). */
|
|
30
118
|
email?: string;
|
|
119
|
+
/** The masked email for safe display (e.g. "pr••••@gmail.com"). */
|
|
31
120
|
maskedEmail?: string;
|
|
32
121
|
} | null>;
|
|
33
122
|
/**
|
|
34
|
-
* First-time setup: create Supabase user with email/password auth.
|
|
123
|
+
* First-time setup: create a Supabase user with email/password auth.
|
|
124
|
+
*
|
|
125
|
+
* This is the entry point for new users. It creates a Supabase account using
|
|
126
|
+
* `signUp()`, stores a local config in IndexedDB, and optionally requires
|
|
127
|
+
* email confirmation before granting a session.
|
|
128
|
+
*
|
|
129
|
+
* ## Online vs Offline
|
|
130
|
+
*
|
|
131
|
+
* - **Online**: Creates a real Supabase user, caches offline credentials,
|
|
132
|
+
* trusts the current device, and sets up the auth state.
|
|
133
|
+
* - **Offline**: Creates a temporary local-only setup with a random UUID as
|
|
134
|
+
* the user ID. The real Supabase account will be created when the user
|
|
135
|
+
* comes back online (handled by the sync engine).
|
|
136
|
+
*
|
|
137
|
+
* @param gate - The PIN or password chosen by the user.
|
|
138
|
+
* @param profile - Arbitrary profile data (e.g., `{ name: 'Alice' }`).
|
|
139
|
+
* @param email - The user's email address for Supabase auth.
|
|
140
|
+
* @returns An object with `error` (string or null) and `confirmationRequired`
|
|
141
|
+
* (true if the caller should show a "check your email" modal).
|
|
35
142
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
143
|
+
* @throws Never throws directly; all errors are caught and returned in the
|
|
144
|
+
* `error` field.
|
|
38
145
|
*
|
|
39
|
-
* @
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const result = await setupSingleUser('1234', { name: 'Alice' }, 'alice@example.com');
|
|
149
|
+
* if (result.error) {
|
|
150
|
+
* showError(result.error);
|
|
151
|
+
* } else if (result.confirmationRequired) {
|
|
152
|
+
* showEmailConfirmationModal();
|
|
153
|
+
* } else {
|
|
154
|
+
* navigateToHome();
|
|
155
|
+
* }
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* @see {@link completeSingleUserSetup} for finalizing after email confirmation
|
|
40
159
|
*/
|
|
41
160
|
export declare function setupSingleUser(gate: string, profile: Record<string, unknown>, email: string): Promise<{
|
|
42
161
|
error: string | null;
|
|
@@ -44,15 +163,62 @@ export declare function setupSingleUser(gate: string, profile: Record<string, un
|
|
|
44
163
|
}>;
|
|
45
164
|
/**
|
|
46
165
|
* Complete setup after email confirmation succeeds.
|
|
47
|
-
*
|
|
166
|
+
*
|
|
167
|
+
* Called when the original tab receives an `AUTH_CONFIRMED` message via
|
|
168
|
+
* BroadcastChannel. At this point, Supabase has confirmed the email and a
|
|
169
|
+
* session should be available. This function caches offline credentials,
|
|
170
|
+
* creates an offline session, and trusts the current device.
|
|
171
|
+
*
|
|
172
|
+
* @returns An object with `error` (string or null).
|
|
173
|
+
*
|
|
174
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
175
|
+
*
|
|
176
|
+
* @see {@link setupSingleUser} for the initial setup that triggers confirmation
|
|
48
177
|
*/
|
|
49
178
|
export declare function completeSingleUserSetup(): Promise<{
|
|
50
179
|
error: string | null;
|
|
51
180
|
}>;
|
|
52
181
|
/**
|
|
53
|
-
* Unlock
|
|
182
|
+
* Unlock (login) the single-user account by verifying the PIN/password.
|
|
183
|
+
*
|
|
184
|
+
* ## Online Flow
|
|
185
|
+
*
|
|
186
|
+
* 1. Pre-check via {@link preCheckLogin} (client-side rate limiting).
|
|
187
|
+
* 2. Authenticate with Supabase `signInWithPassword()`.
|
|
188
|
+
* 3. If device verification is enabled and this device is untrusted, trigger
|
|
189
|
+
* an OTP email and return `deviceVerificationRequired: true`.
|
|
190
|
+
* 4. Otherwise, cache credentials, update offline session, refresh the local
|
|
191
|
+
* gate hash, and set auth state.
|
|
192
|
+
*
|
|
193
|
+
* ## Offline Flow
|
|
194
|
+
*
|
|
195
|
+
* 1. Verify the gate against the locally-stored SHA-256 hash.
|
|
196
|
+
* 2. Attempt to restore a cached Supabase session.
|
|
197
|
+
* 3. If no cached session, create a synthetic offline session.
|
|
198
|
+
*
|
|
199
|
+
* @param gate - The PIN or password entered by the user.
|
|
200
|
+
* @returns An object containing:
|
|
201
|
+
* - `error`: Error message or null on success.
|
|
202
|
+
* - `deviceVerificationRequired`: True if the UI should show OTP verification.
|
|
203
|
+
* - `maskedEmail`: Masked email for display during device verification.
|
|
204
|
+
* - `retryAfterMs`: Milliseconds to wait before retrying (rate-limited).
|
|
54
205
|
*
|
|
55
|
-
*
|
|
206
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* const result = await unlockSingleUser('1234');
|
|
211
|
+
* if (result.error) {
|
|
212
|
+
* showError(result.error);
|
|
213
|
+
* } else if (result.deviceVerificationRequired) {
|
|
214
|
+
* showDeviceVerificationModal(result.maskedEmail);
|
|
215
|
+
* } else {
|
|
216
|
+
* navigateToHome();
|
|
217
|
+
* }
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @see {@link completeDeviceVerification} for finishing the OTP flow
|
|
221
|
+
* @see {@link lockSingleUser} for the reverse operation
|
|
56
222
|
*/
|
|
57
223
|
export declare function unlockSingleUser(gate: string): Promise<{
|
|
58
224
|
error: string | null;
|
|
@@ -61,73 +227,244 @@ export declare function unlockSingleUser(gate: string): Promise<{
|
|
|
61
227
|
retryAfterMs?: number;
|
|
62
228
|
}>;
|
|
63
229
|
/**
|
|
64
|
-
* Complete device verification after OTP email link is clicked.
|
|
65
|
-
*
|
|
230
|
+
* Complete device verification after the OTP email link is clicked.
|
|
231
|
+
*
|
|
232
|
+
* This can be called in two scenarios:
|
|
233
|
+
* 1. **From the confirm page** (with `tokenHash`): Verifies the OTP token,
|
|
234
|
+
* then establishes the session.
|
|
235
|
+
* 2. **From the original tab** (without `tokenHash`): The confirm page has
|
|
236
|
+
* already verified the OTP and sent `AUTH_CONFIRMED` via BroadcastChannel.
|
|
237
|
+
* This function just picks up the now-available session.
|
|
238
|
+
*
|
|
239
|
+
* After verification, the current device is trusted, offline credentials are
|
|
240
|
+
* cached, and auth state is set.
|
|
241
|
+
*
|
|
242
|
+
* @param tokenHash - Optional OTP token hash from the email link URL. If
|
|
243
|
+
* provided, the token is verified against Supabase before proceeding.
|
|
244
|
+
* @returns An object with `error` (string or null).
|
|
245
|
+
*
|
|
246
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
247
|
+
*
|
|
248
|
+
* @see {@link unlockSingleUser} which triggers device verification
|
|
249
|
+
* @see {@link pollDeviceVerification} for polling-based completion
|
|
66
250
|
*/
|
|
67
251
|
export declare function completeDeviceVerification(tokenHash?: string): Promise<{
|
|
68
252
|
error: string | null;
|
|
69
253
|
}>;
|
|
70
254
|
/**
|
|
71
|
-
* Poll whether this device has been trusted
|
|
255
|
+
* Poll whether this device has been trusted after OTP verification.
|
|
256
|
+
*
|
|
257
|
+
* Used by the UI to detect when device verification has been completed on
|
|
258
|
+
* another device (e.g., the user opened the OTP link on their phone). The
|
|
259
|
+
* confirm page calls {@link trustPendingDevice}, which trusts the originating
|
|
260
|
+
* device. Once that happens, this poll returns `true`.
|
|
261
|
+
*
|
|
262
|
+
* Requires an active session — {@link sendDeviceVerification} keeps the
|
|
263
|
+
* session alive specifically for this purpose.
|
|
264
|
+
*
|
|
265
|
+
* @returns `true` if the current device is now trusted, `false` otherwise.
|
|
72
266
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```ts
|
|
269
|
+
* const interval = setInterval(async () => {
|
|
270
|
+
* if (await pollDeviceVerification()) {
|
|
271
|
+
* clearInterval(interval);
|
|
272
|
+
* await completeDeviceVerification();
|
|
273
|
+
* }
|
|
274
|
+
* }, 3000);
|
|
275
|
+
* ```
|
|
76
276
|
*/
|
|
77
277
|
export declare function pollDeviceVerification(): Promise<boolean>;
|
|
78
278
|
/**
|
|
79
|
-
* Lock: stop sync engine
|
|
80
|
-
*
|
|
279
|
+
* Lock the application: stop the sync engine and reset auth state to 'none'.
|
|
280
|
+
*
|
|
281
|
+
* This is a "soft lock" — it does NOT destroy the Supabase session, clear
|
|
282
|
+
* local data, or sign out. The user can unlock again with their PIN without
|
|
283
|
+
* needing network access (if offline credentials are cached).
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```ts
|
|
287
|
+
* await lockSingleUser();
|
|
288
|
+
* navigateToLockScreen();
|
|
289
|
+
* ```
|
|
290
|
+
*
|
|
291
|
+
* @see {@link unlockSingleUser} for the reverse operation
|
|
292
|
+
* @see {@link resetSingleUser} for a full destructive reset
|
|
81
293
|
*/
|
|
82
294
|
export declare function lockSingleUser(): Promise<void>;
|
|
83
295
|
/**
|
|
84
|
-
* Change the gate (
|
|
296
|
+
* Change the gate (PIN/password) for the single-user account.
|
|
297
|
+
*
|
|
298
|
+
* Verifies the old gate before accepting the new one. When online, the
|
|
299
|
+
* password is also updated in Supabase. When offline, only the local hash
|
|
300
|
+
* is updated (Supabase will be out of sync until the next online login).
|
|
301
|
+
*
|
|
302
|
+
* @param oldGate - The current PIN/password for verification.
|
|
303
|
+
* @param newGate - The new PIN/password to set.
|
|
304
|
+
* @returns An object with `error` (string or null).
|
|
305
|
+
*
|
|
306
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
307
|
+
*
|
|
308
|
+
* @security The old gate is verified either via local hash comparison or
|
|
309
|
+
* Supabase `signInWithPassword()` before the change is applied. This
|
|
310
|
+
* prevents unauthorized changes if the device is left unlocked.
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* const result = await changeSingleUserGate('1234', '5678');
|
|
315
|
+
* if (result.error) {
|
|
316
|
+
* showError(result.error);
|
|
317
|
+
* } else {
|
|
318
|
+
* showSuccess('Code changed successfully');
|
|
319
|
+
* }
|
|
320
|
+
* ```
|
|
85
321
|
*/
|
|
86
322
|
export declare function changeSingleUserGate(oldGate: string, newGate: string): Promise<{
|
|
87
323
|
error: string | null;
|
|
88
324
|
}>;
|
|
89
325
|
/**
|
|
90
|
-
* Update profile in IndexedDB and Supabase user_metadata
|
|
326
|
+
* Update the user's profile in both IndexedDB and Supabase `user_metadata`.
|
|
327
|
+
*
|
|
328
|
+
* When online, the profile is pushed to Supabase so it's available on all
|
|
329
|
+
* devices. When offline, only the local config is updated (Supabase will be
|
|
330
|
+
* synced on the next online login via {@link unlockSingleUser}).
|
|
331
|
+
*
|
|
332
|
+
* @param profile - The new profile data to store (replaces the existing profile entirely).
|
|
333
|
+
* @returns An object with `error` (string or null).
|
|
334
|
+
*
|
|
335
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```ts
|
|
339
|
+
* const result = await updateSingleUserProfile({ name: 'Bob', avatar: 'cat' });
|
|
340
|
+
* if (result.error) {
|
|
341
|
+
* showError(result.error);
|
|
342
|
+
* }
|
|
343
|
+
* ```
|
|
91
344
|
*/
|
|
92
345
|
export declare function updateSingleUserProfile(profile: Record<string, unknown>): Promise<{
|
|
93
346
|
error: string | null;
|
|
94
347
|
}>;
|
|
95
348
|
/**
|
|
96
|
-
* Initiate an email change
|
|
97
|
-
*
|
|
349
|
+
* Initiate an email change for the single-user account.
|
|
350
|
+
*
|
|
351
|
+
* Requires an active internet connection. Supabase sends a confirmation email
|
|
352
|
+
* to the new address. The change is not applied until the user clicks the
|
|
353
|
+
* confirmation link and {@link completeSingleUserEmailChange} is called.
|
|
354
|
+
*
|
|
355
|
+
* @param newEmail - The new email address to change to.
|
|
356
|
+
* @returns An object with `error` (string or null) and `confirmationRequired`
|
|
357
|
+
* (true if the caller should show a "check your email" prompt).
|
|
358
|
+
*
|
|
359
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
360
|
+
*
|
|
361
|
+
* @see {@link completeSingleUserEmailChange} for finalizing the change
|
|
98
362
|
*/
|
|
99
363
|
export declare function changeSingleUserEmail(newEmail: string): Promise<{
|
|
100
364
|
error: string | null;
|
|
101
365
|
confirmationRequired: boolean;
|
|
102
366
|
}>;
|
|
103
367
|
/**
|
|
104
|
-
* Complete email change after the user confirms via the email link.
|
|
105
|
-
*
|
|
368
|
+
* Complete an email change after the user confirms via the email link.
|
|
369
|
+
*
|
|
370
|
+
* Called when the original tab receives `AUTH_CONFIRMED` with type
|
|
371
|
+
* `email_change`. Refreshes the Supabase session to pick up the new email,
|
|
372
|
+
* then updates IndexedDB config and offline credentials.
|
|
373
|
+
*
|
|
374
|
+
* @returns An object with `error` (string or null) and `newEmail` (the
|
|
375
|
+
* confirmed new email, or null on error).
|
|
376
|
+
*
|
|
377
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
378
|
+
*
|
|
379
|
+
* @see {@link changeSingleUserEmail} for initiating the change
|
|
106
380
|
*/
|
|
107
381
|
export declare function completeSingleUserEmailChange(): Promise<{
|
|
108
382
|
error: string | null;
|
|
109
383
|
newEmail: string | null;
|
|
110
384
|
}>;
|
|
111
385
|
/**
|
|
112
|
-
* Full reset: clear config, sign out of Supabase, clear all data.
|
|
386
|
+
* Full reset: clear config, sign out of Supabase, and clear all local data.
|
|
387
|
+
*
|
|
388
|
+
* This is a destructive operation that removes the single-user config from
|
|
389
|
+
* IndexedDB and signs out of Supabase (which clears the session and all
|
|
390
|
+
* local auth state). After this, the app returns to the initial setup state.
|
|
391
|
+
*
|
|
392
|
+
* @returns An object with `error` (string or null).
|
|
393
|
+
*
|
|
394
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
395
|
+
*
|
|
396
|
+
* @security This clears auth state but does NOT delete the Supabase user
|
|
397
|
+
* account or any server-side data. Use {@link resetSingleUserRemote} for
|
|
398
|
+
* a full server-side reset.
|
|
399
|
+
*
|
|
400
|
+
* @see {@link resetSingleUserRemote} for server-side account deletion
|
|
113
401
|
*/
|
|
114
402
|
export declare function resetSingleUser(): Promise<{
|
|
115
403
|
error: string | null;
|
|
116
404
|
}>;
|
|
117
405
|
/**
|
|
118
|
-
* Fetch remote gate
|
|
119
|
-
*
|
|
120
|
-
*
|
|
406
|
+
* Fetch remote gate configuration via the `get_extension_config()` Supabase RPC.
|
|
407
|
+
*
|
|
408
|
+
* Returns user info if a user exists in the Supabase project, `null` otherwise.
|
|
409
|
+
* This is used by browser extensions and new devices to discover the existing
|
|
410
|
+
* account before linking. Works without authentication (uses the anon key).
|
|
411
|
+
*
|
|
412
|
+
* @returns An object with `email`, `gateType`, `codeLength`, and `profile`,
|
|
413
|
+
* or `null` if no user exists or the RPC fails.
|
|
414
|
+
*
|
|
415
|
+
* @example
|
|
416
|
+
* ```ts
|
|
417
|
+
* const remote = await fetchRemoteGateConfig();
|
|
418
|
+
* if (remote) {
|
|
419
|
+
* // Account exists — show link-device screen
|
|
420
|
+
* showLinkDeviceScreen(remote.email, remote.gateType);
|
|
421
|
+
* } else {
|
|
422
|
+
* // No account — show setup screen
|
|
423
|
+
* showSetupScreen();
|
|
424
|
+
* }
|
|
425
|
+
* ```
|
|
426
|
+
*
|
|
427
|
+
* @see {@link linkSingleUserDevice} for linking after discovery
|
|
121
428
|
*/
|
|
122
429
|
export declare function fetchRemoteGateConfig(): Promise<{
|
|
430
|
+
/** The user's email address. */
|
|
123
431
|
email: string;
|
|
432
|
+
/** The gate type ('code' or 'password'). */
|
|
124
433
|
gateType: string;
|
|
434
|
+
/** The numeric code length (4 or 6). */
|
|
125
435
|
codeLength: number;
|
|
436
|
+
/** The user's profile metadata. */
|
|
126
437
|
profile: Record<string, unknown>;
|
|
127
438
|
} | null>;
|
|
128
439
|
/**
|
|
129
440
|
* Link a new device to an existing single-user account.
|
|
130
|
-
*
|
|
441
|
+
*
|
|
442
|
+
* Signs in with the provided email and PIN via Supabase `signInWithPassword()`,
|
|
443
|
+
* then builds and stores a local config from the user's `user_metadata`. If
|
|
444
|
+
* device verification is enabled, untrusted devices are challenged with an OTP.
|
|
445
|
+
*
|
|
446
|
+
* This is the multi-device counterpart to {@link setupSingleUser}: setup
|
|
447
|
+
* creates the account, while link joins an existing one from a new device.
|
|
448
|
+
*
|
|
449
|
+
* @param email - The email address of the existing account.
|
|
450
|
+
* @param pin - The PIN/password to authenticate with.
|
|
451
|
+
* @returns An object containing:
|
|
452
|
+
* - `error`: Error message or null on success.
|
|
453
|
+
* - `deviceVerificationRequired`: True if OTP verification is needed.
|
|
454
|
+
* - `maskedEmail`: Masked email for display during device verification.
|
|
455
|
+
* - `retryAfterMs`: Milliseconds to wait before retrying (rate-limited).
|
|
456
|
+
*
|
|
457
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
458
|
+
*
|
|
459
|
+
* @example
|
|
460
|
+
* ```ts
|
|
461
|
+
* const result = await linkSingleUserDevice('alice@example.com', '1234');
|
|
462
|
+
* if (result.deviceVerificationRequired) {
|
|
463
|
+
* showOtpModal(result.maskedEmail);
|
|
464
|
+
* }
|
|
465
|
+
* ```
|
|
466
|
+
*
|
|
467
|
+
* @see {@link fetchRemoteGateConfig} for discovering the account to link to
|
|
131
468
|
*/
|
|
132
469
|
export declare function linkSingleUserDevice(email: string, pin: string): Promise<{
|
|
133
470
|
error: string | null;
|
|
@@ -136,8 +473,24 @@ export declare function linkSingleUserDevice(email: string, pin: string): Promis
|
|
|
136
473
|
retryAfterMs?: number;
|
|
137
474
|
}>;
|
|
138
475
|
/**
|
|
139
|
-
* Reset the remote single
|
|
140
|
-
*
|
|
476
|
+
* Reset the remote single-user account via the `reset_single_user()` Supabase RPC.
|
|
477
|
+
*
|
|
478
|
+
* This is a full destructive reset that:
|
|
479
|
+
* 1. Calls the server-side `reset_single_user()` RPC to delete the user account.
|
|
480
|
+
* 2. Signs out of Supabase to clear the in-memory session.
|
|
481
|
+
* 3. Clears all local IndexedDB state (config, offline credentials, offline session).
|
|
482
|
+
* 4. Removes Supabase session tokens from localStorage.
|
|
483
|
+
*
|
|
484
|
+
* After this, the app returns to its initial un-configured state on all devices.
|
|
485
|
+
*
|
|
486
|
+
* @returns An object with `error` (string or null).
|
|
487
|
+
*
|
|
488
|
+
* @throws Never throws directly; all errors are caught and returned.
|
|
489
|
+
*
|
|
490
|
+
* @security This permanently deletes the Supabase user account. The operation
|
|
491
|
+
* cannot be undone. The RPC should be secured with appropriate RLS policies.
|
|
492
|
+
*
|
|
493
|
+
* @see {@link resetSingleUser} for a local-only reset that preserves the server account
|
|
141
494
|
*/
|
|
142
495
|
export declare function resetSingleUserRemote(): Promise<{
|
|
143
496
|
error: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singleUser.d.ts","sourceRoot":"","sources":["../../src/auth/singleUser.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"singleUser.d.ts","sourceRoot":"","sources":["../../src/auth/singleUser.ts"],"names":[],"mappings":"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"}
|