@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.
Files changed (138) hide show
  1. package/README.md +295 -0
  2. package/dist/actions/remoteChange.d.ts +79 -0
  3. package/dist/actions/remoteChange.d.ts.map +1 -0
  4. package/dist/actions/remoteChange.js +300 -0
  5. package/dist/actions/remoteChange.js.map +1 -0
  6. package/dist/auth/admin.d.ts +12 -0
  7. package/dist/auth/admin.d.ts.map +1 -0
  8. package/dist/auth/admin.js +23 -0
  9. package/dist/auth/admin.js.map +1 -0
  10. package/dist/auth/offlineCredentials.d.ts +41 -0
  11. package/dist/auth/offlineCredentials.d.ts.map +1 -0
  12. package/dist/auth/offlineCredentials.js +121 -0
  13. package/dist/auth/offlineCredentials.js.map +1 -0
  14. package/dist/auth/offlineLogin.d.ts +34 -0
  15. package/dist/auth/offlineLogin.d.ts.map +1 -0
  16. package/dist/auth/offlineLogin.js +75 -0
  17. package/dist/auth/offlineLogin.js.map +1 -0
  18. package/dist/auth/offlineSession.d.ts +22 -0
  19. package/dist/auth/offlineSession.d.ts.map +1 -0
  20. package/dist/auth/offlineSession.js +54 -0
  21. package/dist/auth/offlineSession.js.map +1 -0
  22. package/dist/auth/resolveAuthState.d.ts +24 -0
  23. package/dist/auth/resolveAuthState.d.ts.map +1 -0
  24. package/dist/auth/resolveAuthState.js +69 -0
  25. package/dist/auth/resolveAuthState.js.map +1 -0
  26. package/dist/config.d.ts +53 -0
  27. package/dist/config.d.ts.map +1 -0
  28. package/dist/config.js +55 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/conflicts.d.ts +70 -0
  31. package/dist/conflicts.d.ts.map +1 -0
  32. package/dist/conflicts.js +321 -0
  33. package/dist/conflicts.js.map +1 -0
  34. package/dist/data.d.ts +77 -0
  35. package/dist/data.d.ts.map +1 -0
  36. package/dist/data.js +360 -0
  37. package/dist/data.js.map +1 -0
  38. package/dist/database.d.ts +31 -0
  39. package/dist/database.d.ts.map +1 -0
  40. package/dist/database.js +51 -0
  41. package/dist/database.js.map +1 -0
  42. package/dist/debug.d.ts +11 -0
  43. package/dist/debug.d.ts.map +1 -0
  44. package/dist/debug.js +48 -0
  45. package/dist/debug.js.map +1 -0
  46. package/dist/deviceId.d.ts +16 -0
  47. package/dist/deviceId.d.ts.map +1 -0
  48. package/dist/deviceId.js +48 -0
  49. package/dist/deviceId.js.map +1 -0
  50. package/dist/engine.d.ts +14 -0
  51. package/dist/engine.d.ts.map +1 -0
  52. package/dist/engine.js +1903 -0
  53. package/dist/engine.js.map +1 -0
  54. package/dist/entries/actions.d.ts +2 -0
  55. package/dist/entries/actions.d.ts.map +1 -0
  56. package/dist/entries/actions.js +3 -0
  57. package/dist/entries/actions.js.map +1 -0
  58. package/dist/entries/auth.d.ts +7 -0
  59. package/dist/entries/auth.d.ts.map +1 -0
  60. package/dist/entries/auth.js +6 -0
  61. package/dist/entries/auth.js.map +1 -0
  62. package/dist/entries/config.d.ts +3 -0
  63. package/dist/entries/config.d.ts.map +1 -0
  64. package/dist/entries/config.js +3 -0
  65. package/dist/entries/config.js.map +1 -0
  66. package/dist/entries/stores.d.ts +9 -0
  67. package/dist/entries/stores.d.ts.map +1 -0
  68. package/dist/entries/stores.js +9 -0
  69. package/dist/entries/stores.js.map +1 -0
  70. package/dist/entries/types.d.ts +11 -0
  71. package/dist/entries/types.d.ts.map +1 -0
  72. package/dist/entries/types.js +2 -0
  73. package/dist/entries/types.js.map +1 -0
  74. package/dist/entries/utils.d.ts +3 -0
  75. package/dist/entries/utils.d.ts.map +1 -0
  76. package/dist/entries/utils.js +4 -0
  77. package/dist/entries/utils.js.map +1 -0
  78. package/dist/index.d.ts +32 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +39 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/operations.d.ts +73 -0
  83. package/dist/operations.d.ts.map +1 -0
  84. package/dist/operations.js +227 -0
  85. package/dist/operations.js.map +1 -0
  86. package/dist/queue.d.ts +32 -0
  87. package/dist/queue.d.ts.map +1 -0
  88. package/dist/queue.js +377 -0
  89. package/dist/queue.js.map +1 -0
  90. package/dist/realtime.d.ts +57 -0
  91. package/dist/realtime.d.ts.map +1 -0
  92. package/dist/realtime.js +491 -0
  93. package/dist/realtime.js.map +1 -0
  94. package/dist/reconnectHandler.d.ts +16 -0
  95. package/dist/reconnectHandler.d.ts.map +1 -0
  96. package/dist/reconnectHandler.js +21 -0
  97. package/dist/reconnectHandler.js.map +1 -0
  98. package/dist/runtime/runtimeConfig.d.ts +27 -0
  99. package/dist/runtime/runtimeConfig.d.ts.map +1 -0
  100. package/dist/runtime/runtimeConfig.js +133 -0
  101. package/dist/runtime/runtimeConfig.js.map +1 -0
  102. package/dist/stores/authState.d.ts +57 -0
  103. package/dist/stores/authState.d.ts.map +1 -0
  104. package/dist/stores/authState.js +154 -0
  105. package/dist/stores/authState.js.map +1 -0
  106. package/dist/stores/network.d.ts +9 -0
  107. package/dist/stores/network.d.ts.map +1 -0
  108. package/dist/stores/network.js +97 -0
  109. package/dist/stores/network.js.map +1 -0
  110. package/dist/stores/remoteChanges.d.ts +142 -0
  111. package/dist/stores/remoteChanges.d.ts.map +1 -0
  112. package/dist/stores/remoteChanges.js +353 -0
  113. package/dist/stores/remoteChanges.js.map +1 -0
  114. package/dist/stores/sync.d.ts +35 -0
  115. package/dist/stores/sync.d.ts.map +1 -0
  116. package/dist/stores/sync.js +115 -0
  117. package/dist/stores/sync.js.map +1 -0
  118. package/dist/supabase/auth.d.ts +60 -0
  119. package/dist/supabase/auth.d.ts.map +1 -0
  120. package/dist/supabase/auth.js +298 -0
  121. package/dist/supabase/auth.js.map +1 -0
  122. package/dist/supabase/client.d.ts +15 -0
  123. package/dist/supabase/client.d.ts.map +1 -0
  124. package/dist/supabase/client.js +149 -0
  125. package/dist/supabase/client.js.map +1 -0
  126. package/dist/supabase/validate.d.ts +11 -0
  127. package/dist/supabase/validate.d.ts.map +1 -0
  128. package/dist/supabase/validate.js +38 -0
  129. package/dist/supabase/validate.js.map +1 -0
  130. package/dist/types.d.ts +78 -0
  131. package/dist/types.d.ts.map +1 -0
  132. package/dist/types.js +16 -0
  133. package/dist/types.js.map +1 -0
  134. package/dist/utils.d.ts +24 -0
  135. package/dist/utils.d.ts.map +1 -0
  136. package/dist/utils.js +56 -0
  137. package/dist/utils.js.map +1 -0
  138. 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"}
@@ -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"}