@rehers/rehers-roleplay-sdk 2.1.5 → 2.3.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/README.md +10 -15
- package/index.d.ts +2 -4
- package/package.json +1 -1
- package/roleplay-sdk.js +34 -25
package/README.md
CHANGED
|
@@ -25,7 +25,6 @@ Or load via CDN:
|
|
|
25
25
|
userId: 'user_789',
|
|
26
26
|
userEmail: 'john@example.com',
|
|
27
27
|
userRole: 'member', // optional — "owner", "admin", or "member"
|
|
28
|
-
trialUrl: 'https://seamless.ai/pricing', // optional — shown when user not found
|
|
29
28
|
onReady: function() {
|
|
30
29
|
console.log('SDK ready');
|
|
31
30
|
},
|
|
@@ -48,7 +47,10 @@ Or load via CDN:
|
|
|
48
47
|
onError: function(data) { console.error('Error:', data.code, data.message); },
|
|
49
48
|
});
|
|
50
49
|
|
|
51
|
-
// 2b. Or mount into a container (full-page embed)
|
|
50
|
+
// 2b. Or mount the full app into a container (full-page embed)
|
|
51
|
+
SeamlessRoleplay.mount(document.getElementById('roleplay-container'));
|
|
52
|
+
|
|
53
|
+
// 2c. Or mount a call for a specific contact into a container
|
|
52
54
|
SeamlessRoleplay.mount(document.getElementById('roleplay-container'), {
|
|
53
55
|
name: 'Jane Smith',
|
|
54
56
|
domain: 'acme.com',
|
|
@@ -77,16 +79,7 @@ Or load via CDN:
|
|
|
77
79
|
|
|
78
80
|
## Trial Mode
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
```js
|
|
83
|
-
SeamlessRoleplay.init({
|
|
84
|
-
publishableKey: 'pk_live_abc123',
|
|
85
|
-
userId: 'unknown_user',
|
|
86
|
-
userEmail: 'unknown@example.com',
|
|
87
|
-
trialUrl: 'https://seamless.ai/pricing',
|
|
88
|
-
});
|
|
89
|
-
```
|
|
82
|
+
When the backend returns `USER_NOT_FOUND`, it includes a `paymentLink` in the response. The SDK automatically captures it and renders a trial screen directing the user to sign up — no client-side configuration needed.
|
|
90
83
|
|
|
91
84
|
## API
|
|
92
85
|
|
|
@@ -99,7 +92,6 @@ SeamlessRoleplay.init({
|
|
|
99
92
|
| `userEmail` | `string` | Yes | User email for secure account matching |
|
|
100
93
|
| `userRole` | `string` | No | User role — `"owner"`, `"admin"`, or `"member"` |
|
|
101
94
|
| `userToken` | `string` | No | Signed JWT for identity verification |
|
|
102
|
-
| `trialUrl` | `string` | No | URL shown when user not found |
|
|
103
95
|
| `origin` | `string` | No | Override app origin (dev only) |
|
|
104
96
|
| `onReady` | `function` | No | Called when session is ready |
|
|
105
97
|
| `onError` | `function` | No | Called on init error `({ code, message })` |
|
|
@@ -121,9 +113,12 @@ Opens the roleplay in a modal dialog overlay.
|
|
|
121
113
|
| `onClose` | `function` | No | Called when dialog closes |
|
|
122
114
|
| `onError` | `function` | No | `({ code, message })` |
|
|
123
115
|
|
|
124
|
-
### `SeamlessRoleplay.mount(container, data)`
|
|
116
|
+
### `SeamlessRoleplay.mount(container, data?)`
|
|
117
|
+
|
|
118
|
+
Mounts into a DOM element. Two modes:
|
|
125
119
|
|
|
126
|
-
|
|
120
|
+
- **`mount(container)`** — embeds the full Roleplay app (dashboard, scenarios, call logs)
|
|
121
|
+
- **`mount(container, data)`** — embeds a roleplay call for a specific contact (same `data` options as `open()`)
|
|
127
122
|
|
|
128
123
|
### `SeamlessRoleplay.addToScenario(options)`
|
|
129
124
|
|
package/index.d.ts
CHANGED
|
@@ -9,8 +9,6 @@ export interface SeamlessRoleplayInitOptions {
|
|
|
9
9
|
userRole?: "owner" | "admin" | "member";
|
|
10
10
|
/** Optional signed JWT for identity verification */
|
|
11
11
|
userToken?: string;
|
|
12
|
-
/** URL shown when the user is not found (trial mode) */
|
|
13
|
-
trialUrl?: string;
|
|
14
12
|
/** Override the app origin — where the iframe loads from (for dev/testing only) */
|
|
15
13
|
origin?: string;
|
|
16
14
|
/** Called when the SDK session is ready */
|
|
@@ -80,8 +78,8 @@ export interface SeamlessRoleplaySDK {
|
|
|
80
78
|
init(options: SeamlessRoleplayInitOptions): void;
|
|
81
79
|
/** Open the roleplay modal for a contact (dialog mode). */
|
|
82
80
|
open(data: SeamlessRoleplayOpenData): void;
|
|
83
|
-
/** Mount the
|
|
84
|
-
mount(container: HTMLElement, data
|
|
81
|
+
/** Mount the full Roleplay app into a container (no data), or a call embed for a specific contact (with data). */
|
|
82
|
+
mount(container: HTMLElement, data?: SeamlessRoleplayOpenData): void;
|
|
85
83
|
/** Open the add-to-scenario dialog for bulk contact import. */
|
|
86
84
|
addToScenario(options: AddToScenarioOptions): void;
|
|
87
85
|
/** Close the roleplay dialog or unmount. */
|
package/package.json
CHANGED
package/roleplay-sdk.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
var userEmail = null;
|
|
22
22
|
var userRole = null;
|
|
23
23
|
var userToken = null;
|
|
24
|
-
var
|
|
24
|
+
var paymentLink = null;
|
|
25
25
|
var appOrigin = null;
|
|
26
26
|
|
|
27
27
|
var sessionToken = null;
|
|
@@ -116,6 +116,7 @@
|
|
|
116
116
|
if (data.error === "USER_NOT_FOUND") {
|
|
117
117
|
// Trial mode — not a fatal error
|
|
118
118
|
sessionToken = null;
|
|
119
|
+
if (data.paymentLink) paymentLink = data.paymentLink;
|
|
119
120
|
resolve({ trialMode: true });
|
|
120
121
|
return;
|
|
121
122
|
}
|
|
@@ -216,31 +217,32 @@
|
|
|
216
217
|
userId: userId,
|
|
217
218
|
contacts: addToScenarioPendingContacts,
|
|
218
219
|
};
|
|
219
|
-
if (
|
|
220
|
+
if (paymentLink) msg.paymentLink = paymentLink;
|
|
220
221
|
sendToIframe(msg);
|
|
221
|
-
} else if (token
|
|
222
|
-
|
|
222
|
+
} else if (token) {
|
|
223
|
+
var msg = {
|
|
223
224
|
type: "seamless-session-init",
|
|
224
225
|
sessionToken: token,
|
|
225
|
-
contact: {
|
|
226
|
+
contact: pendingContactData ? {
|
|
226
227
|
name: pendingContactData.name,
|
|
227
228
|
domain: pendingContactData.domain,
|
|
228
229
|
company: pendingContactData.company,
|
|
229
230
|
title: pendingContactData.title,
|
|
230
231
|
companyDescription: pendingContactData.companyDescription || undefined,
|
|
231
232
|
liUrl: pendingContactData.liUrl || undefined,
|
|
232
|
-
},
|
|
233
|
-
}
|
|
234
|
-
|
|
233
|
+
} : null,
|
|
234
|
+
};
|
|
235
|
+
sendToIframe(msg);
|
|
236
|
+
} else if (paymentLink) {
|
|
235
237
|
sendToIframe({
|
|
236
238
|
type: "seamless-session-init",
|
|
237
|
-
|
|
239
|
+
paymentLink: paymentLink,
|
|
238
240
|
contact: null,
|
|
239
241
|
});
|
|
240
242
|
} else {
|
|
241
243
|
sendToIframe({
|
|
242
244
|
type: "seamless-session-init",
|
|
243
|
-
|
|
245
|
+
paymentLink: null,
|
|
244
246
|
contact: null,
|
|
245
247
|
});
|
|
246
248
|
}
|
|
@@ -335,9 +337,9 @@
|
|
|
335
337
|
|
|
336
338
|
// ── Create iframe ───────────────────────────────────────────────────
|
|
337
339
|
|
|
338
|
-
function createIframe() {
|
|
340
|
+
function createIframe(path) {
|
|
339
341
|
var iframeEl = document.createElement("iframe");
|
|
340
|
-
iframeEl.src = getOrigin() + "/embed/roleplay-call";
|
|
342
|
+
iframeEl.src = getOrigin() + (path || "/embed/roleplay-call");
|
|
341
343
|
iframeEl.allow = "camera; microphone; display-capture; autoplay";
|
|
342
344
|
iframeEl.style.width = "100%";
|
|
343
345
|
iframeEl.style.height = "100%";
|
|
@@ -373,7 +375,6 @@
|
|
|
373
375
|
userEmail = opts.userEmail || null;
|
|
374
376
|
userRole = opts.userRole || null;
|
|
375
377
|
userToken = opts.userToken || null;
|
|
376
|
-
trialUrl = opts.trialUrl || null;
|
|
377
378
|
appOrigin = opts.origin || null;
|
|
378
379
|
initCallbacks.onReady = opts.onReady || null;
|
|
379
380
|
initCallbacks.onError = opts.onError || null;
|
|
@@ -382,8 +383,8 @@
|
|
|
382
383
|
// Fetch session immediately
|
|
383
384
|
fetchSession()
|
|
384
385
|
.then(function (result) {
|
|
385
|
-
if (result.trialMode && !
|
|
386
|
-
// User not found and no
|
|
386
|
+
if (result.trialMode && !paymentLink) {
|
|
387
|
+
// User not found and no payment link from server — still call onReady
|
|
387
388
|
// The open() will show an error state in the iframe
|
|
388
389
|
}
|
|
389
390
|
if (initCallbacks.onReady) initCallbacks.onReady();
|
|
@@ -502,7 +503,11 @@
|
|
|
502
503
|
},
|
|
503
504
|
|
|
504
505
|
/**
|
|
505
|
-
* Mount the roleplay into a container element
|
|
506
|
+
* Mount the roleplay into a container element.
|
|
507
|
+
*
|
|
508
|
+
* Two modes:
|
|
509
|
+
* mount(container) — full app embed (dashboard, scenarios, call logs, etc.)
|
|
510
|
+
* mount(container, contactData) — roleplay call embed for a specific contact
|
|
506
511
|
*/
|
|
507
512
|
mount: function (container, data) {
|
|
508
513
|
try {
|
|
@@ -514,19 +519,22 @@
|
|
|
514
519
|
logError("mount", "requires a DOM element as first argument");
|
|
515
520
|
return;
|
|
516
521
|
}
|
|
517
|
-
|
|
518
|
-
|
|
522
|
+
|
|
523
|
+
// If contact data is provided, validate required fields
|
|
524
|
+
var hasContactData = data && data.name && data.domain && data.company && data.title;
|
|
525
|
+
if (data && !hasContactData && (data.name || data.domain || data.company || data.title)) {
|
|
526
|
+
logError("mount", "contact data requires { name, domain, company, title }");
|
|
519
527
|
return;
|
|
520
528
|
}
|
|
521
529
|
|
|
522
530
|
// If already open, tear down first (also cancels any pending close timer)
|
|
523
531
|
if (overlay || (iframe && mode)) teardown();
|
|
524
532
|
|
|
525
|
-
pendingContactData = data;
|
|
526
|
-
callbacks.onCallStarted = data.onCallStarted || null;
|
|
527
|
-
callbacks.onCallEnded = data.onCallEnded || null;
|
|
528
|
-
callbacks.onClose = data.onClose || null;
|
|
529
|
-
callbacks.onError = data.onError || null;
|
|
533
|
+
pendingContactData = hasContactData ? data : null;
|
|
534
|
+
callbacks.onCallStarted = (data && data.onCallStarted) || null;
|
|
535
|
+
callbacks.onCallEnded = (data && data.onCallEnded) || null;
|
|
536
|
+
callbacks.onClose = (data && data.onClose) || null;
|
|
537
|
+
callbacks.onError = (data && data.onError) || null;
|
|
530
538
|
mode = "mount";
|
|
531
539
|
mountContainer = container;
|
|
532
540
|
|
|
@@ -534,7 +542,8 @@
|
|
|
534
542
|
listener = handleMessage;
|
|
535
543
|
window.addEventListener("message", listener);
|
|
536
544
|
|
|
537
|
-
|
|
545
|
+
// No contact data → full app embed at root; with contact → /embed/roleplay-call
|
|
546
|
+
var iframeEl = createIframe(hasContactData ? "/embed/roleplay-call" : "/");
|
|
538
547
|
iframe = iframeEl;
|
|
539
548
|
container.appendChild(iframeEl);
|
|
540
549
|
} catch (e) {
|
|
@@ -703,7 +712,7 @@
|
|
|
703
712
|
userEmail = null;
|
|
704
713
|
userRole = null;
|
|
705
714
|
userToken = null;
|
|
706
|
-
|
|
715
|
+
paymentLink = null;
|
|
707
716
|
sessionToken = null;
|
|
708
717
|
sessionExpiresAt = 0;
|
|
709
718
|
fetchingSession = null;
|