@corti/embedded-web 0.1.1 → 0.3.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.
Files changed (53) hide show
  1. package/README.md +92 -50
  2. package/dist/CortiEmbedded.d.ts +34 -7
  3. package/dist/CortiEmbedded.js +274 -106
  4. package/dist/CortiEmbedded.js.map +1 -1
  5. package/dist/bundle.js +1699 -20
  6. package/dist/corti-embedded.d.ts +17 -1
  7. package/dist/corti-embedded.js +4 -3
  8. package/dist/corti-embedded.js.map +1 -1
  9. package/dist/index.d.ts +5 -5
  10. package/dist/index.js +5 -5
  11. package/dist/index.js.map +1 -1
  12. package/dist/public-types.d.ts +185 -0
  13. package/dist/public-types.js +2 -0
  14. package/dist/public-types.js.map +1 -0
  15. package/dist/react/CortiEmbeddedReact.d.ts +32 -23
  16. package/dist/react/CortiEmbeddedReact.js +69 -21
  17. package/dist/react/CortiEmbeddedReact.js.map +1 -1
  18. package/dist/react/index.d.ts +2 -2
  19. package/dist/react/index.js +1 -1
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/styles/base.js +1 -1
  22. package/dist/styles/base.js.map +1 -1
  23. package/dist/styles/container-styles.js +2 -2
  24. package/dist/styles/container-styles.js.map +1 -1
  25. package/dist/styles/theme.js +2 -2
  26. package/dist/styles/theme.js.map +1 -1
  27. package/dist/types/api.d.ts +36 -22
  28. package/dist/types/api.js.map +1 -1
  29. package/dist/types/config.d.ts +16 -2
  30. package/dist/types/config.js.map +1 -1
  31. package/dist/types/index.js +1 -1
  32. package/dist/types/index.js.map +1 -1
  33. package/dist/types/payloads.d.ts +36 -4
  34. package/dist/types/payloads.js.map +1 -1
  35. package/dist/types/protocol.d.ts +9 -4
  36. package/dist/types/protocol.js.map +1 -1
  37. package/dist/types/responses.d.ts +10 -2
  38. package/dist/types/responses.js.map +1 -1
  39. package/dist/utils/PostMessageHandler.d.ts +19 -70
  40. package/dist/utils/PostMessageHandler.js +98 -201
  41. package/dist/utils/PostMessageHandler.js.map +1 -1
  42. package/dist/utils/baseUrl.js +8 -8
  43. package/dist/utils/baseUrl.js.map +1 -1
  44. package/dist/utils/embedUrl.js +3 -3
  45. package/dist/utils/embedUrl.js.map +1 -1
  46. package/dist/utils/errorFormatter.js +44 -20
  47. package/dist/utils/errorFormatter.js.map +1 -1
  48. package/dist/web-bundle.js +1555 -13
  49. package/dist/web-index.d.ts +3 -3
  50. package/dist/web-index.js +4 -4
  51. package/dist/web-index.js.map +1 -1
  52. package/package.json +20 -20
  53. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -4,27 +4,70 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { html, LitElement } from 'lit';
