@prabhask5/stellar-engine 1.0.3
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 +295 -0
- package/dist/actions/remoteChange.d.ts +79 -0
- package/dist/actions/remoteChange.d.ts.map +1 -0
- package/dist/actions/remoteChange.js +300 -0
- package/dist/actions/remoteChange.js.map +1 -0
- package/dist/auth/admin.d.ts +12 -0
- package/dist/auth/admin.d.ts.map +1 -0
- package/dist/auth/admin.js +23 -0
- package/dist/auth/admin.js.map +1 -0
- package/dist/auth/offlineCredentials.d.ts +41 -0
- package/dist/auth/offlineCredentials.d.ts.map +1 -0
- package/dist/auth/offlineCredentials.js +121 -0
- package/dist/auth/offlineCredentials.js.map +1 -0
- package/dist/auth/offlineLogin.d.ts +34 -0
- package/dist/auth/offlineLogin.d.ts.map +1 -0
- package/dist/auth/offlineLogin.js +75 -0
- package/dist/auth/offlineLogin.js.map +1 -0
- package/dist/auth/offlineSession.d.ts +22 -0
- package/dist/auth/offlineSession.d.ts.map +1 -0
- package/dist/auth/offlineSession.js +54 -0
- package/dist/auth/offlineSession.js.map +1 -0
- package/dist/auth/resolveAuthState.d.ts +24 -0
- package/dist/auth/resolveAuthState.d.ts.map +1 -0
- package/dist/auth/resolveAuthState.js +69 -0
- package/dist/auth/resolveAuthState.js.map +1 -0
- package/dist/config.d.ts +53 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -0
- package/dist/conflicts.d.ts +70 -0
- package/dist/conflicts.d.ts.map +1 -0
- package/dist/conflicts.js +321 -0
- package/dist/conflicts.js.map +1 -0
- package/dist/data.d.ts +77 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +360 -0
- package/dist/data.js.map +1 -0
- package/dist/database.d.ts +31 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +51 -0
- package/dist/database.js.map +1 -0
- package/dist/debug.d.ts +11 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +48 -0
- package/dist/debug.js.map +1 -0
- package/dist/deviceId.d.ts +16 -0
- package/dist/deviceId.d.ts.map +1 -0
- package/dist/deviceId.js +48 -0
- package/dist/deviceId.js.map +1 -0
- package/dist/engine.d.ts +14 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +1903 -0
- package/dist/engine.js.map +1 -0
- package/dist/entries/actions.d.ts +2 -0
- package/dist/entries/actions.d.ts.map +1 -0
- package/dist/entries/actions.js +3 -0
- package/dist/entries/actions.js.map +1 -0
- package/dist/entries/auth.d.ts +7 -0
- package/dist/entries/auth.d.ts.map +1 -0
- package/dist/entries/auth.js +6 -0
- package/dist/entries/auth.js.map +1 -0
- package/dist/entries/config.d.ts +3 -0
- package/dist/entries/config.d.ts.map +1 -0
- package/dist/entries/config.js +3 -0
- package/dist/entries/config.js.map +1 -0
- package/dist/entries/stores.d.ts +9 -0
- package/dist/entries/stores.d.ts.map +1 -0
- package/dist/entries/stores.js +9 -0
- package/dist/entries/stores.js.map +1 -0
- package/dist/entries/types.d.ts +11 -0
- package/dist/entries/types.d.ts.map +1 -0
- package/dist/entries/types.js +2 -0
- package/dist/entries/types.js.map +1 -0
- package/dist/entries/utils.d.ts +3 -0
- package/dist/entries/utils.d.ts.map +1 -0
- package/dist/entries/utils.js +4 -0
- package/dist/entries/utils.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/operations.d.ts +73 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +227 -0
- package/dist/operations.js.map +1 -0
- package/dist/queue.d.ts +32 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +377 -0
- package/dist/queue.js.map +1 -0
- package/dist/realtime.d.ts +57 -0
- package/dist/realtime.d.ts.map +1 -0
- package/dist/realtime.js +491 -0
- package/dist/realtime.js.map +1 -0
- package/dist/reconnectHandler.d.ts +16 -0
- package/dist/reconnectHandler.d.ts.map +1 -0
- package/dist/reconnectHandler.js +21 -0
- package/dist/reconnectHandler.js.map +1 -0
- package/dist/runtime/runtimeConfig.d.ts +27 -0
- package/dist/runtime/runtimeConfig.d.ts.map +1 -0
- package/dist/runtime/runtimeConfig.js +133 -0
- package/dist/runtime/runtimeConfig.js.map +1 -0
- package/dist/stores/authState.d.ts +57 -0
- package/dist/stores/authState.d.ts.map +1 -0
- package/dist/stores/authState.js +154 -0
- package/dist/stores/authState.js.map +1 -0
- package/dist/stores/network.d.ts +9 -0
- package/dist/stores/network.d.ts.map +1 -0
- package/dist/stores/network.js +97 -0
- package/dist/stores/network.js.map +1 -0
- package/dist/stores/remoteChanges.d.ts +142 -0
- package/dist/stores/remoteChanges.d.ts.map +1 -0
- package/dist/stores/remoteChanges.js +353 -0
- package/dist/stores/remoteChanges.js.map +1 -0
- package/dist/stores/sync.d.ts +35 -0
- package/dist/stores/sync.d.ts.map +1 -0
- package/dist/stores/sync.js +115 -0
- package/dist/stores/sync.js.map +1 -0
- package/dist/supabase/auth.d.ts +60 -0
- package/dist/supabase/auth.d.ts.map +1 -0
- package/dist/supabase/auth.js +298 -0
- package/dist/supabase/auth.js.map +1 -0
- package/dist/supabase/client.d.ts +15 -0
- package/dist/supabase/client.d.ts.map +1 -0
- package/dist/supabase/client.js +149 -0
- package/dist/supabase/client.js.map +1 -0
- package/dist/supabase/validate.d.ts +11 -0
- package/dist/supabase/validate.d.ts.map +1 -0
- package/dist/supabase/validate.js +38 -0
- package/dist/supabase/validate.js.map +1 -0
- package/dist/types.d.ts +78 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +24 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +56 -0
- package/dist/utils.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { supabase } from './client';
|
|
2
|
+
import { cacheOfflineCredentials, clearOfflineCredentials, updateOfflineCredentialsPassword, updateOfflineCredentialsProfile } from '../auth/offlineCredentials';
|
|
3
|
+
import { clearOfflineSession } from '../auth/offlineSession';
|
|
4
|
+
import { debugWarn, debugError } from '../debug';
|
|
5
|
+
import { getEngineConfig } from '../config';
|
|
6
|
+
import { syncStatusStore } from '../stores/sync';
|
|
7
|
+
import { authState } from '../stores/authState';
|
|
8
|
+
/**
|
|
9
|
+
* Get the email confirmation redirect URL
|
|
10
|
+
* Points to /confirm page which handles the token verification
|
|
11
|
+
*/
|
|
12
|
+
function getConfirmRedirectUrl() {
|
|
13
|
+
if (typeof window !== 'undefined') {
|
|
14
|
+
const path = getEngineConfig().auth?.confirmRedirectPath || '/confirm';
|
|
15
|
+
return `${window.location.origin}${path}`;
|
|
16
|
+
}
|
|
17
|
+
// Fallback for SSR (shouldn't be called, but just in case)
|
|
18
|
+
return '/confirm';
|
|
19
|
+
}
|
|
20
|
+
export async function signIn(email, password) {
|
|
21
|
+
const { data, error } = await supabase.auth.signInWithPassword({
|
|
22
|
+
email,
|
|
23
|
+
password
|
|
24
|
+
});
|
|
25
|
+
// Cache credentials for offline use on successful login
|
|
26
|
+
if (!error && data.session && data.user) {
|
|
27
|
+
try {
|
|
28
|
+
await cacheOfflineCredentials(email, password, data.user, data.session);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
// Don't fail login if credential caching fails
|
|
32
|
+
debugError('[Auth] Failed to cache offline credentials:', e);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
user: data.user,
|
|
37
|
+
session: data.session,
|
|
38
|
+
error: error?.message || null
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export async function signUp(email, password, profileData) {
|
|
42
|
+
const config = getEngineConfig();
|
|
43
|
+
const metadata = config.auth?.profileToMetadata
|
|
44
|
+
? config.auth.profileToMetadata(profileData)
|
|
45
|
+
: profileData;
|
|
46
|
+
const { data, error } = await supabase.auth.signUp({
|
|
47
|
+
email,
|
|
48
|
+
password,
|
|
49
|
+
options: {
|
|
50
|
+
emailRedirectTo: getConfirmRedirectUrl(),
|
|
51
|
+
data: metadata
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
user: data.user,
|
|
56
|
+
session: data.session,
|
|
57
|
+
error: error?.message || null
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export async function signOut(options) {
|
|
61
|
+
// 1. Stop sync engine (import dynamically to avoid circular deps)
|
|
62
|
+
try {
|
|
63
|
+
const { stopSyncEngine, clearLocalCache, clearPendingSyncQueue } = await import('../engine');
|
|
64
|
+
await stopSyncEngine();
|
|
65
|
+
if (!options?.preserveLocalData) {
|
|
66
|
+
// 2. Clear pending sync queue
|
|
67
|
+
await clearPendingSyncQueue();
|
|
68
|
+
// 3. Clear local cache
|
|
69
|
+
await clearLocalCache();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
debugError('[Auth] Failed to stop engine/clear data:', e);
|
|
74
|
+
}
|
|
75
|
+
// 4. Clear offline session
|
|
76
|
+
try {
|
|
77
|
+
await clearOfflineSession();
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
debugError('[Auth] Failed to clear offline session:', e);
|
|
81
|
+
}
|
|
82
|
+
// 5. Clear offline credentials (only if online, for offline re-login preservation)
|
|
83
|
+
try {
|
|
84
|
+
if (!options?.preserveOfflineCredentials) {
|
|
85
|
+
const isOnline = typeof navigator !== 'undefined' && navigator.onLine;
|
|
86
|
+
if (isOnline) {
|
|
87
|
+
await clearOfflineCredentials();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
debugError('[Auth] Failed to clear offline credentials:', e);
|
|
93
|
+
}
|
|
94
|
+
// 6. Supabase auth signOut
|
|
95
|
+
const { error } = await supabase.auth.signOut();
|
|
96
|
+
// 7. Clear sb-* localStorage keys
|
|
97
|
+
try {
|
|
98
|
+
if (typeof localStorage !== 'undefined') {
|
|
99
|
+
const keys = Object.keys(localStorage).filter((k) => k.startsWith('sb-'));
|
|
100
|
+
keys.forEach((k) => localStorage.removeItem(k));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Ignore storage errors
|
|
105
|
+
}
|
|
106
|
+
// 8. Reset sync status store
|
|
107
|
+
syncStatusStore.reset();
|
|
108
|
+
// 9. Reset auth state store
|
|
109
|
+
authState.reset();
|
|
110
|
+
return { error: error?.message || null };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get current Supabase session
|
|
114
|
+
* When offline, returns the cached session from localStorage even if expired
|
|
115
|
+
* (the caller should handle offline mode appropriately)
|
|
116
|
+
*/
|
|
117
|
+
export async function getSession() {
|
|
118
|
+
const isOffline = typeof navigator !== 'undefined' && !navigator.onLine;
|
|
119
|
+
try {
|
|
120
|
+
const { data, error } = await supabase.auth.getSession();
|
|
121
|
+
if (error) {
|
|
122
|
+
debugError('[Auth] getSession error:', error.message);
|
|
123
|
+
// If offline and we got an error, don't clear session - it might just be a network issue
|
|
124
|
+
if (isOffline) {
|
|
125
|
+
debugWarn('[Auth] Offline - keeping session despite error');
|
|
126
|
+
// Try to get session from localStorage directly
|
|
127
|
+
return getSessionFromStorage();
|
|
128
|
+
}
|
|
129
|
+
// If session retrieval fails online, it might be corrupted - try to sign out to clear it
|
|
130
|
+
if (error.message?.includes('hash') || error.message?.includes('undefined')) {
|
|
131
|
+
debugWarn('[Auth] Detected corrupted session, attempting to clear');
|
|
132
|
+
await supabase.auth.signOut();
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return data.session;
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
debugError('[Auth] Unexpected error getting session:', e);
|
|
140
|
+
// If offline, don't clear anything - try to get from storage
|
|
141
|
+
if (isOffline) {
|
|
142
|
+
debugWarn('[Auth] Offline - attempting to get session from storage');
|
|
143
|
+
return getSessionFromStorage();
|
|
144
|
+
}
|
|
145
|
+
// Attempt to clear any corrupted state when online
|
|
146
|
+
try {
|
|
147
|
+
await supabase.auth.signOut();
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Ignore signOut errors
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get session directly from localStorage (for offline scenarios)
|
|
157
|
+
* This bypasses Supabase's token refresh logic
|
|
158
|
+
*/
|
|
159
|
+
function getSessionFromStorage() {
|
|
160
|
+
try {
|
|
161
|
+
// Supabase stores session in localStorage with key pattern: sb-{project-ref}-auth-token
|
|
162
|
+
const keys = Object.keys(localStorage);
|
|
163
|
+
const sessionKey = keys.find((k) => k.includes('-auth-token'));
|
|
164
|
+
if (!sessionKey)
|
|
165
|
+
return null;
|
|
166
|
+
const stored = localStorage.getItem(sessionKey);
|
|
167
|
+
if (!stored)
|
|
168
|
+
return null;
|
|
169
|
+
const parsed = JSON.parse(stored);
|
|
170
|
+
if (parsed?.currentSession) {
|
|
171
|
+
return parsed.currentSession;
|
|
172
|
+
}
|
|
173
|
+
// Newer Supabase versions use different structure
|
|
174
|
+
if (parsed?.session) {
|
|
175
|
+
return parsed.session;
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
catch (e) {
|
|
180
|
+
debugError('[Auth] Failed to get session from storage:', e);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check if a session's access token is expired
|
|
186
|
+
*/
|
|
187
|
+
export function isSessionExpired(session) {
|
|
188
|
+
if (!session)
|
|
189
|
+
return true;
|
|
190
|
+
// expires_at is in seconds
|
|
191
|
+
const expiresAt = session.expires_at;
|
|
192
|
+
if (!expiresAt)
|
|
193
|
+
return true;
|
|
194
|
+
return Date.now() / 1000 > expiresAt;
|
|
195
|
+
}
|
|
196
|
+
export function getUserProfile(user) {
|
|
197
|
+
const config = getEngineConfig();
|
|
198
|
+
if (config.auth?.profileExtractor && user) {
|
|
199
|
+
return config.auth.profileExtractor(user.user_metadata || {});
|
|
200
|
+
}
|
|
201
|
+
return user?.user_metadata || {};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Update user profile
|
|
205
|
+
* Also updates cached offline credentials
|
|
206
|
+
*/
|
|
207
|
+
export async function updateProfile(profile) {
|
|
208
|
+
const config = getEngineConfig();
|
|
209
|
+
const metadata = config.auth?.profileToMetadata
|
|
210
|
+
? config.auth.profileToMetadata(profile)
|
|
211
|
+
: profile;
|
|
212
|
+
const { error } = await supabase.auth.updateUser({
|
|
213
|
+
data: metadata
|
|
214
|
+
});
|
|
215
|
+
if (!error) {
|
|
216
|
+
// Update offline cache
|
|
217
|
+
try {
|
|
218
|
+
await updateOfflineCredentialsProfile(profile);
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
debugError('[Auth] Failed to update offline profile:', e);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return { error: error?.message || null };
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Change user password
|
|
228
|
+
* Verifies current password first, then updates
|
|
229
|
+
* Also updates cached offline credentials
|
|
230
|
+
*/
|
|
231
|
+
export async function changePassword(currentPassword, newPassword) {
|
|
232
|
+
// Get current user email from session
|
|
233
|
+
const { data: { session } } = await supabase.auth.getSession();
|
|
234
|
+
const user = session?.user;
|
|
235
|
+
if (!user?.email) {
|
|
236
|
+
return { error: 'No authenticated user found' };
|
|
237
|
+
}
|
|
238
|
+
// Verify current password by attempting to sign in
|
|
239
|
+
const { error: verifyError } = await supabase.auth.signInWithPassword({
|
|
240
|
+
email: user.email,
|
|
241
|
+
password: currentPassword
|
|
242
|
+
});
|
|
243
|
+
if (verifyError) {
|
|
244
|
+
return { error: 'Current password is incorrect' };
|
|
245
|
+
}
|
|
246
|
+
// Update password
|
|
247
|
+
const { error } = await supabase.auth.updateUser({
|
|
248
|
+
password: newPassword
|
|
249
|
+
});
|
|
250
|
+
if (!error) {
|
|
251
|
+
// Update offline cache with new password
|
|
252
|
+
try {
|
|
253
|
+
await updateOfflineCredentialsPassword(newPassword);
|
|
254
|
+
}
|
|
255
|
+
catch (e) {
|
|
256
|
+
debugError('[Auth] Failed to update offline password:', e);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { error: error?.message || null };
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Resend confirmation email for signup
|
|
263
|
+
* Should be rate-limited on the client side (30 second cooldown)
|
|
264
|
+
*/
|
|
265
|
+
export async function resendConfirmationEmail(email) {
|
|
266
|
+
const { error } = await supabase.auth.resend({
|
|
267
|
+
type: 'signup',
|
|
268
|
+
email,
|
|
269
|
+
options: {
|
|
270
|
+
emailRedirectTo: getConfirmRedirectUrl()
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
return { error: error?.message || null };
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Verify OTP token (for email confirmation).
|
|
277
|
+
* Absorbs confirm page's direct Supabase call.
|
|
278
|
+
*/
|
|
279
|
+
export async function verifyOtp(tokenHash, type) {
|
|
280
|
+
const { error } = await supabase.auth.verifyOtp({
|
|
281
|
+
token_hash: tokenHash,
|
|
282
|
+
type
|
|
283
|
+
});
|
|
284
|
+
return { error: error?.message || null };
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Get a valid (non-expired) session, or null.
|
|
288
|
+
* Merges getSession() + isSessionExpired() into a single call.
|
|
289
|
+
*/
|
|
290
|
+
export async function getValidSession() {
|
|
291
|
+
const session = await getSession();
|
|
292
|
+
if (!session)
|
|
293
|
+
return null;
|
|
294
|
+
if (isSessionExpired(session))
|
|
295
|
+
return null;
|
|
296
|
+
return session;
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/supabase/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Client - Lazy Initialization via Proxy
|
|
3
|
+
*
|
|
4
|
+
* Uses runtime config instead of build-time $env/static/public.
|
|
5
|
+
* The Proxy pattern preserves the exact same API surface.
|
|
6
|
+
*/
|
|
7
|
+
import { type SupabaseClient } from '@supabase/supabase-js';
|
|
8
|
+
export declare function _setClientPrefix(prefix: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Proxy-based lazy singleton.
|
|
11
|
+
* Delegates all property access to the real SupabaseClient,
|
|
12
|
+
* which is created on first access using getConfig().
|
|
13
|
+
*/
|
|
14
|
+
export declare const supabase: SupabaseClient;
|
|
15
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/supabase/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAM1E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,QAE9C;AA4ID;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,cASrB,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Client - Lazy Initialization via Proxy
|
|
3
|
+
*
|
|
4
|
+
* Uses runtime config instead of build-time $env/static/public.
|
|
5
|
+
* The Proxy pattern preserves the exact same API surface.
|
|
6
|
+
*/
|
|
7
|
+
import { createClient } from '@supabase/supabase-js';
|
|
8
|
+
import { getConfig } from '../runtime/runtimeConfig';
|
|
9
|
+
import { debugLog, debugWarn, debugError } from '../debug';
|
|
10
|
+
let _prefix = 'stellar';
|
|
11
|
+
export function _setClientPrefix(prefix) {
|
|
12
|
+
_prefix = prefix;
|
|
13
|
+
}
|
|
14
|
+
// Clear corrupted Supabase auth data from localStorage if it exists
|
|
15
|
+
// This prevents "can't access property 'hash'" errors during initialization
|
|
16
|
+
function clearCorruptedAuthData() {
|
|
17
|
+
if (typeof localStorage === 'undefined')
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
// Supabase stores auth data with keys starting with 'sb-'
|
|
21
|
+
const keysToCheck = Object.keys(localStorage).filter((key) => key.startsWith('sb-'));
|
|
22
|
+
for (const key of keysToCheck) {
|
|
23
|
+
const value = localStorage.getItem(key);
|
|
24
|
+
if (value) {
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(value);
|
|
27
|
+
// Validate the parsed data has expected structure
|
|
28
|
+
if (parsed && typeof parsed === 'object') {
|
|
29
|
+
// Check for signs of corruption
|
|
30
|
+
const hasCorruptedSession =
|
|
31
|
+
// currentSession exists but missing required fields
|
|
32
|
+
(parsed.currentSession && typeof parsed.currentSession !== 'object') ||
|
|
33
|
+
// access_token exists but is not a string
|
|
34
|
+
(parsed.access_token !== undefined && typeof parsed.access_token !== 'string') ||
|
|
35
|
+
// expires_at exists but is not a number
|
|
36
|
+
(parsed.expires_at !== undefined && typeof parsed.expires_at !== 'number');
|
|
37
|
+
if (hasCorruptedSession) {
|
|
38
|
+
debugWarn('[Auth] Clearing corrupted session data:', key);
|
|
39
|
+
localStorage.removeItem(key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// JSON parse failed - data is corrupted
|
|
45
|
+
debugWarn('[Auth] Clearing malformed session data:', key);
|
|
46
|
+
localStorage.removeItem(key);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
debugError('[Auth] Error checking localStorage:', e);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Add global handler for unhandled Supabase auth errors
|
|
56
|
+
if (typeof window !== 'undefined') {
|
|
57
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
58
|
+
const reason = event.reason;
|
|
59
|
+
// Check if this is a Supabase auth error
|
|
60
|
+
if (reason && typeof reason === 'object' && 'message' in reason) {
|
|
61
|
+
const message = String(reason.message || '');
|
|
62
|
+
if (message.includes('hash') || message.includes("can't access property")) {
|
|
63
|
+
debugWarn('[Auth] Caught unhandled auth error, clearing storage');
|
|
64
|
+
event.preventDefault(); // Prevent the error from showing in console
|
|
65
|
+
// Clear Supabase storage
|
|
66
|
+
try {
|
|
67
|
+
const keys = Object.keys(localStorage).filter((k) => k.startsWith('sb-'));
|
|
68
|
+
keys.forEach((k) => localStorage.removeItem(k));
|
|
69
|
+
// Reload the page to get a fresh state
|
|
70
|
+
window.location.reload();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Ignore storage errors
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// Run cleanup before creating client
|
|
80
|
+
clearCorruptedAuthData();
|
|
81
|
+
// Detect if running as iOS PWA (standalone mode)
|
|
82
|
+
const isIOSPWA = typeof window !== 'undefined' &&
|
|
83
|
+
// @ts-expect-error - navigator.standalone is iOS-specific
|
|
84
|
+
(window.navigator.standalone === true || window.matchMedia('(display-mode: standalone)').matches);
|
|
85
|
+
if (isIOSPWA) {
|
|
86
|
+
debugLog('[Auth] Running as iOS PWA - using enhanced auth persistence');
|
|
87
|
+
}
|
|
88
|
+
// Lazy singleton: actual client is created on first access
|
|
89
|
+
let realClient = null;
|
|
90
|
+
function getOrCreateClient() {
|
|
91
|
+
if (realClient)
|
|
92
|
+
return realClient;
|
|
93
|
+
const config = getConfig();
|
|
94
|
+
const url = config?.supabaseUrl || 'https://placeholder.supabase.co';
|
|
95
|
+
const key = config?.supabaseAnonKey || 'placeholder';
|
|
96
|
+
if (!config) {
|
|
97
|
+
debugWarn('Supabase config not loaded yet. Call initConfig() before using supabase client.');
|
|
98
|
+
}
|
|
99
|
+
realClient = createClient(url, key, {
|
|
100
|
+
auth: {
|
|
101
|
+
// Use localStorage for persistence (default, but explicit for clarity)
|
|
102
|
+
persistSession: true,
|
|
103
|
+
// Auto-refresh tokens before they expire
|
|
104
|
+
autoRefreshToken: true,
|
|
105
|
+
// Detect session from URL (for OAuth redirects)
|
|
106
|
+
detectSessionInUrl: true,
|
|
107
|
+
// Storage key prefix
|
|
108
|
+
storageKey: `${_prefix}-auth`,
|
|
109
|
+
// Flow type - PKCE is more secure and works better with PWAs
|
|
110
|
+
flowType: 'pkce'
|
|
111
|
+
},
|
|
112
|
+
global: {
|
|
113
|
+
// Add custom headers to help debug PWA issues
|
|
114
|
+
headers: {
|
|
115
|
+
'x-client-info': isIOSPWA ? `${_prefix}-ios-pwa` : `${_prefix}-web`
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// Set up auth state change listener to log auth events (helps debug PWA issues)
|
|
120
|
+
if (typeof window !== 'undefined') {
|
|
121
|
+
realClient.auth.onAuthStateChange((event, session) => {
|
|
122
|
+
debugLog(`[Auth] State change: ${event}`, session ? `User: ${session.user?.id}` : 'No session');
|
|
123
|
+
// If session is lost unexpectedly, this helps identify the issue
|
|
124
|
+
if (event === 'SIGNED_OUT' && isIOSPWA) {
|
|
125
|
+
debugWarn('[Auth] Signed out on iOS PWA - session may have been evicted');
|
|
126
|
+
}
|
|
127
|
+
if (event === 'TOKEN_REFRESHED') {
|
|
128
|
+
debugLog('[Auth] Token refreshed successfully');
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return realClient;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Proxy-based lazy singleton.
|
|
136
|
+
* Delegates all property access to the real SupabaseClient,
|
|
137
|
+
* which is created on first access using getConfig().
|
|
138
|
+
*/
|
|
139
|
+
export const supabase = new Proxy({}, {
|
|
140
|
+
get(_target, prop, receiver) {
|
|
141
|
+
const client = getOrCreateClient();
|
|
142
|
+
const value = Reflect.get(client, prop, receiver);
|
|
143
|
+
if (typeof value === 'function') {
|
|
144
|
+
return value.bind(client);
|
|
145
|
+
}
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/supabase/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Credential Validation
|
|
3
|
+
*
|
|
4
|
+
* Tests connectivity to a Supabase project using provided credentials.
|
|
5
|
+
* Used during setup flows to verify user-inputted URL and anon key.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateSupabaseCredentials(url: string, anonKey: string): Promise<{
|
|
8
|
+
valid: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/supabase/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA+B7C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Credential Validation
|
|
3
|
+
*
|
|
4
|
+
* Tests connectivity to a Supabase project using provided credentials.
|
|
5
|
+
* Used during setup flows to verify user-inputted URL and anon key.
|
|
6
|
+
*/
|
|
7
|
+
import { createClient } from '@supabase/supabase-js';
|
|
8
|
+
export async function validateSupabaseCredentials(url, anonKey) {
|
|
9
|
+
try {
|
|
10
|
+
new URL(url);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return { valid: false, error: 'Invalid Supabase URL format' };
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const tempClient = createClient(url, anonKey);
|
|
17
|
+
// Test REST API reachability by attempting a simple query
|
|
18
|
+
const { error } = await tempClient.from('focus_sessions').select('id').limit(1);
|
|
19
|
+
if (error) {
|
|
20
|
+
// Bad credentials
|
|
21
|
+
if (error.message?.includes('Invalid API key') || error.code === 'PGRST301') {
|
|
22
|
+
return { valid: false, error: 'Invalid Supabase credentials. Check your URL and Anon Key.' };
|
|
23
|
+
}
|
|
24
|
+
// Table doesn't exist but API is reachable — credentials work, schema not set up yet
|
|
25
|
+
if (error.message?.includes('relation') && error.message?.includes('does not exist')) {
|
|
26
|
+
return { valid: true };
|
|
27
|
+
}
|
|
28
|
+
// Any other error
|
|
29
|
+
return { valid: false, error: `Supabase responded with an error: ${error.message}` };
|
|
30
|
+
}
|
|
31
|
+
return { valid: true };
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
const message = e instanceof Error ? e.message : 'Unknown error';
|
|
35
|
+
return { valid: false, error: `Could not connect to Supabase: ${message}` };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/supabase/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,GAAW,EACX,OAAe;IAEf,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC;IAChE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAE9C,0DAA0D;QAC1D,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEhF,IAAI,KAAK,EAAE,CAAC;YACV,kBAAkB;YAClB,IAAI,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC5E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,4DAA4D,EAAE,CAAC;YAC/F,CAAC;YACD,qFAAqF;YACrF,IAAI,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACrF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACzB,CAAC;YACD,kBAAkB;YAClB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,qCAAqC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QACvF,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACjE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,OAAO,EAAE,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent-Based Sync Operation Types
|
|
3
|
+
*
|
|
4
|
+
* These types enable preserving operation intent (e.g., "increment by 1")
|
|
5
|
+
* rather than just final state (e.g., "current_value: 50").
|
|
6
|
+
*
|
|
7
|
+
* Benefits:
|
|
8
|
+
* - Rapid increments are coalesced locally (50 +1s -> single +50) reducing sync traffic
|
|
9
|
+
* - Pending operations are protected during conflict resolution
|
|
10
|
+
*
|
|
11
|
+
* Note: True numeric merge across devices (e.g., +50 + +30 = +80) is not implemented.
|
|
12
|
+
* Operations are converted to final values before pushing to Supabase, so conflicts
|
|
13
|
+
* use last-write-wins. Full numeric merge would require an operation inbox system.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Operation types that preserve intent:
|
|
17
|
+
* - 'increment': Add delta to numeric field (e.g., current_value += 1)
|
|
18
|
+
* - 'set': Set field to value (works for any type)
|
|
19
|
+
* - 'create': Create new entity
|
|
20
|
+
* - 'delete': Soft delete entity
|
|
21
|
+
*/
|
|
22
|
+
export type OperationType = 'increment' | 'set' | 'create' | 'delete';
|
|
23
|
+
/**
|
|
24
|
+
* Intent-based sync operation item.
|
|
25
|
+
*
|
|
26
|
+
* Key design:
|
|
27
|
+
* - Uses `operationType` to specify the operation intent
|
|
28
|
+
* - Has optional `field` for field-level operations
|
|
29
|
+
* - `value` is the delta (for increment) or new value (for set/create)
|
|
30
|
+
*
|
|
31
|
+
* For create operations, value contains the full entity payload.
|
|
32
|
+
* For increment operations, value contains the delta to add.
|
|
33
|
+
* For set operations, value contains the new field value(s).
|
|
34
|
+
* For delete operations, value is not used.
|
|
35
|
+
*/
|
|
36
|
+
export interface SyncOperationItem {
|
|
37
|
+
id?: number;
|
|
38
|
+
table: string;
|
|
39
|
+
entityId: string;
|
|
40
|
+
operationType: OperationType;
|
|
41
|
+
field?: string;
|
|
42
|
+
value?: unknown;
|
|
43
|
+
timestamp: string;
|
|
44
|
+
retries: number;
|
|
45
|
+
}
|
|
46
|
+
export interface OfflineCredentials {
|
|
47
|
+
id: string;
|
|
48
|
+
userId: string;
|
|
49
|
+
email: string;
|
|
50
|
+
password: string;
|
|
51
|
+
profile: Record<string, unknown>;
|
|
52
|
+
cachedAt: string;
|
|
53
|
+
}
|
|
54
|
+
export interface OfflineSession {
|
|
55
|
+
id: string;
|
|
56
|
+
userId: string;
|
|
57
|
+
offlineToken: string;
|
|
58
|
+
createdAt: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Conflict history entry (stored in IndexedDB)
|
|
62
|
+
* Records field-level conflict resolutions for review and potential undo
|
|
63
|
+
*/
|
|
64
|
+
export interface ConflictHistoryEntry {
|
|
65
|
+
id?: number;
|
|
66
|
+
entityId: string;
|
|
67
|
+
entityType: string;
|
|
68
|
+
field: string;
|
|
69
|
+
localValue: unknown;
|
|
70
|
+
remoteValue: unknown;
|
|
71
|
+
resolvedValue: unknown;
|
|
72
|
+
winner: 'local' | 'remote' | 'merged';
|
|
73
|
+
strategy: string;
|
|
74
|
+
timestamp: string;
|
|
75
|
+
}
|
|
76
|
+
export type SyncStatus = 'idle' | 'syncing' | 'error' | 'offline';
|
|
77
|
+
export type AuthMode = 'supabase' | 'offline' | 'none';
|
|
78
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEtE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CAGnB;AAMD;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAElE,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent-Based Sync Operation Types
|
|
3
|
+
*
|
|
4
|
+
* These types enable preserving operation intent (e.g., "increment by 1")
|
|
5
|
+
* rather than just final state (e.g., "current_value: 50").
|
|
6
|
+
*
|
|
7
|
+
* Benefits:
|
|
8
|
+
* - Rapid increments are coalesced locally (50 +1s -> single +50) reducing sync traffic
|
|
9
|
+
* - Pending operations are protected during conflict resolution
|
|
10
|
+
*
|
|
11
|
+
* Note: True numeric merge across devices (e.g., +50 + +30 = +80) is not implemented.
|
|
12
|
+
* Operations are converted to final values before pushing to Supabase, so conflicts
|
|
13
|
+
* use last-write-wins. Full numeric merge would require an operation inbox system.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|