@proveanything/smartlinks-auth-ui 0.5.22 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ACCOUNT_CACHING.md +349 -0
- package/ANDROID_NATIVE_BRIDGE.md +775 -0
- package/AUTH_STATE_MANAGEMENT.md +262 -0
- package/CAPACITOR_INTEGRATION.md +244 -0
- package/CUSTOMIZATION_GUIDE.md +411 -0
- package/README.md +73 -13
- package/SDK_DEBUGGING_GUIDE.md +217 -0
- package/SMARTLINKS_FRAME.md +302 -0
- package/SMARTLINKS_INTEGRATION.md +330 -0
- package/WHATSAPP_OTP_PLAN.md +106 -0
- package/dist/api.d.ts +15 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/components/ProviderButtons.d.ts +1 -0
- package/dist/components/ProviderButtons.d.ts.map +1 -1
- package/dist/components/SmartlinksAuthUI.d.ts.map +1 -1
- package/dist/context/AuthContext.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +352 -31
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +352 -30
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +98 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/persistentStorage.d.ts +14 -0
- package/dist/utils/persistentStorage.d.ts.map +1 -1
- package/dist/utils/tokenStorage.d.ts +7 -0
- package/dist/utils/tokenStorage.d.ts.map +1 -1
- package/package.json +15 -6
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# Account Information Caching
|
|
2
|
+
|
|
3
|
+
The auth module provides intelligent caching for Smartlinks account information, reducing API calls and improving performance.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
### Get Account Information
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { useAuth } from '@smartlinks/auth-ui';
|
|
11
|
+
|
|
12
|
+
function MyComponent() {
|
|
13
|
+
const auth = useAuth();
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const loadAccount = async () => {
|
|
17
|
+
try {
|
|
18
|
+
// Smart caching - uses cache if fresh, fetches if stale
|
|
19
|
+
const account = await auth.getAccount();
|
|
20
|
+
console.log('Account:', account);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('Failed to load account:', error);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (auth.isAuthenticated) {
|
|
27
|
+
loadAccount();
|
|
28
|
+
}
|
|
29
|
+
}, [auth.isAuthenticated]);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Force Refresh
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Bypass cache and fetch fresh data
|
|
37
|
+
const account = await auth.getAccount(true);
|
|
38
|
+
|
|
39
|
+
// Or use convenience method
|
|
40
|
+
const account = await auth.refreshAccount();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Access Cached Data Synchronously
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Access cached account info without triggering API call
|
|
47
|
+
const { accountInfo } = useAuth();
|
|
48
|
+
|
|
49
|
+
if (accountInfo) {
|
|
50
|
+
console.log('Cached account:', accountInfo);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
### Cache TTL
|
|
57
|
+
|
|
58
|
+
Configure how long account data is cached:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
<AuthProvider accountCacheTTL={10 * 60 * 1000}> {/* 10 minutes */}
|
|
62
|
+
<App />
|
|
63
|
+
</AuthProvider>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Preload on Login
|
|
67
|
+
|
|
68
|
+
Automatically fetch account info on login:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
<AuthProvider preloadAccountInfo={true}>
|
|
72
|
+
<App />
|
|
73
|
+
</AuthProvider>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Caching Strategy
|
|
77
|
+
|
|
78
|
+
**When cache is used:**
|
|
79
|
+
- Account info cached for 5 minutes by default (configurable)
|
|
80
|
+
- Subsequent calls return cached data without API request
|
|
81
|
+
- Cache persists across page refreshes (IndexedDB/localStorage)
|
|
82
|
+
- Cache synchronized across browser tabs
|
|
83
|
+
|
|
84
|
+
**When API is called:**
|
|
85
|
+
- First `getAccount()` call after login
|
|
86
|
+
- Cache has expired (past TTL)
|
|
87
|
+
- `forceRefresh` parameter is true
|
|
88
|
+
- Cache is cleared or missing
|
|
89
|
+
|
|
90
|
+
**Fallback behavior:**
|
|
91
|
+
- If API call fails, returns stale cached data if available
|
|
92
|
+
- Logs warning when returning stale data
|
|
93
|
+
- Throws error only if no cache exists and API fails
|
|
94
|
+
|
|
95
|
+
## Cross-Tab Synchronization
|
|
96
|
+
|
|
97
|
+
When one tab fetches fresh account info, all other tabs automatically receive the updated data:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
const unsubscribe = auth.onAuthStateChange((event) => {
|
|
102
|
+
if (event.type === 'ACCOUNT_REFRESH') {
|
|
103
|
+
console.log('Account refreshed:', event.accountInfo);
|
|
104
|
+
// Update UI with fresh account data
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return unsubscribe;
|
|
109
|
+
}, []);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Best Practices
|
|
113
|
+
|
|
114
|
+
### 1. Use Cached Data for Frequent Access
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// Good - uses cached data
|
|
118
|
+
const { accountInfo } = useAuth();
|
|
119
|
+
const userName = accountInfo?.name;
|
|
120
|
+
|
|
121
|
+
// Avoid - triggers API call on every render if cache expired
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
auth.getAccount().then(account => setName(account.name));
|
|
124
|
+
}, []);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 2. Refresh on User-Initiated Actions
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
function RefreshButton() {
|
|
131
|
+
const auth = useAuth();
|
|
132
|
+
|
|
133
|
+
const handleRefresh = async () => {
|
|
134
|
+
await auth.refreshAccount(); // Force fresh fetch
|
|
135
|
+
toast.success('Account refreshed');
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return <button onClick={handleRefresh}>Refresh Account</button>;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 3. Clear Cache on Sensitive Operations
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// After updating user profile via separate API
|
|
146
|
+
await updateUserProfile({ displayName: 'New Name' });
|
|
147
|
+
|
|
148
|
+
// Clear account cache to ensure fresh data on next fetch
|
|
149
|
+
await auth.clearAccountCache();
|
|
150
|
+
|
|
151
|
+
// Fetch fresh data
|
|
152
|
+
const updatedAccount = await auth.getAccount();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 4. Handle Loading and Error States
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
function AccountDisplay() {
|
|
159
|
+
const auth = useAuth();
|
|
160
|
+
const [account, setAccount] = useState(null);
|
|
161
|
+
const [loading, setLoading] = useState(true);
|
|
162
|
+
const [error, setError] = useState(null);
|
|
163
|
+
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (auth.isAuthenticated) {
|
|
166
|
+
auth.getAccount()
|
|
167
|
+
.then(setAccount)
|
|
168
|
+
.catch(setError)
|
|
169
|
+
.finally(() => setLoading(false));
|
|
170
|
+
}
|
|
171
|
+
}, [auth.isAuthenticated]);
|
|
172
|
+
|
|
173
|
+
if (loading) return <div>Loading...</div>;
|
|
174
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
175
|
+
if (!account) return <div>No account data</div>;
|
|
176
|
+
|
|
177
|
+
return <div>Welcome, {account.name}!</div>;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Common Patterns
|
|
182
|
+
|
|
183
|
+
### Dashboard Component
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
function Dashboard() {
|
|
187
|
+
const auth = useAuth();
|
|
188
|
+
const [account, setAccount] = useState(auth.accountInfo); // Start with cached
|
|
189
|
+
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
// Load account info, using cache if available
|
|
192
|
+
auth.getAccount().then(setAccount);
|
|
193
|
+
}, []);
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div>
|
|
197
|
+
<h1>Welcome, {account?.name}</h1>
|
|
198
|
+
<p>Email: {account?.email}</p>
|
|
199
|
+
<p>Collections: {Object.keys(account?.sites || {}).length}</p>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Permission Check
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
function AdminPanel() {
|
|
209
|
+
const auth = useAuth();
|
|
210
|
+
const [hasAccess, setHasAccess] = useState(false);
|
|
211
|
+
|
|
212
|
+
useEffect(() => {
|
|
213
|
+
auth.getAccount().then(account => {
|
|
214
|
+
const isAdmin = account.features?.adminCollections === true;
|
|
215
|
+
setHasAccess(isAdmin);
|
|
216
|
+
});
|
|
217
|
+
}, []);
|
|
218
|
+
|
|
219
|
+
if (!hasAccess) return <div>Access Denied</div>;
|
|
220
|
+
|
|
221
|
+
return <div>Admin Content</div>;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Migration Guide
|
|
226
|
+
|
|
227
|
+
### Before (Direct Smartlinks SDK)
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import * as smartlinks from '@proveanything/smartlinks';
|
|
231
|
+
|
|
232
|
+
function MyComponent() {
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
// Every call hits the API
|
|
235
|
+
smartlinks.auth.getAccount().then(account => {
|
|
236
|
+
console.log(account);
|
|
237
|
+
});
|
|
238
|
+
}, []);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### After (Auth Module with Caching)
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { useAuth } from '@smartlinks/auth-ui';
|
|
246
|
+
|
|
247
|
+
function MyComponent() {
|
|
248
|
+
const auth = useAuth();
|
|
249
|
+
|
|
250
|
+
useEffect(() => {
|
|
251
|
+
// Smart caching - much faster on subsequent calls
|
|
252
|
+
auth.getAccount().then(account => {
|
|
253
|
+
console.log(account);
|
|
254
|
+
});
|
|
255
|
+
}, []);
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Performance Benefits
|
|
260
|
+
|
|
261
|
+
- **Reduced API calls**: 5-minute cache means 1 API call instead of potentially dozens
|
|
262
|
+
- **Faster response**: Cached data returns in <1ms vs 100-500ms API latency
|
|
263
|
+
- **Better UX**: Instant data display on page navigation
|
|
264
|
+
- **Cross-tab efficiency**: One tab fetches, all tabs benefit
|
|
265
|
+
- **Offline resilience**: Stale cache returned when API unavailable
|
|
266
|
+
|
|
267
|
+
## Troubleshooting
|
|
268
|
+
|
|
269
|
+
### Cache Not Updating
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// Force refresh to bypass cache
|
|
273
|
+
await auth.refreshAccount();
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Cross-Tab Sync Not Working
|
|
277
|
+
|
|
278
|
+
Ensure BroadcastChannel is supported (modern browsers):
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
if ('BroadcastChannel' in window) {
|
|
282
|
+
// Cross-tab sync available
|
|
283
|
+
} else {
|
|
284
|
+
// Fallback: cache still works, just no cross-tab sync
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Memory Concerns
|
|
289
|
+
|
|
290
|
+
Account info is stored in IndexedDB/localStorage, not memory:
|
|
291
|
+
- Minimal memory footprint
|
|
292
|
+
- Persists across page refreshes
|
|
293
|
+
- Automatically cleared on logout
|
|
294
|
+
|
|
295
|
+
## API Reference
|
|
296
|
+
|
|
297
|
+
### `getAccount(forceRefresh?: boolean): Promise<Record<string, any>>`
|
|
298
|
+
|
|
299
|
+
Retrieves account information with intelligent caching.
|
|
300
|
+
|
|
301
|
+
**Parameters:**
|
|
302
|
+
- `forceRefresh` (optional): Set to `true` to bypass cache and fetch fresh data
|
|
303
|
+
|
|
304
|
+
**Returns:** Promise resolving to account info object
|
|
305
|
+
|
|
306
|
+
**Throws:** Error if not authenticated or API fails with no cache available
|
|
307
|
+
|
|
308
|
+
### `refreshAccount(): Promise<Record<string, any>>`
|
|
309
|
+
|
|
310
|
+
Convenience method to force refresh account info. Equivalent to `getAccount(true)`.
|
|
311
|
+
|
|
312
|
+
**Returns:** Promise resolving to fresh account info
|
|
313
|
+
|
|
314
|
+
### `clearAccountCache(): Promise<void>`
|
|
315
|
+
|
|
316
|
+
Clears the cached account information. Next `getAccount()` call will fetch fresh data.
|
|
317
|
+
|
|
318
|
+
**Returns:** Promise that resolves when cache is cleared
|
|
319
|
+
|
|
320
|
+
### `accountInfo: Record<string, any> | null`
|
|
321
|
+
|
|
322
|
+
Synchronously accessible cached account information. Returns `null` if no cache exists.
|
|
323
|
+
|
|
324
|
+
## Implementation Details
|
|
325
|
+
|
|
326
|
+
### Storage Architecture
|
|
327
|
+
|
|
328
|
+
- **Primary storage**: IndexedDB for structured data and better capacity
|
|
329
|
+
- **Fallback storage**: localStorage for browsers with limited IndexedDB support
|
|
330
|
+
- **In-memory cache**: React state for synchronous access within components
|
|
331
|
+
|
|
332
|
+
### Cache Structure
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
{
|
|
336
|
+
data: Record<string, any>, // The actual account info
|
|
337
|
+
cachedAt: number, // Timestamp when data was cached
|
|
338
|
+
expiresAt: number // Timestamp when cache expires
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Cross-Tab Synchronization
|
|
343
|
+
|
|
344
|
+
Uses BroadcastChannel API and storage events to notify all browser tabs when:
|
|
345
|
+
- Account info is fetched/refreshed in any tab
|
|
346
|
+
- Account cache is cleared
|
|
347
|
+
- User logs out (clears all caches)
|
|
348
|
+
|
|
349
|
+
All tabs automatically update their in-memory state without additional API calls.
|