@proveanything/smartlinks 1.3.8 → 1.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache.d.ts +32 -0
- package/dist/cache.js +125 -0
- package/dist/docs/API_SUMMARY.md +160 -1
- package/dist/docs/iframe-responder.md +463 -0
- package/dist/iframe.d.ts +2 -0
- package/dist/iframe.js +2 -0
- package/dist/iframeResponder.d.ts +93 -0
- package/dist/iframeResponder.js +549 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/types/iframeResponder.d.ts +112 -0
- package/dist/types/iframeResponder.js +18 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/docs/API_SUMMARY.md +160 -1
- package/docs/iframe-responder.md +463 -0
- package/package.json +1 -1
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
# IframeResponder - Parent-Side Iframe Communication
|
|
2
|
+
|
|
3
|
+
The `IframeResponder` enables bidirectional communication between a parent application and an embedded iframe, both using the SmartLinks SDK. This allows seamless integration of microapps within your application with automatic API proxying, authentication sync, and deep linking.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Automatic URL Resolution** - Fetches app configuration from collection and resolves the correct URL
|
|
8
|
+
- **API Request Proxying** - Forwards API requests from iframe to parent's authenticated session
|
|
9
|
+
- **Smart Caching** - Reduces API calls by serving cached collection, product, and proof data
|
|
10
|
+
- **Authentication Sync** - Handles login/logout events between parent and iframe
|
|
11
|
+
- **Deep Linking** - Synchronizes iframe routes with parent URL state
|
|
12
|
+
- **Responsive Sizing** - Calculates and reports optimal iframe dimensions
|
|
13
|
+
- **Chunked File Uploads** - Proxies large file uploads through the parent
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
### 1. Create and Attach Responder
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import * as smartlinks from '@proveanything/smartlinks';
|
|
21
|
+
|
|
22
|
+
// Initialize SDK
|
|
23
|
+
smartlinks.initializeApi({
|
|
24
|
+
baseURL: 'https://api.smartlinks.io',
|
|
25
|
+
apiKey: 'your-api-key',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Create responder (URL resolved automatically from collection apps)
|
|
29
|
+
const responder = new smartlinks.IframeResponder({
|
|
30
|
+
collectionId: 'acme-wines',
|
|
31
|
+
appId: 'warranty-registration',
|
|
32
|
+
productId: 'wine-bottle-123', // Optional context
|
|
33
|
+
onAuthLogin: async (token, user) => {
|
|
34
|
+
// Handle authentication from iframe
|
|
35
|
+
smartlinks.setBearerToken(token);
|
|
36
|
+
console.log('User logged in:', user);
|
|
37
|
+
},
|
|
38
|
+
onResize: (height) => {
|
|
39
|
+
// Update iframe height
|
|
40
|
+
iframeElement.style.height = `${height}px`;
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Attach to iframe element
|
|
45
|
+
const iframe = document.getElementById('app-iframe') as HTMLIFrameElement;
|
|
46
|
+
const src = await responder.attach(iframe);
|
|
47
|
+
iframe.src = src;
|
|
48
|
+
|
|
49
|
+
// Cleanup when done
|
|
50
|
+
// responder.destroy();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. With Pre-cached Data (Faster Loading)
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Fetch data upfront
|
|
57
|
+
const collection = await smartlinks.collection.get('acme-wines');
|
|
58
|
+
const product = await smartlinks.product.get('wine-bottle-123');
|
|
59
|
+
const user = await smartlinks.auth.getAccountInfo();
|
|
60
|
+
|
|
61
|
+
const responder = new smartlinks.IframeResponder({
|
|
62
|
+
collectionId: 'acme-wines',
|
|
63
|
+
appId: 'warranty-registration',
|
|
64
|
+
productId: 'wine-bottle-123',
|
|
65
|
+
|
|
66
|
+
// Pre-populate cache for instant API responses
|
|
67
|
+
cache: {
|
|
68
|
+
collection,
|
|
69
|
+
product,
|
|
70
|
+
user: user ? {
|
|
71
|
+
uid: user.uid,
|
|
72
|
+
email: user.email,
|
|
73
|
+
displayName: user.displayName,
|
|
74
|
+
accountData: user.accountData,
|
|
75
|
+
} : null,
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
onAuthLogin: async (token, user) => {
|
|
79
|
+
smartlinks.setBearerToken(token);
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const src = await responder.attach(iframeElement);
|
|
84
|
+
iframeElement.src = src;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Configuration Options
|
|
88
|
+
|
|
89
|
+
### IframeResponderOptions
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
interface IframeResponderOptions {
|
|
93
|
+
// Required
|
|
94
|
+
collectionId: string; // Collection context
|
|
95
|
+
appId: string; // App to load (e.g., 'warranty-registration')
|
|
96
|
+
|
|
97
|
+
// Optional Context
|
|
98
|
+
productId?: string; // Product context
|
|
99
|
+
proofId?: string; // Proof context
|
|
100
|
+
isAdmin?: boolean; // Admin mode flag
|
|
101
|
+
|
|
102
|
+
// URL Configuration
|
|
103
|
+
version?: 'stable' | 'development'; // App version (default: 'stable')
|
|
104
|
+
appUrl?: string; // Override URL (for local dev)
|
|
105
|
+
initialPath?: string; // Initial hash path (e.g., '/settings')
|
|
106
|
+
|
|
107
|
+
// Data
|
|
108
|
+
cache?: CachedData; // Pre-cached data
|
|
109
|
+
|
|
110
|
+
// Callbacks
|
|
111
|
+
onAuthLogin?: (token: string, user: any, accountData?: any) => Promise<void>;
|
|
112
|
+
onAuthLogout?: () => Promise<void>;
|
|
113
|
+
onRouteChange?: (path: string, state: Record<string, string>) => void;
|
|
114
|
+
onResize?: (height: number) => void;
|
|
115
|
+
onError?: (error: Error) => void;
|
|
116
|
+
onReady?: () => void;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Advanced Examples
|
|
121
|
+
|
|
122
|
+
### Deep Linking / Route Synchronization
|
|
123
|
+
|
|
124
|
+
Keep the parent URL in sync with iframe navigation:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const responder = new smartlinks.IframeResponder({
|
|
128
|
+
collectionId: 'acme-wines',
|
|
129
|
+
appId: 'warranty',
|
|
130
|
+
initialPath: '/products/wine-123',
|
|
131
|
+
|
|
132
|
+
onRouteChange: (path, state) => {
|
|
133
|
+
// Update parent URL with iframe route
|
|
134
|
+
const url = new URL(window.location.href);
|
|
135
|
+
url.searchParams.set('app-path', path);
|
|
136
|
+
Object.entries(state).forEach(([key, value]) => {
|
|
137
|
+
url.searchParams.set(key, value);
|
|
138
|
+
});
|
|
139
|
+
window.history.pushState({}, '', url);
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Local Development Override
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const responder = new smartlinks.IframeResponder({
|
|
148
|
+
collectionId: 'acme-wines',
|
|
149
|
+
appId: 'warranty',
|
|
150
|
+
|
|
151
|
+
// Override URL for local development
|
|
152
|
+
appUrl: 'http://localhost:5173',
|
|
153
|
+
version: 'development',
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Admin Mode with Role Detection
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const user = await smartlinks.auth.getAccountInfo();
|
|
161
|
+
const collection = await smartlinks.collection.get('acme-wines');
|
|
162
|
+
|
|
163
|
+
const isAdmin = smartlinks.isAdminFromRoles(user, collection);
|
|
164
|
+
|
|
165
|
+
const responder = new smartlinks.IframeResponder({
|
|
166
|
+
collectionId: 'acme-wines',
|
|
167
|
+
appId: 'warranty',
|
|
168
|
+
isAdmin, // Pass admin status to iframe
|
|
169
|
+
cache: { collection, user },
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Responsive Height Management
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const responder = new smartlinks.IframeResponder({
|
|
177
|
+
collectionId: 'acme-wines',
|
|
178
|
+
appId: 'warranty',
|
|
179
|
+
|
|
180
|
+
onResize: (height) => {
|
|
181
|
+
// Smooth height transitions
|
|
182
|
+
iframe.style.transition = 'height 0.3s ease';
|
|
183
|
+
iframe.style.height = `${height}px`;
|
|
184
|
+
|
|
185
|
+
// Or calculate viewport-based height
|
|
186
|
+
const maxHeight = window.innerHeight - 100;
|
|
187
|
+
iframe.style.height = `${Math.min(height, maxHeight)}px`;
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Helper Functions
|
|
193
|
+
|
|
194
|
+
### buildIframeSrc()
|
|
195
|
+
|
|
196
|
+
Manually construct an iframe src URL without using the full responder:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const src = smartlinks.buildIframeSrc({
|
|
200
|
+
appUrl: 'https://warranty.lovable.app',
|
|
201
|
+
collectionId: 'acme-wines',
|
|
202
|
+
appId: 'warranty',
|
|
203
|
+
productId: 'wine-123',
|
|
204
|
+
isAdmin: false,
|
|
205
|
+
dark: true,
|
|
206
|
+
theme: {
|
|
207
|
+
primary: '#FF6B6B',
|
|
208
|
+
secondary: '#4ECDC4',
|
|
209
|
+
},
|
|
210
|
+
initialPath: '/register',
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
iframe.src = src;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### isAdminFromRoles()
|
|
217
|
+
|
|
218
|
+
Check if a user has admin access:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
const user = await smartlinks.auth.getAccountInfo();
|
|
222
|
+
const collection = await smartlinks.collection.get('acme-wines');
|
|
223
|
+
|
|
224
|
+
const isAdmin = smartlinks.isAdminFromRoles(user, collection);
|
|
225
|
+
// or with proof
|
|
226
|
+
const isAdminOfProof = smartlinks.isAdminFromRoles(user, collection, proof);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Cache Utilities
|
|
230
|
+
|
|
231
|
+
The `cache` module provides TTL-based caching:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import * as smartlinks from '@proveanything/smartlinks';
|
|
235
|
+
|
|
236
|
+
// Cache with 5-minute TTL
|
|
237
|
+
const apps = await smartlinks.cache.getOrFetch(
|
|
238
|
+
'apps:acme-wines',
|
|
239
|
+
() => smartlinks.collection.getApps('acme-wines'),
|
|
240
|
+
{ ttl: 5 * 60 * 1000, storage: 'session' }
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// Invalidate cache
|
|
244
|
+
smartlinks.cache.invalidate('apps:acme-wines');
|
|
245
|
+
|
|
246
|
+
// Clear all cache
|
|
247
|
+
smartlinks.cache.clear();
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Cache Storage Options
|
|
251
|
+
|
|
252
|
+
- `memory` - In-memory only (default, cleared on page reload)
|
|
253
|
+
- `session` - sessionStorage (persists across page reloads in same tab)
|
|
254
|
+
- `local` - localStorage (persists across browser sessions)
|
|
255
|
+
|
|
256
|
+
## Backend API Requirement
|
|
257
|
+
|
|
258
|
+
The SDK uses the existing `getAppsConfig()` endpoint:
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
GET /public/collection/:collectionId/apps-config
|
|
262
|
+
|
|
263
|
+
Response:
|
|
264
|
+
{
|
|
265
|
+
"apps": [
|
|
266
|
+
{
|
|
267
|
+
"id": "warranty-registration",
|
|
268
|
+
"srcAppId": "warranty-v2",
|
|
269
|
+
"name": "Warranty Registration",
|
|
270
|
+
"publicIframeUrl": "https://warranty.lovable.app",
|
|
271
|
+
"active": true,
|
|
272
|
+
"category": "Commerce",
|
|
273
|
+
"usage": {
|
|
274
|
+
"collection": true,
|
|
275
|
+
"product": true,
|
|
276
|
+
"proof": false,
|
|
277
|
+
"widget": false
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Each app must have a `publicIframeUrl` configured for the IframeResponder to work.
|
|
285
|
+
|
|
286
|
+
## Complete Integration Example
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import * as smartlinks from '@proveanything/smartlinks';
|
|
290
|
+
|
|
291
|
+
// Initialize SDK
|
|
292
|
+
smartlinks.initializeApi({
|
|
293
|
+
baseURL: 'https://api.smartlinks.io',
|
|
294
|
+
apiKey: 'your-api-key',
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
class AppManager {
|
|
298
|
+
private responder: smartlinks.IframeResponder | null = null;
|
|
299
|
+
|
|
300
|
+
async loadApp(containerId: string) {
|
|
301
|
+
// Create iframe
|
|
302
|
+
const iframe = document.createElement('iframe');
|
|
303
|
+
iframe.style.width = '100%';
|
|
304
|
+
iframe.style.border = 'none';
|
|
305
|
+
document.getElementById(containerId)?.appendChild(iframe);
|
|
306
|
+
|
|
307
|
+
// Fetch context data
|
|
308
|
+
const collection = await smartlinks.collection.get('acme-wines');
|
|
309
|
+
const product = await smartlinks.product.get('wine-123');
|
|
310
|
+
|
|
311
|
+
// Determine admin status
|
|
312
|
+
try {
|
|
313
|
+
const user = await smartlinks.auth.getAccountInfo();
|
|
314
|
+
const isAdmin = smartlinks.isAdminFromRoles(user, collection);
|
|
315
|
+
|
|
316
|
+
// Create responder
|
|
317
|
+
this.responder = new smartlinks.IframeResponder({
|
|
318
|
+
collectionId: 'acme-wines',
|
|
319
|
+
appId: 'warranty',
|
|
320
|
+
productId: 'wine-123',
|
|
321
|
+
isAdmin,
|
|
322
|
+
cache: { collection, product, user },
|
|
323
|
+
|
|
324
|
+
onAuthLogin: async (token, user) => {
|
|
325
|
+
smartlinks.setBearerToken(token);
|
|
326
|
+
this.responder?.updateCache({ user });
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
onAuthLogout: async () => {
|
|
330
|
+
smartlinks.setBearerToken('');
|
|
331
|
+
this.responder?.updateCache({ user: null });
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
onRouteChange: (path, state) => {
|
|
335
|
+
console.log('Route changed:', path, state);
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
onResize: (height) => {
|
|
339
|
+
iframe.style.height = `${height}px`;
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
onError: (error) => {
|
|
343
|
+
console.error('Iframe error:', error);
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Attach and load
|
|
348
|
+
const src = await this.responder.attach(iframe);
|
|
349
|
+
iframe.src = src;
|
|
350
|
+
|
|
351
|
+
} catch (err) {
|
|
352
|
+
console.error('Failed to load app:', err);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
destroy() {
|
|
357
|
+
this.responder?.destroy();
|
|
358
|
+
this.responder = null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Usage
|
|
363
|
+
const manager = new AppManager();
|
|
364
|
+
await manager.loadApp('app-container');
|
|
365
|
+
|
|
366
|
+
// Cleanup on unmount
|
|
367
|
+
// manager.destroy();
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Message Protocol
|
|
371
|
+
|
|
372
|
+
The responder handles these message types from the iframe:
|
|
373
|
+
|
|
374
|
+
### Route Changes
|
|
375
|
+
```typescript
|
|
376
|
+
{
|
|
377
|
+
type: 'smartlinks-route-change',
|
|
378
|
+
path: '/products/wine-123',
|
|
379
|
+
context: { collectionId: 'acme-wines', appId: 'warranty' },
|
|
380
|
+
state: { tab: 'details' }
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Resize Events
|
|
385
|
+
```typescript
|
|
386
|
+
{
|
|
387
|
+
_smartlinksIframeMessage: true,
|
|
388
|
+
type: 'smartlinks:resize',
|
|
389
|
+
payload: { height: 800 }
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Authentication
|
|
394
|
+
```typescript
|
|
395
|
+
{
|
|
396
|
+
_smartlinksIframeMessage: true,
|
|
397
|
+
type: 'smartlinks:authkit:login',
|
|
398
|
+
payload: { token: '...', user: {...}, messageId: 'abc123' }
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### API Proxy
|
|
403
|
+
```typescript
|
|
404
|
+
{
|
|
405
|
+
_smartlinksProxyRequest: true,
|
|
406
|
+
id: 'req-123',
|
|
407
|
+
method: 'GET',
|
|
408
|
+
path: 'public/product/wine-123',
|
|
409
|
+
headers: { 'Authorization': 'Bearer ...' }
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## TypeScript Support
|
|
414
|
+
|
|
415
|
+
All types are exported for full TypeScript support:
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import type {
|
|
419
|
+
IframeResponderOptions,
|
|
420
|
+
CachedData,
|
|
421
|
+
CollectionApp,
|
|
422
|
+
RouteChangeMessage,
|
|
423
|
+
SmartlinksIframeMessage,
|
|
424
|
+
} from '@proveanything/smartlinks';
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Browser Compatibility
|
|
428
|
+
|
|
429
|
+
- Modern browsers with ES6+ support
|
|
430
|
+
- Requires `postMessage`, `MessageEvent`, `ResizeObserver` APIs
|
|
431
|
+
- Falls back gracefully in Node.js environments (no-ops for browser-only features)
|
|
432
|
+
|
|
433
|
+
## Best Practices
|
|
434
|
+
|
|
435
|
+
1. **Pre-cache data** when possible to eliminate loading delays
|
|
436
|
+
2. **Handle onError** to catch and log communication issues
|
|
437
|
+
3. **Clean up** responder with `destroy()` when unmounting
|
|
438
|
+
4. **Use version control** to test against development versions
|
|
439
|
+
5. **Validate tokens** server-side for security
|
|
440
|
+
6. **Set height dynamically** based on content using `onResize`
|
|
441
|
+
7. **Sync routes** with parent navigation for better UX
|
|
442
|
+
|
|
443
|
+
## Troubleshooting
|
|
444
|
+
|
|
445
|
+
### App not loading
|
|
446
|
+
- Verify the appId exists in collection apps configuration
|
|
447
|
+
- Check browser console for errors
|
|
448
|
+
- Ensure backend API endpoint is available
|
|
449
|
+
|
|
450
|
+
### Authentication not syncing
|
|
451
|
+
- Implement `onAuthLogin` callback
|
|
452
|
+
- Verify token is being set with `setBearerToken()`
|
|
453
|
+
- Check that auth messages are being received
|
|
454
|
+
|
|
455
|
+
### Height not updating
|
|
456
|
+
- Implement `onResize` callback
|
|
457
|
+
- Ensure iframe has CSS styling for height changes
|
|
458
|
+
- Check that iframe is sending resize messages
|
|
459
|
+
|
|
460
|
+
### Cache not working
|
|
461
|
+
- Verify cache storage option is supported (sessionStorage/localStorage)
|
|
462
|
+
- Check browser storage isn't disabled
|
|
463
|
+
- Clear cache and retry with `smartlinks.cache.clear()`
|
package/dist/iframe.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { IframeResponder, isAdminFromRoles, buildIframeSrc, } from './iframeResponder';
|
|
2
|
+
export type { IframeResponderOptions, CachedData, CollectionApp, RouteChangeMessage, SmartlinksIframeMessage, ProxyRequest, CustomProxyRequest, UploadStartMessage, UploadChunkMessage, UploadEndMessage, } from './types/iframeResponder';
|
|
1
3
|
export declare namespace iframe {
|
|
2
4
|
interface IframeResizeOptions {
|
|
3
5
|
/** Minimum ms between height postMessages (default 100). */
|
package/dist/iframe.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Utilities to communicate with parent window when running inside an iframe.
|
|
3
3
|
// These helpers are optional and safe in non-browser / Node environments.
|
|
4
4
|
// They build on the existing proxyMode infrastructure but can also be used standalone.
|
|
5
|
+
// Re-export IframeResponder for parent-side iframe communication
|
|
6
|
+
export { IframeResponder, isAdminFromRoles, buildIframeSrc, } from './iframeResponder';
|
|
5
7
|
export var iframe;
|
|
6
8
|
(function (iframe) {
|
|
7
9
|
let autoResizeTimer;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { IframeResponderOptions, CachedData } from './types/iframeResponder';
|
|
2
|
+
/**
|
|
3
|
+
* Parent-side iframe responder for SmartLinks microapp embedding.
|
|
4
|
+
*
|
|
5
|
+
* Handles all bidirectional communication with embedded iframes:
|
|
6
|
+
* - API proxy requests (with caching)
|
|
7
|
+
* - Authentication state synchronization
|
|
8
|
+
* - Deep linking / route changes
|
|
9
|
+
* - Resize management
|
|
10
|
+
* - Chunked file upload proxying
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const responder = new IframeResponder({
|
|
15
|
+
* collectionId: 'my-collection',
|
|
16
|
+
* appId: 'warranty',
|
|
17
|
+
* onAuthLogin: async (token, user) => {
|
|
18
|
+
* smartlinks.setBearerToken(token);
|
|
19
|
+
* },
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const src = await responder.attach(iframeElement);
|
|
23
|
+
* iframeElement.src = src;
|
|
24
|
+
*
|
|
25
|
+
* // Cleanup
|
|
26
|
+
* responder.destroy();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class IframeResponder {
|
|
30
|
+
private iframe;
|
|
31
|
+
private options;
|
|
32
|
+
private cache;
|
|
33
|
+
private uploads;
|
|
34
|
+
private isInitialLoad;
|
|
35
|
+
private messageHandler;
|
|
36
|
+
private resizeHandler;
|
|
37
|
+
private appUrl;
|
|
38
|
+
private ready;
|
|
39
|
+
private resolveReady;
|
|
40
|
+
constructor(options: IframeResponderOptions);
|
|
41
|
+
/**
|
|
42
|
+
* Attach to an iframe element.
|
|
43
|
+
* Returns the src URL to set on the iframe.
|
|
44
|
+
*/
|
|
45
|
+
attach(iframe: HTMLIFrameElement): Promise<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Update cached data (e.g., after user logs in).
|
|
48
|
+
*/
|
|
49
|
+
updateCache(data: Partial<CachedData>): void;
|
|
50
|
+
/**
|
|
51
|
+
* Cleanup - remove event listeners and clear state.
|
|
52
|
+
*/
|
|
53
|
+
destroy(): void;
|
|
54
|
+
private resolveAppUrl;
|
|
55
|
+
private getVersionUrl;
|
|
56
|
+
private buildIframeSrc;
|
|
57
|
+
private calculateViewportHeight;
|
|
58
|
+
private handleMessage;
|
|
59
|
+
private handleRouteChange;
|
|
60
|
+
private handleStandardMessage;
|
|
61
|
+
private handleProxyRequest;
|
|
62
|
+
private getCachedResponse;
|
|
63
|
+
private handleUpload;
|
|
64
|
+
private sendResponse;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Determine admin status from collection/proof roles.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isAdminFromRoles(user: {
|
|
70
|
+
uid: string;
|
|
71
|
+
} | null | undefined, collection?: {
|
|
72
|
+
roles?: Record<string, any>;
|
|
73
|
+
}, proof?: {
|
|
74
|
+
roles?: Record<string, any>;
|
|
75
|
+
}): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Build iframe src URL with all context params.
|
|
78
|
+
* Standalone helper for cases where you don't need the full IframeResponder.
|
|
79
|
+
*/
|
|
80
|
+
export declare function buildIframeSrc(options: {
|
|
81
|
+
appUrl: string;
|
|
82
|
+
collectionId: string;
|
|
83
|
+
appId: string;
|
|
84
|
+
productId?: string;
|
|
85
|
+
proofId?: string;
|
|
86
|
+
isAdmin?: boolean;
|
|
87
|
+
dark?: boolean;
|
|
88
|
+
theme?: {
|
|
89
|
+
primary?: string;
|
|
90
|
+
secondary?: string;
|
|
91
|
+
};
|
|
92
|
+
initialPath?: string;
|
|
93
|
+
}): string;
|