@alter-ai/connect 0.2.0 → 0.2.1
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 +122 -239
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Alter Connect SDK
|
|
2
2
|
|
|
3
|
-
A lightweight JavaScript SDK for embedding OAuth integrations into your application. Connect
|
|
3
|
+
A lightweight JavaScript SDK for embedding OAuth integrations into your application. The SDK opens a backend-served Connect UI in a popup — the backend handles auth, provider selection, branding, and OAuth, then sends results back via postMessage.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**~10KB minified | Zero dependencies | TypeScript included**
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
6
8
|
|
|
7
9
|
### 1. Install
|
|
8
10
|
|
|
@@ -31,9 +33,15 @@ const response = await fetch('https://api.alterai.dev/oauth/connect/session', {
|
|
|
31
33
|
body: JSON.stringify({
|
|
32
34
|
end_user: {
|
|
33
35
|
id: 'user_123',
|
|
34
|
-
email: 'user@example.com'
|
|
36
|
+
email: 'user@example.com',
|
|
37
|
+
name: 'John Doe'
|
|
38
|
+
},
|
|
39
|
+
attributes: {
|
|
40
|
+
user_id: 'user_123',
|
|
41
|
+
org_id: 'org_456'
|
|
35
42
|
},
|
|
36
|
-
allowed_providers: ['google', 'slack', 'microsoft']
|
|
43
|
+
allowed_providers: ['google', 'slack', 'microsoft'],
|
|
44
|
+
allowed_origin: 'https://yourapp.com'
|
|
37
45
|
})
|
|
38
46
|
});
|
|
39
47
|
|
|
@@ -45,7 +53,7 @@ const { session_token } = await response.json();
|
|
|
45
53
|
```javascript
|
|
46
54
|
import AlterConnect from '@alter-ai/connect';
|
|
47
55
|
|
|
48
|
-
// Initialize SDK
|
|
56
|
+
// Initialize SDK (no API key needed!)
|
|
49
57
|
const alterConnect = AlterConnect.create();
|
|
50
58
|
|
|
51
59
|
// Get session token from YOUR backend
|
|
@@ -60,13 +68,16 @@ await alterConnect.open({
|
|
|
60
68
|
},
|
|
61
69
|
onError: (error) => {
|
|
62
70
|
console.error('Failed:', error);
|
|
71
|
+
},
|
|
72
|
+
onExit: () => {
|
|
73
|
+
console.log('User closed the window');
|
|
63
74
|
}
|
|
64
75
|
});
|
|
65
76
|
```
|
|
66
77
|
|
|
67
|
-
That's it! The SDK handles the OAuth flow, popup windows, and all security.
|
|
78
|
+
That's it! The SDK handles the OAuth flow, popup windows, mobile redirects, and all security.
|
|
68
79
|
|
|
69
|
-
##
|
|
80
|
+
## Framework Examples
|
|
70
81
|
|
|
71
82
|
### React
|
|
72
83
|
|
|
@@ -143,100 +154,7 @@ async function handleConnect() {
|
|
|
143
154
|
</script>
|
|
144
155
|
```
|
|
145
156
|
|
|
146
|
-
##
|
|
147
|
-
|
|
148
|
-
**Branding is now managed through the Developer Portal** and automatically applied to the Connect UI at runtime.
|
|
149
|
-
|
|
150
|
-
### Managing Branding (Developer Portal)
|
|
151
|
-
|
|
152
|
-
Configure your app's branding through the Developer Portal API:
|
|
153
|
-
|
|
154
|
-
#### Initial Setup or Complete Rebrand (PUT)
|
|
155
|
-
|
|
156
|
-
Use PUT for initial branding setup or to completely replace existing branding:
|
|
157
|
-
|
|
158
|
-
```javascript
|
|
159
|
-
// Create or fully replace branding
|
|
160
|
-
await fetch('https://api.alterai.dev/api/v1/developer/apps/{app_id}/branding', {
|
|
161
|
-
method: 'PUT',
|
|
162
|
-
headers: {
|
|
163
|
-
'Authorization': `Bearer ${DEVELOPER_TOKEN}`,
|
|
164
|
-
'Content-Type': 'application/json'
|
|
165
|
-
},
|
|
166
|
-
body: JSON.stringify({
|
|
167
|
-
logo_url: 'https://your-domain.com/logo.png', // Required
|
|
168
|
-
colors: { // Required
|
|
169
|
-
primary: '#6366f1',
|
|
170
|
-
text: '#1f2937',
|
|
171
|
-
background: '#ffffff'
|
|
172
|
-
},
|
|
173
|
-
font_family: 'Inter, sans-serif' // Optional
|
|
174
|
-
})
|
|
175
|
-
});
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
#### Partial Updates (PATCH)
|
|
179
|
-
|
|
180
|
-
Use PATCH to update specific branding fields:
|
|
181
|
-
|
|
182
|
-
```javascript
|
|
183
|
-
// Update only font (logo + colors preserved)
|
|
184
|
-
await fetch('https://api.alterai.dev/api/v1/developer/apps/{app_id}/branding', {
|
|
185
|
-
method: 'PATCH',
|
|
186
|
-
headers: {
|
|
187
|
-
'Authorization': `Bearer ${DEVELOPER_TOKEN}`,
|
|
188
|
-
'Content-Type': 'application/json'
|
|
189
|
-
},
|
|
190
|
-
body: JSON.stringify({
|
|
191
|
-
font_family: 'Roboto, sans-serif'
|
|
192
|
-
})
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Update logo + colors (font preserved)
|
|
196
|
-
await fetch('https://api.alterai.dev/api/v1/developer/apps/{app_id}/branding', {
|
|
197
|
-
method: 'PATCH',
|
|
198
|
-
headers: {
|
|
199
|
-
'Authorization': `Bearer ${DEVELOPER_TOKEN}`,
|
|
200
|
-
'Content-Type': 'application/json'
|
|
201
|
-
},
|
|
202
|
-
body: JSON.stringify({
|
|
203
|
-
logo_url: 'https://your-domain.com/new-logo.png',
|
|
204
|
-
colors: {
|
|
205
|
-
primary: '#ff0000',
|
|
206
|
-
text: '#000000',
|
|
207
|
-
background: '#ffffff'
|
|
208
|
-
}
|
|
209
|
-
})
|
|
210
|
-
});
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
**Important Rules:**
|
|
214
|
-
- **PUT:** Requires `logo_url` and `colors`. Font is optional. Replaces all existing branding.
|
|
215
|
-
- **PATCH:** Requires existing branding (use PUT first). If updating logo or colors, both must be provided together. Font can be updated independently.
|
|
216
|
-
- **DELETE:** Removes all branding and reverts to Alter defaults.
|
|
217
|
-
|
|
218
|
-
### How It Works
|
|
219
|
-
|
|
220
|
-
1. **Configure branding** in the Developer Portal
|
|
221
|
-
2. **SDK fetches branding** automatically when `alterConnect.open()` is called
|
|
222
|
-
3. **Branding is applied** instantly to the Connect UI
|
|
223
|
-
4. **No redeployment needed** - changes take effect immediately
|
|
224
|
-
|
|
225
|
-
### Fallback Behavior
|
|
226
|
-
|
|
227
|
-
If no branding is configured or the API call fails, the SDK gracefully falls back to Alter's default branding.
|
|
228
|
-
|
|
229
|
-
### SDK Configuration Options
|
|
230
|
-
|
|
231
|
-
For local development or debugging, you can still configure some options:
|
|
232
|
-
|
|
233
|
-
```javascript
|
|
234
|
-
const alterConnect = AlterConnect.create({
|
|
235
|
-
debug: true // Enable console logging
|
|
236
|
-
});
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
## 📚 API Reference
|
|
157
|
+
## API Reference
|
|
240
158
|
|
|
241
159
|
### `AlterConnect.create(config?)`
|
|
242
160
|
|
|
@@ -244,42 +162,40 @@ Creates a new SDK instance.
|
|
|
244
162
|
|
|
245
163
|
```javascript
|
|
246
164
|
const alterConnect = AlterConnect.create({
|
|
247
|
-
debug: false
|
|
165
|
+
debug: true // Enable console logging (default: false)
|
|
248
166
|
});
|
|
249
167
|
```
|
|
250
168
|
|
|
251
|
-
**Config Options:**
|
|
252
|
-
|
|
253
169
|
| Option | Type | Description | Default |
|
|
254
170
|
|--------|------|-------------|---------|
|
|
255
171
|
| `debug` | `boolean` | Enable debug logging | `false` |
|
|
256
172
|
|
|
257
|
-
**Note:**
|
|
173
|
+
**Note:** Visual customization (colors, fonts, logo) is configured via the Developer Portal branding settings. The backend-served Connect UI applies your branding automatically.
|
|
258
174
|
|
|
259
175
|
---
|
|
260
176
|
|
|
261
177
|
### `alterConnect.open(options)`
|
|
262
178
|
|
|
263
|
-
Opens the Connect UI
|
|
179
|
+
Opens the Connect UI. On desktop, opens a centered popup window (500x700px). On mobile, uses a full-page redirect flow.
|
|
264
180
|
|
|
265
181
|
```javascript
|
|
266
182
|
await alterConnect.open({
|
|
267
183
|
token: 'sess_abc123...',
|
|
184
|
+
baseURL: 'https://api.alterai.dev', // Optional
|
|
268
185
|
onSuccess: (connection) => { /* ... */ },
|
|
269
186
|
onError: (error) => { /* ... */ },
|
|
270
|
-
onExit: () => { /* ... */ }
|
|
187
|
+
onExit: () => { /* ... */ },
|
|
188
|
+
onEvent: (eventName, metadata) => { /* ... */ }
|
|
271
189
|
});
|
|
272
190
|
```
|
|
273
191
|
|
|
274
|
-
**Options:**
|
|
275
|
-
|
|
276
192
|
| Parameter | Type | Required | Description |
|
|
277
193
|
|-----------|------|----------|-------------|
|
|
278
|
-
| `token` | `string` |
|
|
194
|
+
| `token` | `string` | Yes | Session token from your backend |
|
|
279
195
|
| `baseURL` | `string` | No | Alter API URL (usually auto-detected) |
|
|
280
|
-
| `onSuccess` | `function` |
|
|
196
|
+
| `onSuccess` | `function` | Yes | Called when connection succeeds |
|
|
281
197
|
| `onError` | `function` | No | Called when connection fails |
|
|
282
|
-
| `onExit` | `function` | No | Called when user closes
|
|
198
|
+
| `onExit` | `function` | No | Called when user closes popup |
|
|
283
199
|
| `onEvent` | `function` | No | Called for analytics events |
|
|
284
200
|
|
|
285
201
|
**Connection Object (onSuccess):**
|
|
@@ -292,9 +208,12 @@ await alterConnect.open({
|
|
|
292
208
|
account_identifier: string; // e.g., 'user@gmail.com'
|
|
293
209
|
timestamp: string; // ISO 8601 timestamp
|
|
294
210
|
operation: 'creation' | 'reauth';
|
|
295
|
-
scopes: string[];
|
|
211
|
+
scopes: string[]; // Granted OAuth scopes
|
|
296
212
|
status: 'active' | 'pending' | 'error';
|
|
297
|
-
metadata?:
|
|
213
|
+
metadata?: {
|
|
214
|
+
account_display_name?: string;
|
|
215
|
+
account_email?: string;
|
|
216
|
+
};
|
|
298
217
|
}
|
|
299
218
|
```
|
|
300
219
|
|
|
@@ -330,6 +249,22 @@ alterConnect.destroy();
|
|
|
330
249
|
|
|
331
250
|
---
|
|
332
251
|
|
|
252
|
+
### `alterConnect.on(event, handler)`
|
|
253
|
+
|
|
254
|
+
Register an event listener. Returns an unsubscribe function.
|
|
255
|
+
|
|
256
|
+
```javascript
|
|
257
|
+
const unsubscribe = alterConnect.on('success', (connection) => {
|
|
258
|
+
console.log('Connected:', connection);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Later: unsubscribe();
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Events:** `success`, `error`, `exit`, `close`, `event`
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
333
268
|
### `alterConnect.isOpen()`
|
|
334
269
|
|
|
335
270
|
Checks if the Connect UI is currently open.
|
|
@@ -340,8 +275,6 @@ if (alterConnect.isOpen()) {
|
|
|
340
275
|
}
|
|
341
276
|
```
|
|
342
277
|
|
|
343
|
-
**Returns:** `boolean`
|
|
344
|
-
|
|
345
278
|
---
|
|
346
279
|
|
|
347
280
|
### `alterConnect.getVersion()`
|
|
@@ -349,14 +282,38 @@ if (alterConnect.isOpen()) {
|
|
|
349
282
|
Gets the SDK version.
|
|
350
283
|
|
|
351
284
|
```javascript
|
|
352
|
-
console.log(alterConnect.getVersion()); // "0.1
|
|
285
|
+
console.log(alterConnect.getVersion()); // "0.2.1"
|
|
353
286
|
```
|
|
354
287
|
|
|
355
|
-
|
|
288
|
+
## Mobile Support
|
|
289
|
+
|
|
290
|
+
The SDK automatically detects mobile devices and switches to an optimized flow:
|
|
291
|
+
|
|
292
|
+
| Device | Flow | How It Works |
|
|
293
|
+
|--------|------|-------------|
|
|
294
|
+
| Desktop | Popup | Opens centered popup (500x700px), communicates via postMessage |
|
|
295
|
+
| Phone (<=480px) | Redirect | Full-page redirect, returns via URL params |
|
|
296
|
+
| Tablet (portrait) | Redirect | Full-page redirect for better UX |
|
|
297
|
+
| Tablet (landscape) | Popup | Uses popup flow like desktop |
|
|
298
|
+
|
|
299
|
+
No code changes needed — the SDK handles device detection automatically.
|
|
300
|
+
|
|
301
|
+
For mobile redirect flow, include a `return_url` when creating the session:
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
// Backend session creation with mobile support
|
|
305
|
+
body: JSON.stringify({
|
|
306
|
+
end_user: { id: 'user_123', email: 'user@example.com' },
|
|
307
|
+
attributes: { user_id: 'user_123' },
|
|
308
|
+
allowed_providers: ['google', 'slack'],
|
|
309
|
+
allowed_origin: 'https://yourapp.com', // For desktop popup (postMessage)
|
|
310
|
+
return_url: 'https://yourapp.com/' // For mobile redirect (return destination)
|
|
311
|
+
})
|
|
312
|
+
```
|
|
356
313
|
|
|
357
|
-
##
|
|
314
|
+
## Security Architecture
|
|
358
315
|
|
|
359
|
-
The SDK uses a **Plaid-style token architecture
|
|
316
|
+
The SDK uses a **Plaid-style token architecture**:
|
|
360
317
|
|
|
361
318
|
```
|
|
362
319
|
Frontend (Public) Backend (Secure) Alter API
|
|
@@ -375,140 +332,63 @@ Frontend (Public) Backend (Secure) Alter API
|
|
|
375
332
|
│ 4. { session_token } │ │
|
|
376
333
|
│<─────────────────────────│ │
|
|
377
334
|
│ │ │
|
|
378
|
-
│ 5. SDK
|
|
379
|
-
|
|
380
|
-
│ │
|
|
381
|
-
|
|
382
|
-
│
|
|
335
|
+
│ 5. SDK opens popup to backend Connect UI │
|
|
336
|
+
│───────────────────────────────────────────────────>│
|
|
337
|
+
│ │ │
|
|
338
|
+
│ 6. Backend handles auth + OAuth │
|
|
339
|
+
│ │ │
|
|
340
|
+
│ 7. postMessage(connection) │
|
|
341
|
+
│<──────────────────────────────────────────────────│
|
|
342
|
+
│ 8. onSuccess(connection) │ │
|
|
383
343
|
```
|
|
384
344
|
|
|
385
345
|
**Key Security Features:**
|
|
386
346
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
347
|
+
- **API keys never touch frontend** - Only backend has API key
|
|
348
|
+
- **Session tokens are short-lived** - Expire after 10 minutes
|
|
349
|
+
- **Session tokens are single-use** - Can only create one connection
|
|
350
|
+
- **Session tokens are scoped** - Locked to specific user & providers
|
|
351
|
+
- **No secrets in browser** - SDK is purely a popup launcher + callback listener
|
|
392
352
|
|
|
393
|
-
##
|
|
353
|
+
## Smart UX
|
|
394
354
|
|
|
395
355
|
### Single Provider Flow
|
|
396
356
|
|
|
397
|
-
When only 1 provider is allowed, the
|
|
357
|
+
When only 1 provider is allowed, the Connect UI **skips the selection screen** and opens OAuth directly:
|
|
398
358
|
|
|
399
359
|
```javascript
|
|
400
|
-
// Backend
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
// SDK behavior: Opens Google OAuth immediately (no modal)
|
|
360
|
+
// Backend: allowed_providers: ['google']
|
|
361
|
+
// Result: Opens Google OAuth immediately (no selection screen)
|
|
404
362
|
```
|
|
405
363
|
|
|
406
364
|
### Multiple Provider Flow
|
|
407
365
|
|
|
408
|
-
When 2+ providers are allowed, the
|
|
366
|
+
When 2+ providers are allowed, the Connect UI shows a **provider selection screen**:
|
|
409
367
|
|
|
410
368
|
```javascript
|
|
411
|
-
// Backend
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
// SDK behavior: Shows modal with provider grid
|
|
369
|
+
// Backend: allowed_providers: ['google', 'slack', 'microsoft']
|
|
370
|
+
// Result: Shows provider selection, user picks one
|
|
415
371
|
```
|
|
416
372
|
|
|
417
|
-
##
|
|
418
|
-
|
|
419
|
-
### Save Connection to Your Database
|
|
420
|
-
|
|
421
|
-
```javascript
|
|
422
|
-
await alterConnect.open({
|
|
423
|
-
token: sessionToken,
|
|
424
|
-
onSuccess: async (connection) => {
|
|
425
|
-
// Save to YOUR database
|
|
426
|
-
await fetch('/api/connections', {
|
|
427
|
-
method: 'POST',
|
|
428
|
-
body: JSON.stringify({
|
|
429
|
-
connection_id: connection.connection_id,
|
|
430
|
-
user_id: currentUserId,
|
|
431
|
-
provider: connection.provider
|
|
432
|
-
})
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### Validate Provider Type
|
|
439
|
-
|
|
440
|
-
```javascript
|
|
441
|
-
await alterConnect.open({
|
|
442
|
-
token: sessionToken,
|
|
443
|
-
onSuccess: async (connection) => {
|
|
444
|
-
// Ensure user connected the right provider
|
|
445
|
-
if (connection.provider !== 'google') {
|
|
446
|
-
alert('Please connect your Gmail account');
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
await saveConnection(connection);
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
### Validate Email Domain
|
|
456
|
-
|
|
457
|
-
```javascript
|
|
458
|
-
await alterConnect.open({
|
|
459
|
-
token: sessionToken,
|
|
460
|
-
onSuccess: async (connection) => {
|
|
461
|
-
// Ensure user connected a work email
|
|
462
|
-
if (!connection.account_identifier.endsWith('@company.com')) {
|
|
463
|
-
alert('Please connect your @company.com work email');
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
await saveConnection(connection);
|
|
468
|
-
}
|
|
469
|
-
});
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
### Handle Errors Gracefully
|
|
473
|
-
|
|
474
|
-
```javascript
|
|
475
|
-
await alterConnect.open({
|
|
476
|
-
token: sessionToken,
|
|
477
|
-
onSuccess: (connection) => {
|
|
478
|
-
console.log('Connected!', connection);
|
|
479
|
-
},
|
|
480
|
-
onError: (error) => {
|
|
481
|
-
if (error.code === 'popup_blocked') {
|
|
482
|
-
alert('Please allow popups for this site');
|
|
483
|
-
} else if (error.code === 'session_expired') {
|
|
484
|
-
alert('Session expired. Please try again.');
|
|
485
|
-
} else {
|
|
486
|
-
alert(`Connection failed: ${error.message}`);
|
|
487
|
-
}
|
|
488
|
-
},
|
|
489
|
-
onExit: () => {
|
|
490
|
-
console.log('User cancelled');
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
## 📦 TypeScript Support
|
|
373
|
+
## TypeScript Support
|
|
496
374
|
|
|
497
375
|
Full TypeScript definitions included:
|
|
498
376
|
|
|
499
377
|
```typescript
|
|
500
|
-
import AlterConnect, {
|
|
378
|
+
import AlterConnect, {
|
|
379
|
+
AlterConnectConfig,
|
|
380
|
+
Connection,
|
|
381
|
+
AlterError
|
|
382
|
+
} from '@alter-ai/connect';
|
|
501
383
|
|
|
502
|
-
const alterConnect = AlterConnect.create({
|
|
503
|
-
customization: { colors: { primary: '#6366f1' } }
|
|
504
|
-
});
|
|
384
|
+
const alterConnect = AlterConnect.create({ debug: true });
|
|
505
385
|
|
|
506
386
|
await alterConnect.open({
|
|
507
387
|
token: sessionToken,
|
|
508
388
|
onSuccess: (connection: Connection) => {
|
|
509
|
-
// TypeScript knows all properties
|
|
510
389
|
console.log(connection.connection_id);
|
|
511
390
|
console.log(connection.provider);
|
|
391
|
+
console.log(connection.scopes);
|
|
512
392
|
},
|
|
513
393
|
onError: (error: AlterError) => {
|
|
514
394
|
console.error(error.code, error.message);
|
|
@@ -516,21 +396,24 @@ await alterConnect.open({
|
|
|
516
396
|
});
|
|
517
397
|
```
|
|
518
398
|
|
|
519
|
-
##
|
|
399
|
+
## Bundle Size
|
|
400
|
+
|
|
401
|
+
| Format | Size | Gzipped |
|
|
402
|
+
|--------|------|---------|
|
|
403
|
+
| **CJS** | ~10KB | ~3.5KB |
|
|
404
|
+
| **ESM** | ~10KB | ~3.4KB |
|
|
405
|
+
| **UMD** | ~11KB | ~3.5KB |
|
|
406
|
+
|
|
407
|
+
Zero runtime dependencies.
|
|
408
|
+
|
|
409
|
+
## Browser Support
|
|
520
410
|
|
|
521
411
|
- Chrome/Edge 90+
|
|
522
412
|
- Firefox 88+
|
|
523
413
|
- Safari 14+
|
|
524
414
|
- Mobile browsers (iOS Safari 14+, Chrome Mobile)
|
|
525
415
|
|
|
526
|
-
##
|
|
527
|
-
|
|
528
|
-
- **UMD:** 21KB minified
|
|
529
|
-
- **ESM:** 21KB minified
|
|
530
|
-
- **CJS:** 21KB minified
|
|
531
|
-
- **Zero runtime dependencies**
|
|
532
|
-
|
|
533
|
-
## 🐛 Troubleshooting
|
|
416
|
+
## Troubleshooting
|
|
534
417
|
|
|
535
418
|
### Popup Blocked
|
|
536
419
|
|
|
@@ -539,13 +422,13 @@ await alterConnect.open({
|
|
|
539
422
|
**Solution:** Ensure `alterConnect.open()` is called directly from a user interaction (click event):
|
|
540
423
|
|
|
541
424
|
```javascript
|
|
542
|
-
//
|
|
425
|
+
// Bad - may be blocked
|
|
543
426
|
button.addEventListener('click', async () => {
|
|
544
427
|
const token = await fetchToken(); // Async delay
|
|
545
428
|
alterConnect.open({ token }); // May be blocked
|
|
546
429
|
});
|
|
547
430
|
|
|
548
|
-
//
|
|
431
|
+
// Good - no async delay before open()
|
|
549
432
|
button.addEventListener('click', () => {
|
|
550
433
|
fetchToken().then(token => {
|
|
551
434
|
alterConnect.open({ token }); // Called synchronously
|
|
@@ -565,13 +448,13 @@ button.addEventListener('click', () => {
|
|
|
565
448
|
|
|
566
449
|
**Solution:** Session tokens should be created from your **backend**, not frontend. The SDK handles all frontend API calls.
|
|
567
450
|
|
|
568
|
-
##
|
|
451
|
+
## Support
|
|
569
452
|
|
|
570
453
|
- **Documentation:** [https://docs.alterai.dev](https://docs.alterai.dev)
|
|
571
454
|
- **API Reference:** [https://api.alterai.dev/docs](https://api.alterai.dev/docs)
|
|
572
|
-
- **Issues:** [GitHub Issues](https://github.com/
|
|
455
|
+
- **Issues:** [GitHub Issues](https://github.com/AlterAIDev/Alter-Vault/issues)
|
|
573
456
|
- **Email:** support@alterai.dev
|
|
574
457
|
|
|
575
|
-
##
|
|
458
|
+
## License
|
|
576
459
|
|
|
577
460
|
MIT License - See [LICENSE](LICENSE) file for details
|
package/package.json
CHANGED