8
- import { property } from 'lit/decorators.js';
9
- import { baseStyles } from './styles/base.js';
10
- import { containerStyles } from './styles/container-styles.js';
11
- import { validateAndNormalizeBaseURL } from './utils/baseUrl.js';
12
- import { buildEmbeddedUrl, isRealEmbeddedLoad } from './utils/embedUrl.js';
13
- import { formatError } from './utils/errorFormatter.js';
14
- import { PostMessageHandler, } from './utils/PostMessageHandler.js';
7
+ import { html, LitElement } from "lit";
8
+ import { property } from "lit/decorators.js";
9
+ import { baseStyles } from "./styles/base.js";
10
+ import { containerStyles } from "./styles/container-styles.js";
11
+ import { validateAndNormalizeBaseURL } from "./utils/baseUrl.js";
12
+ import { buildEmbeddedUrl, isRealEmbeddedLoad } from "./utils/embedUrl.js";
13
+ import { formatError } from "./utils/errorFormatter.js";
14
+ import { PostMessageHandler, } from "./utils/PostMessageHandler.js";
15
+ const IFRAME_SANDBOX_POLICY = "allow-forms allow-modals allow-scripts allow-same-origin";
16
+ const DEPRECATION_TIMELINE_URL = "https://docs.corti.ai/assistant/deprecation-timeline";
17
+ const CONFIGURATION_MIGRATION_URL = "https://docs.corti.ai/assistant/configuration-migration";
18
+ const DEPRECATED_EVENT_SUBSCRIPTIONS = new Set([
19
+ "ready",
20
+ "loaded",
21
+ "recordingStarted",
22
+ "recordingStopped",
23
+ "documentGenerated",
24
+ "documentUpdated",
25
+ "documentSynced",
26
+ "authChanged",
27
+ "interactionCreated",
28
+ "navigationChanged",
29
+ "usage",
30
+ "embedded-event",
31
+ ]);
15
32
  export class CortiEmbedded extends LitElement {
16
33
  constructor() {
17
34
  super(...arguments);
18
- this.visibility = 'hidden';
35
+ this.visibility = "hidden";
19
36
  this.postMessageHandler = null;
20
37
  this.normalizedBaseURL = null;
38
+ this.warnedDeprecatedEventSubscriptions = new Set();
39
+ }
40
+ addEventListener(type, callback, options) {
41
+ this.warnDeprecatedEventSubscription(type);
42
+ super.addEventListener(type, callback, options);
43
+ }
44
+ warnDeprecatedEventSubscription(eventName) {
45
+ if (!DEPRECATED_EVENT_SUBSCRIPTIONS.has(eventName) ||
46
+ this.warnedDeprecatedEventSubscriptions.has(eventName)) {
47
+ return;
48
+ }
49
+ this.warnedDeprecatedEventSubscriptions.add(eventName);
50
+ console.warn(`[Corti Embedded] The '${eventName}' event subscription is deprecated and will be removed in a future release. Subscribe to the canonical 'event' stream instead. See ${DEPRECATION_TIMELINE_URL}.`);
51
+ }
52
+ // eslint-disable-next-line class-methods-use-this
53
+ getIframeAllowPolicy(normalizedBaseURL) {
54
+ const permissionTarget = normalizedBaseURL
55
+ ? new URL(normalizedBaseURL).origin
56
+ : "*";
57
+ return [
58
+ `microphone ${permissionTarget}`,
59
+ `camera ${permissionTarget}`,
60
+ `device-capture ${permissionTarget}`,
61
+ `display-capture ${permissionTarget}`,
62
+ `clipboard-write ${permissionTarget}`,
63
+ ].join("; ");
21
64
  }
22
65
  connectedCallback() {
23
66
  super.connectedCallback();
24
67
  // Ensure baseURL is provided
25
68
  if (!this.baseURL) {
26
69
  this.dispatchErrorEvent({
27
- message: 'baseURL is required',
70
+ message: "baseURL is required",
28
71
  });
29
72
  return;
30
73
  }
@@ -34,9 +77,10 @@ export class CortiEmbedded extends LitElement {
34
77
  }
35
78
  catch (error) {
36
79
  this.dispatchErrorEvent({
37
- message: error.message || 'Invalid baseURL',
80
+ message: error.message || "Invalid baseURL",
38
81
  });
39
- throw error;
82
+ // Dispatch the error event rather than throwing so consumers can handle it
83
+ // via the 'error' event listener without wrapping connectedCallback in try/catch.
40
84
  }
41
85
  }
42
86
  disconnectedCallback() {
@@ -65,7 +109,7 @@ export class CortiEmbedded extends LitElement {
65
109
  }
66
110
  else {
67
111
  this.dispatchErrorEvent({
68
- message: 'No iframe or contentWindow available',
112
+ message: "No iframe or contentWindow available",
69
113
  });
70
114
  }
71
115
  }
@@ -73,18 +117,32 @@ export class CortiEmbedded extends LitElement {
73
117
  this.dispatchEvent(new CustomEvent(event, { detail: data }));
74
118
  }
75
119
  dispatchEmbeddedEvent(rawEventName, payload) {
76
- // Preserve raw DOM event passthrough for consumers listening directly.
120
+ if (rawEventName === "ready" || rawEventName === "loaded")
121
+ return;
122
+ // Pass all other events through as raw DOM events for direct listeners.
77
123
  this.dispatchPublicEvent(rawEventName, payload);
78
- this.dispatchPublicEvent('embedded-event', {
124
+ // Forward supported embedded events through the generic 'event' stream so
125
+ // consumers can observe them without subscribing to each raw event name.
126
+ this.dispatchPublicEvent("event", {
127
+ name: rawEventName,
128
+ payload,
129
+ });
130
+ // Also emit the legacy 'embedded-event' stream for backward compatibility.
131
+ // This allows existing integrations listening for 'embedded-event' to continue
132
+ // working while newer consumers can use the 'event' stream.
133
+ this.dispatchPublicEvent("embedded-event", {
79
134
  name: rawEventName,
80
135
  payload,
81
136
  });
82
137
  }
83
138
  dispatchErrorEvent(error) {
84
- this.dispatchPublicEvent('error', error);
139
+ this.dispatchPublicEvent("error", error);
140
+ }
141
+ static warnDeprecatedAPI(methodName, replacement) {
142
+ console.warn(`[Corti Embedded] ${methodName} is deprecated and will be removed in a future release. Use ${replacement} instead. See ${CONFIGURATION_MIGRATION_URL} and ${DEPRECATION_TIMELINE_URL}.`);
85
143
  }
86
144
  isRealIframeLoad(iframe) {
87
- const src = iframe.getAttribute('src') || '';
145
+ const src = iframe.getAttribute("src") || "";
88
146
  if (!this.normalizedBaseURL)
89
147
  return false;
90
148
  return isRealEmbeddedLoad(src, this.normalizedBaseURL);
@@ -108,43 +166,38 @@ export class CortiEmbedded extends LitElement {
108
166
  }
109
167
  }
110
168
  getIframe() {
111
- return this.shadowRoot?.querySelector('iframe') || null;
169
+ return this.shadowRoot?.querySelector("iframe") || null;
112
170
  }
113
171
  updated(changedProps) {
114
172
  super.updated(changedProps);
115
- if (changedProps.has('baseURL')) {
116
- // Validate baseURL and normalize; fail fast on invalid input
173
+ if (changedProps.has("baseURL")) {
174
+ // Tear down the existing handler; the new one is created in handleIframeLoad
175
+ if (this.postMessageHandler) {
176
+ this.postMessageHandler.destroy();
177
+ this.postMessageHandler = null;
178
+ }
179
+ // Validate the new URL
117
180
  try {
118
181
  this.normalizedBaseURL = validateAndNormalizeBaseURL(this.baseURL);
119
182
  }
120
183
  catch (error) {
121
- // Tear down and clear iframe to avoid keeping an old origin active
122
- if (this.postMessageHandler) {
123
- this.postMessageHandler.destroy();
124
- this.postMessageHandler = null;
125
- }
184
+ this.normalizedBaseURL = null;
126
185
  const iframe = this.getIframe();
127
186
  if (iframe) {
128
- iframe.setAttribute('src', 'about:blank');
187
+ iframe.setAttribute("src", "about:blank");
129
188
  }
130
189
  this.dispatchErrorEvent({
131
- message: error.message || 'Invalid baseURL',
190
+ message: error.message || "Invalid baseURL",
132
191
  });
133
192
  return;
134
193
  }
135
- // Tear down existing handler and re-point iframe to new URL
136
- if (this.postMessageHandler) {
137
- this.postMessageHandler.destroy();
138
- this.postMessageHandler = null;
139
- }
194
+ // Update the iframe to the new URL
140
195
  const iframe = this.getIframe();
141
196
  if (iframe) {
142
- const expected = this.normalizedBaseURL
143
- ? buildEmbeddedUrl(this.normalizedBaseURL)
144
- : '';
145
- if (iframe.getAttribute('src') !== expected) {
146
- iframe.setAttribute('src', expected);
147
- iframe.setAttribute('allow', `microphone ${expected}; camera ${expected}; device-capture ${expected}; display-capture ${expected}`);
197
+ const expected = buildEmbeddedUrl(this.normalizedBaseURL);
198
+ iframe.setAttribute("allow", this.getIframeAllowPolicy(expected));
199
+ if (iframe.getAttribute("src") !== expected) {
200
+ iframe.setAttribute("src", expected);
148
201
  }
149
202
  }
150
203
  }
@@ -157,7 +210,7 @@ export class CortiEmbedded extends LitElement {
157
210
  */
158
211
  async auth(credentials) {
159
212
  if (!this.postMessageHandler) {
160
- throw new Error('Component not ready');
213
+ throw new Error("Component not ready");
161
214
  }
162
215
  try {
163
216
  const payload = {
@@ -168,18 +221,24 @@ export class CortiEmbedded extends LitElement {
168
221
  refresh_expires_in: credentials.refresh_expires_in,
169
222
  refresh_token: credentials.refresh_token,
170
223
  id_token: credentials.id_token,
171
- 'not-before-policy': credentials['not-before-policy'],
224
+ "not-before-policy": credentials["not-before-policy"],
172
225
  session_state: credentials.session_state,
173
226
  scope: credentials.scope,
174
227
  profile: credentials.profile,
175
- mode: credentials.mode,
176
228
  };
177
- const user = await this.postMessageHandler.auth(payload);
178
- return user;
229
+ const response = await this.postMessageHandler.postMessage({
230
+ type: "CORTI_EMBEDDED",
231
+ version: "v1",
232
+ action: "auth",
233
+ payload,
234
+ });
235
+ if (response.success && response.payload) {
236
+ return response.payload.user;
237
+ }
238
+ throw new Error(response.error);
179
239
  }
180
240
  catch (error) {
181
- const formattedError = formatError(error, 'Authentication failed');
182
- this.dispatchErrorEvent(formattedError);
241
+ const formattedError = formatError(error, "Authentication failed");
183
242
  throw new Error(JSON.stringify(formattedError));
184
243
  }
185
244
  }
@@ -190,18 +249,26 @@ export class CortiEmbedded extends LitElement {
190
249
  */
191
250
  async createInteraction(encounter) {
192
251
  if (!this.postMessageHandler) {
193
- throw new Error('Component not ready');
252
+ throw new Error("Component not ready");
194
253
  }
195
254
  try {
196
- const response = await this.postMessageHandler.createInteraction(encounter);
197
- return {
198
- id: response.id,
199
- createdAt: response.createdAt,
200
- };
255
+ const response = await this.postMessageHandler.postMessage({
256
+ type: "CORTI_EMBEDDED",
257
+ version: "v1",
258
+ action: "createInteraction",
259
+ payload: encounter,
260
+ });
261
+ if (response.success && response.payload) {
262
+ const result = response.payload;
263
+ return {
264
+ id: result.id,
265
+ createdAt: result.createdAt,
266
+ };
267
+ }
268
+ throw new Error(response.error);
201
269
  }
202
270
  catch (error) {
203
- const formattedError = formatError(error, 'Failed to create interaction');
204
- this.dispatchErrorEvent(formattedError);
271
+ const formattedError = formatError(error, "Failed to create interaction");
205
272
  throw new Error(JSON.stringify(formattedError));
206
273
  }
207
274
  }
@@ -212,20 +279,25 @@ export class CortiEmbedded extends LitElement {
212
279
  */
213
280
  async configureSession(config) {
214
281
  if (!this.postMessageHandler) {
215
- throw new Error('Component not ready');
282
+ throw new Error("Component not ready");
216
283
  }
217
284
  try {
285
+ CortiEmbedded.warnDeprecatedAPI("configureSession()", "setInteractionOptions()");
218
286
  const payload = {
219
287
  defaultLanguage: config.defaultLanguage,
220
288
  defaultOutputLanguage: config.defaultOutputLanguage,
221
289
  defaultTemplateKey: config.defaultTemplateKey,
222
290
  defaultMode: config.defaultMode,
223
291
  };
224
- await this.postMessageHandler.configureSession(payload);
292
+ await this.postMessageHandler.postMessage({
293
+ type: "CORTI_EMBEDDED",
294
+ version: "v1",
295
+ action: "configureSession",
296
+ payload,
297
+ });
225
298
  }
226
299
  catch (error) {
227
- const formattedError = formatError(error, 'Failed to configure session');
228
- this.dispatchErrorEvent(formattedError);
300
+ const formattedError = formatError(error, "Failed to configure session");
229
301
  throw new Error(JSON.stringify(formattedError));
230
302
  }
231
303
  }
@@ -236,34 +308,42 @@ export class CortiEmbedded extends LitElement {
236
308
  */
237
309
  async addFacts(facts) {
238
310
  if (!this.postMessageHandler) {
239
- throw new Error('Component not ready');
311
+ throw new Error("Component not ready");
240
312
  }
241
313
  try {
242
314
  const payload = { facts };
243
- await this.postMessageHandler.addFacts(payload);
315
+ await this.postMessageHandler.postMessage({
316
+ type: "CORTI_EMBEDDED",
317
+ version: "v1",
318
+ action: "addFacts",
319
+ payload,
320
+ });
244
321
  }
245
322
  catch (error) {
246
- const formattedError = formatError(error, 'Failed to add facts');
247
- this.dispatchErrorEvent(formattedError);
323
+ const formattedError = formatError(error, "Failed to add facts");
248
324
  throw new Error(JSON.stringify(formattedError));
249
325
  }
250
326
  }
251
327
  /**
252
328
  * Navigate to a specific path within the embedded UI
253
- * @param path Path to navigate to
329
+ * @param payload Navigation request payload or legacy path string
254
330
  * @returns Promise that resolves when navigation is complete
255
331
  */
256
- async navigate(path) {
332
+ async navigate(payload) {
257
333
  if (!this.postMessageHandler) {
258
- throw new Error('Component not ready');
334
+ throw new Error("Component not ready");
259
335
  }
260
336
  try {
261
- const payload = { path };
262
- await this.postMessageHandler.navigate(payload);
337
+ const normalizedPayload = typeof payload === "string" ? { path: payload } : payload;
338
+ await this.postMessageHandler.postMessage({
339
+ type: "CORTI_EMBEDDED",
340
+ version: "v1",
341
+ action: "navigate",
342
+ payload: normalizedPayload,
343
+ });
263
344
  }
264
345
  catch (error) {
265
- const formattedError = formatError(error, 'Failed to navigate');
266
- this.dispatchErrorEvent(formattedError);
346
+ const formattedError = formatError(error, "Failed to navigate");
267
347
  throw new Error(JSON.stringify(formattedError));
268
348
  }
269
349
  }
@@ -273,14 +353,18 @@ export class CortiEmbedded extends LitElement {
273
353
  */
274
354
  async startRecording() {
275
355
  if (!this.postMessageHandler) {
276
- throw new Error('Component not ready');
356
+ throw new Error("Component not ready");
277
357
  }
278
358
  try {
279
- await this.postMessageHandler.startRecording();
359
+ await this.postMessageHandler.postMessage({
360
+ type: "CORTI_EMBEDDED",
361
+ version: "v1",
362
+ action: "startRecording",
363
+ payload: {},
364
+ });
280
365
  }
281
366
  catch (error) {
282
- const formattedError = formatError(error, 'Failed to start recording');
283
- this.dispatchErrorEvent(formattedError);
367
+ const formattedError = formatError(error, "Failed to start recording");
284
368
  throw new Error(JSON.stringify(formattedError));
285
369
  }
286
370
  }
@@ -290,14 +374,18 @@ export class CortiEmbedded extends LitElement {
290
374
  */
291
375
  async stopRecording() {
292
376
  if (!this.postMessageHandler) {
293
- throw new Error('Component not ready');
377
+ throw new Error("Component not ready");
294
378
  }
295
379
  try {
296
- await this.postMessageHandler.stopRecording();
380
+ await this.postMessageHandler.postMessage({
381
+ type: "CORTI_EMBEDDED",
382
+ version: "v1",
383
+ action: "stopRecording",
384
+ payload: {},
385
+ });
297
386
  }
298
387
  catch (error) {
299
- const formattedError = formatError(error, 'Failed to stop recording');
300
- this.dispatchErrorEvent(formattedError);
388
+ const formattedError = formatError(error, "Failed to stop recording");
301
389
  throw new Error(JSON.stringify(formattedError));
302
390
  }
303
391
  }
@@ -312,16 +400,50 @@ export class CortiEmbedded extends LitElement {
312
400
  isAuthenticated: false,
313
401
  user: undefined,
314
402
  },
315
- currentUrl: '',
403
+ currentUrl: "",
316
404
  interaction: null,
317
405
  };
318
406
  }
319
407
  try {
320
- return await this.postMessageHandler.getStatus();
408
+ const response = await this.postMessageHandler.postMessage({
409
+ type: "CORTI_EMBEDDED",
410
+ version: "v1",
411
+ action: "getStatus",
412
+ payload: {},
413
+ });
414
+ if (response.success && response.payload) {
415
+ return response.payload;
416
+ }
417
+ throw new Error(response.error);
321
418
  }
322
419
  catch (error) {
323
- const formattedError = formatError(error, 'Failed to get status');
324
- this.dispatchErrorEvent(formattedError);
420
+ const formattedError = formatError(error, "Failed to get status");
421
+ throw new Error(JSON.stringify(formattedError));
422
+ }
423
+ }
424
+ /**
425
+ * Configure the component
426
+ * @param config Component configuration
427
+ * @returns Promise that resolves when configuration is applied
428
+ */
429
+ async configureApp(config) {
430
+ if (!this.postMessageHandler) {
431
+ throw new Error("Component not ready");
432
+ }
433
+ try {
434
+ const response = await this.postMessageHandler.postMessage({
435
+ type: "CORTI_EMBEDDED",
436
+ version: "v1",
437
+ action: "configureApp",
438
+ payload: config,
439
+ });
440
+ if (response.success && response.payload) {
441
+ return response.payload;
442
+ }
443
+ throw new Error(response.error);
444
+ }
445
+ catch (error) {
446
+ const formattedError = formatError(error, "Failed to configure app");
325
447
  throw new Error(JSON.stringify(formattedError));
326
448
  }
327
449
  }
@@ -332,14 +454,48 @@ export class CortiEmbedded extends LitElement {
332
454
  */
333
455
  async configure(config) {
334
456
  if (!this.postMessageHandler) {
335
- throw new Error('Component not ready');
457
+ throw new Error("Component not ready");
458
+ }
459
+ try {
460
+ CortiEmbedded.warnDeprecatedAPI("configure()", "configureApp()");
461
+ const response = await this.postMessageHandler.postMessage({
462
+ type: "CORTI_EMBEDDED",
463
+ version: "v1",
464
+ action: "configure",
465
+ payload: config,
466
+ });
467
+ if (response.success && response.payload) {
468
+ return response.payload;
469
+ }
470
+ throw new Error(response.error);
471
+ }
472
+ catch (error) {
473
+ const formattedError = formatError(error, "Failed to configure component");
474
+ throw new Error(JSON.stringify(formattedError));
475
+ }
476
+ }
477
+ /**
478
+ * Set one-shot interaction options for the embedded instance.
479
+ * @param config Interaction/session-level options
480
+ * @returns Promise that resolves when options are applied
481
+ */
482
+ async setInteractionOptions(config) {
483
+ if (!this.postMessageHandler) {
484
+ throw new Error("Component not ready");
336
485
  }
337
486
  try {
338
- return await this.postMessageHandler.configure(config);
487
+ const response = await this.postMessageHandler.postMessage({
488
+ type: "CORTI_EMBEDDED",
489
+ version: "v1",
490
+ action: "setInteractionOptions",
491
+ payload: config,
492
+ });
493
+ if (response.success === false || response.error) {
494
+ throw new Error(response.error);
495
+ }
339
496
  }
340
497
  catch (error) {
341
- const formattedError = formatError(error, 'Failed to configure component');
342
- this.dispatchErrorEvent(formattedError);
498
+ const formattedError = formatError(error, "Failed to set interaction options");
343
499
  throw new Error(JSON.stringify(formattedError));
344
500
  }
345
501
  }
@@ -350,17 +506,21 @@ export class CortiEmbedded extends LitElement {
350
506
  */
351
507
  async setCredentials(credentials) {
352
508
  if (!this.postMessageHandler) {
353
- throw new Error('Component not ready');
509
+ throw new Error("Component not ready");
354
510
  }
355
511
  try {
356
512
  if (!credentials.password) {
357
- throw new Error('Password is required');
513
+ throw new Error("Password is required");
358
514
  }
359
- await this.postMessageHandler.setCredentials(credentials);
515
+ await this.postMessageHandler.postMessage({
516
+ type: "CORTI_EMBEDDED",
517
+ version: "v1",
518
+ action: "setCredentials",
519
+ payload: credentials,
520
+ });
360
521
  }
361
522
  catch (error) {
362
- const formattedError = formatError(error, 'Failed to set credentials');
363
- this.dispatchErrorEvent(formattedError);
523
+ const formattedError = formatError(error, "Failed to set credentials");
364
524
  throw new Error(JSON.stringify(formattedError));
365
525
  }
366
526
  }
@@ -368,28 +528,34 @@ export class CortiEmbedded extends LitElement {
368
528
  * Show the embedded UI
369
529
  */
370
530
  show() {
371
- this.visibility = 'visible';
531
+ this.visibility = "visible";
372
532
  }
373
533
  /**
374
534
  * Hide the embedded UI
375
535
  */
376
536
  hide() {
377
- this.visibility = 'hidden';
537
+ this.visibility = "hidden";
378
538
  }
379
539
  /**
380
540
  * Get templates
381
541
  */
382
542
  async getTemplates() {
383
543
  if (!this.postMessageHandler) {
384
- throw new Error('Component not ready');
544
+ throw new Error("Component not ready");
385
545
  }
386
546
  try {
387
- const response = await this.postMessageHandler.getTemplates();
388
- return response;
547
+ const response = await this.postMessageHandler.postMessage({
548
+ type: "CORTI_EMBEDDED",
549
+ version: "v1",
550
+ action: "getTemplates",
551
+ });
552
+ if (response.success && response.payload) {
553
+ return response.payload;
554
+ }
555
+ throw new Error(response.error);
389
556
  }
390
557
  catch (error) {
391
- const formattedError = formatError(error, 'Failed to get templates');
392
- this.dispatchErrorEvent(formattedError);
558
+ const formattedError = formatError(error, "Failed to get templates");
393
559
  throw new Error(JSON.stringify(formattedError));
394
560
  }
395
561
  }
@@ -401,7 +567,7 @@ export class CortiEmbedded extends LitElement {
401
567
  getDebugStatus() {
402
568
  const iframe = this.getIframe();
403
569
  return {
404
- ready: iframe?.contentDocument?.readyState === 'complete',
570
+ ready: iframe?.contentDocument?.readyState === "complete",
405
571
  iframeExists: !!iframe,
406
572
  iframeSrc: iframe?.src,
407
573
  iframeContentWindow: !!iframe?.contentWindow,
@@ -413,21 +579,23 @@ export class CortiEmbedded extends LitElement {
413
579
  };
414
580
  }
415
581
  render() {
416
- // Don't render if baseURL is not provided
417
- if (!this.baseURL) {
418
- return html `<div>baseURL is required</div>`;
582
+ // Use the pre-validated normalizedBaseURL so render() never throws.
583
+ // normalizedBaseURL is set in connectedCallback (before first render) and
584
+ // kept up to date by updated() on each baseURL change.
585
+ if (!this.normalizedBaseURL) {
586
+ return html ``;
419
587
  }
420
588
  return html `
421
589
  <iframe
422
- src=${buildEmbeddedUrl(validateAndNormalizeBaseURL(this.baseURL))}
590
+ src=${buildEmbeddedUrl(this.normalizedBaseURL)}
423
591
  title="Corti Embedded UI"
424
- sandbox=${'allow-forms allow-modals allow-scripts allow-same-origin'}
425
- allow="microphone *; camera *; device-capture *; display-capture *"
592
+ sandbox=${IFRAME_SANDBOX_POLICY}
593
+ allow=${this.getIframeAllowPolicy(this.normalizedBaseURL)}
426
594
  @load=${(event) => this.handleIframeLoad(event)}
427
595
  @unload=${() => this.postMessageHandler?.destroy()}
428
- style=${this.visibility === 'hidden'
429
- ? 'display: none;'
430
- : 'display: block;'}
596
+ style=${this.visibility === "hidden"
597
+ ? "display: none;"
598
+ : "display: block;"}
431
599
  ></iframe>
432
600
  `;
433
601
  }