@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 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
- If the user doesn't have an active account, provide a `trialUrl` during init. When the backend returns `USER_NOT_FOUND`, the SDK will render a trial screen:
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
- Mounts the roleplay into a DOM element (full-page embed). Same `data` options as `open()`.
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 roleplay into a container element (full-page embed). */
84
- mount(container: HTMLElement, data: SeamlessRoleplayOpenData): void;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rehers/rehers-roleplay-sdk",
3
- "version": "2.1.5",
3
+ "version": "2.3.0",
4
4
  "description": "Seamless Roleplay SDK — embed roleplay call sessions via a modal + iframe",
5
5
  "main": "roleplay-sdk.js",
6
6
  "types": "index.d.ts",
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 trialUrl = null;
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 (trialUrl) msg.trialUrl = trialUrl;
220
+ if (paymentLink) msg.paymentLink = paymentLink;
220
221
  sendToIframe(msg);
221
- } else if (token && pendingContactData) {
222
- sendToIframe({
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
- } else if (trialUrl) {
233
+ } : null,
234
+ };
235
+ sendToIframe(msg);
236
+ } else if (paymentLink) {
235
237
  sendToIframe({
236
238
  type: "seamless-session-init",
237
- trialUrl: trialUrl,
239
+ paymentLink: paymentLink,
238
240
  contact: null,
239
241
  });
240
242
  } else {
241
243
  sendToIframe({
242
244
  type: "seamless-session-init",
243
- trialUrl: null,
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 && !trialUrl) {
386
- // User not found and no trial URL configured — still call onReady
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 (full-page embed).
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
- if (!data || !data.name || !data.domain || !data.company || !data.title) {
518
- logError("mount", "requires { name, domain, company, title }");
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
- var iframeEl = createIframe();
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
- trialUrl = null;
715
+ paymentLink = null;
707
716
  sessionToken = null;
708
717
  sessionExpiresAt = 0;
709
718
  fetchingSession = null;