@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
@@ -1,10 +1,27 @@
1
+ function isRecord(value) {
2
+ return typeof value === "object" && value !== null;
3
+ }
4
+ function isEmbeddedEventMessage(value) {
5
+ return (isRecord(value) &&
6
+ value.type === "CORTI_EMBEDDED_EVENT" &&
7
+ typeof value.event === "string");
8
+ }
9
+ function isEmbeddedResponseMessage(value) {
10
+ return (isRecord(value) &&
11
+ value.type === "CORTI_EMBEDDED_RESPONSE" &&
12
+ typeof value.action === "string" &&
13
+ typeof value.requestId === "string" &&
14
+ typeof value.success === "boolean");
15
+ }
1
16
  export class PostMessageHandler {
2
17
  constructor(iframe, callbacks = {}) {
3
18
  this.pendingRequests = new Map();
4
19
  this.messageListener = null;
5
20
  this.isReady = false;
21
+ this._protocolVersion = null;
6
22
  this.iframe = iframe;
7
23
  this.callbacks = callbacks;
24
+ this.requestTimeout = callbacks.requestTimeout ?? 10000;
8
25
  this.setupMessageListener();
9
26
  }
10
27
  setupMessageListener() {
@@ -20,25 +37,56 @@ export class PostMessageHandler {
20
37
  }
21
38
  const { data } = event;
22
39
  // Check for Corti embedded events
23
- if (data?.type === 'CORTI_EMBEDDED_EVENT') {
40
+ if (isEmbeddedEventMessage(data)) {
24
41
  this.handleEvent(data);
25
42
  return;
26
43
  }
27
44
  // Check if this is a response to a pending request
28
- if (data.requestId && this.pendingRequests.has(data.requestId)) {
45
+ if (isEmbeddedResponseMessage(data) &&
46
+ this.pendingRequests.has(data.requestId)) {
29
47
  this.handleResponse(data);
30
48
  }
31
49
  };
32
- window.addEventListener('message', this.messageListener);
50
+ window.addEventListener("message", this.messageListener);
33
51
  }
34
52
  handleEvent(eventData) {
35
53
  const eventType = eventData.event;
36
54
  const { payload } = eventData;
37
- // Handle ready-like events
38
- if (eventType === 'ready' ||
39
- eventType === 'loaded' ||
40
- eventType === 'embedded.ready') {
55
+ // Only 'embedded.ready' signals that the iframe is ready to receive messages
56
+ if (eventType === "embedded.ready") {
41
57
  this.isReady = true;
58
+ // Store and validate the protocol version from the ready payload
59
+ const version = isRecord(payload) && typeof payload.version === "string"
60
+ ? payload.version
61
+ : undefined;
62
+ if (typeof version === "string") {
63
+ this._protocolVersion = version;
64
+ if (version !== PostMessageHandler.SUPPORTED_PROTOCOL_VERSION) {
65
+ this.callbacks.onError?.({
66
+ message: `Protocol version mismatch: host supports '${PostMessageHandler.SUPPORTED_PROTOCOL_VERSION}', iframe reported '${version}'. Some features may not work correctly.`,
67
+ });
68
+ }
69
+ }
70
+ }
71
+ if (eventType === "error.triggered") {
72
+ const errorPayload = payload && typeof payload === "object"
73
+ ? payload
74
+ : undefined;
75
+ const payloadMessage = errorPayload && typeof errorPayload.message === "string"
76
+ ? errorPayload.message
77
+ : undefined;
78
+ const payloadCode = errorPayload && typeof errorPayload.code === "string"
79
+ ? errorPayload.code
80
+ : undefined;
81
+ this.callbacks.onError?.({
82
+ message: payloadMessage ||
83
+ (typeof payload === "string"
84
+ ? payload
85
+ : "Embedded event reported an error"),
86
+ code: payloadCode,
87
+ details: eventData,
88
+ });
89
+ return;
42
90
  }
43
91
  this.callbacks.onEvent?.({
44
92
  name: eventType,
@@ -52,7 +100,7 @@ export class PostMessageHandler {
52
100
  this.pendingRequests.delete(data.requestId);
53
101
  if (data.success === false || data.error) {
54
102
  const error = {
55
- message: data.error || 'Request failed',
103
+ message: data.error || "Request failed",
56
104
  code: data.errorCode,
57
105
  details: data.errorDetails,
58
106
  };
@@ -66,7 +114,7 @@ export class PostMessageHandler {
66
114
  }
67
115
  destroy() {
68
116
  if (this.messageListener) {
69
- window.removeEventListener('message', this.messageListener);
117
+ window.removeEventListener("message", this.messageListener);
70
118
  this.messageListener = null;
71
119
  }
72
120
  this.pendingRequests.clear();
@@ -78,73 +126,81 @@ export class PostMessageHandler {
78
126
  this.callbacks = { ...this.callbacks, ...callbacks };
79
127
  }
80
128
  /**
81
- * Check if the iframe is ready to receive postMessages
129
+ * Whether the iframe has signaled it is ready to receive postMessages
82
130
  */
83
131
  get ready() {
84
132
  return this.isReady;
85
133
  }
86
134
  /**
87
- * Wait for the iframe to be ready
135
+ * The protocol version reported by the iframe in its 'embedded.ready' event,
136
+ * or null if the version was not included in the ready payload.
137
+ */
138
+ get protocolVersion() {
139
+ return this._protocolVersion;
140
+ }
141
+ /**
142
+ * Wait for the iframe to signal readiness via the 'embedded.ready' event.
88
143
  * @param timeout - Optional timeout in milliseconds (default: 30000ms)
89
- * @returns Promise that resolves when ready
90
144
  */
91
145
  async waitForReady(timeout = 30000) {
92
146
  if (this.isReady) {
93
147
  return Promise.resolve();
94
148
  }
95
149
  return new Promise((resolve, reject) => {
96
- const timeoutId = setTimeout(() => {
97
- reject(new Error('Timeout waiting for iframe to be ready'));
98
- }, timeout);
150
+ let timeoutId = null;
151
+ let readyListener = () => { };
152
+ function cleanup() {
153
+ if (timeoutId !== null) {
154
+ clearTimeout(timeoutId);
155
+ }
156
+ window.removeEventListener("message", readyListener);
157
+ }
99
158
  // Create a one-time listener for the ready event
100
- const readyListener = (event) => {
159
+ readyListener = (event) => {
101
160
  if (event.source === this.iframe.contentWindow &&
102
161
  event.origin === this.getTrustedOrigin() &&
103
- event.data?.type === 'CORTI_EMBEDDED_EVENT' &&
104
- (event.data.event === 'ready' ||
105
- event.data.event === 'loaded' ||
106
- event.data.event === 'embedded.ready')) {
107
- clearTimeout(timeoutId);
108
- window.removeEventListener('message', readyListener);
162
+ event.data?.type === "CORTI_EMBEDDED_EVENT" &&
163
+ event.data.event === "embedded.ready") {
164
+ cleanup();
109
165
  resolve();
110
166
  }
111
167
  };
112
- window.addEventListener('message', readyListener);
168
+ timeoutId = setTimeout(() => {
169
+ cleanup();
170
+ reject(new Error("Timeout waiting for iframe to be ready"));
171
+ }, timeout);
172
+ window.addEventListener("message", readyListener);
113
173
  });
114
174
  }
115
175
  /**
116
- * Sends a postMessage to the iframe and returns a Promise that resolves with the response
176
+ * Sends a postMessage to the iframe and returns a Promise that resolves with the response.
117
177
  * @param message - The message to send
118
- * @param timeout - Optional timeout in milliseconds (default: 10000ms)
119
- * @returns Promise that resolves with the response
178
+ * @param timeout - Optional timeout in milliseconds. Defaults to the requestTimeout set at construction.
120
179
  */
121
- async postMessage(message, timeout = 10000) {
180
+ async postMessage(message, timeout) {
122
181
  if (!this.iframe.contentWindow) {
123
- throw new Error('Iframe not ready');
182
+ throw new Error("Iframe not ready");
124
183
  }
125
184
  // Ensure the iframe has signaled readiness before sending
126
185
  await this.waitForReady();
127
186
  const { contentWindow } = this.iframe;
128
187
  const requestId = PostMessageHandler.generateRequestId();
188
+ const effectiveTimeout = timeout ?? this.requestTimeout;
129
189
  return new Promise((resolve, reject) => {
130
- // Set up timeout
131
190
  const timeoutId = setTimeout(() => {
132
191
  this.pendingRequests.delete(requestId);
133
- reject(new Error('Request timeout'));
134
- }, timeout);
135
- // Store the promise handlers
136
- const handlers = {
137
- resolve: (value) => {
192
+ reject(new Error("Request timeout"));
193
+ }, effectiveTimeout);
194
+ this.pendingRequests.set(requestId, {
195
+ resolve: value => {
138
196
  clearTimeout(timeoutId);
139
197
  resolve(value);
140
198
  },
141
- reject: (reason) => {
199
+ reject: reason => {
142
200
  clearTimeout(timeoutId);
143
201
  reject(reason);
144
202
  },
145
- };
146
- this.pendingRequests.set(requestId, handlers);
147
- // Send the message
203
+ });
148
204
  const fullMessage = {
149
205
  ...message,
150
206
  requestId,
@@ -152,172 +208,14 @@ export class PostMessageHandler {
152
208
  const targetOrigin = this.getTrustedOrigin();
153
209
  if (!targetOrigin) {
154
210
  this.pendingRequests.delete(requestId);
155
- reject(new Error('Cannot determine trusted origin for postMessage'));
211
+ reject(new Error("Cannot determine trusted origin for postMessage"));
156
212
  return;
157
213
  }
158
214
  contentWindow.postMessage(fullMessage, targetOrigin);
159
215
  });
160
216
  }
161
- /**
162
- * Helper method to send an auth message and return clean user data
163
- * @param payload - Auth payload
164
- * @returns Promise that resolves with user data
165
- */
166
- async auth(payload) {
167
- const response = await this.postMessage({
168
- type: 'CORTI_EMBEDDED',
169
- version: 'v1',
170
- action: 'auth',
171
- payload,
172
- });
173
- if (response.payload && response.success) {
174
- return response.payload.user;
175
- }
176
- throw new Error(response.error);
177
- }
178
- /**
179
- * Helper method to configure a session
180
- * @param payload - Session configuration payload
181
- * @returns Promise that resolves when configuration is complete
182
- */
183
- async configureSession(payload) {
184
- await this.postMessage({
185
- type: 'CORTI_EMBEDDED',
186
- version: 'v1',
187
- action: 'configureSession',
188
- payload,
189
- });
190
- }
191
- /**
192
- * Helper method to navigate to a specific path
193
- * @param payload - Navigation payload
194
- * @returns Promise that resolves when navigation is complete
195
- */
196
- async navigate(payload) {
197
- await this.postMessage({
198
- type: 'CORTI_EMBEDDED',
199
- version: 'v1',
200
- action: 'navigate',
201
- payload,
202
- });
203
- }
204
- /**
205
- * Helper method to add facts to the session
206
- * @param payload - Facts payload
207
- * @returns Promise that resolves when facts are added
208
- */
209
- async addFacts(payload) {
210
- await this.postMessage({
211
- type: 'CORTI_EMBEDDED',
212
- version: 'v1',
213
- action: 'addFacts',
214
- payload,
215
- });
216
- }
217
- /**
218
- * Helper method to create a new interaction and return clean interaction data
219
- * @param payload - Interaction creation payload
220
- * @returns Promise that resolves with interaction details
221
- */
222
- async createInteraction(payload) {
223
- const response = await this.postMessage({
224
- type: 'CORTI_EMBEDDED',
225
- version: 'v1',
226
- action: 'createInteraction',
227
- payload,
228
- });
229
- if (response.payload && response.success) {
230
- return response.payload;
231
- }
232
- throw new Error(response.error);
233
- }
234
- /**
235
- * Helper method to start recording
236
- * @returns Promise that resolves when recording starts
237
- */
238
- async startRecording() {
239
- await this.postMessage({
240
- type: 'CORTI_EMBEDDED',
241
- version: 'v1',
242
- action: 'startRecording',
243
- payload: {},
244
- });
245
- }
246
- /**
247
- * Helper method to stop recording
248
- * @returns Promise that resolves when recording stops
249
- */
250
- async stopRecording() {
251
- await this.postMessage({
252
- type: 'CORTI_EMBEDDED',
253
- version: 'v1',
254
- action: 'stopRecording',
255
- payload: {},
256
- });
257
- }
258
- /**
259
- * Helper method to get current status
260
- * @returns Promise that resolves with current status
261
- */
262
- async getStatus() {
263
- const response = await this.postMessage({
264
- type: 'CORTI_EMBEDDED',
265
- version: 'v1',
266
- action: 'getStatus',
267
- payload: {},
268
- });
269
- if (response.payload && response.success) {
270
- return response.payload;
271
- }
272
- throw new Error(response.error);
273
- }
274
- /**
275
- * Helper method to configure the component
276
- * @param payload - Component configuration payload
277
- * @returns Promise that resolves when configuration is applied
278
- */
279
- async configure(payload) {
280
- const response = await this.postMessage({
281
- type: 'CORTI_EMBEDDED',
282
- version: 'v1',
283
- action: 'configure',
284
- payload,
285
- });
286
- if (response.payload && response.success) {
287
- return response.payload;
288
- }
289
- throw new Error(response.error);
290
- }
291
- /**
292
- * Helper method to set credentials without triggering auth flow
293
- * @param payload - Credentials payload
294
- * @returns Promise that resolves when credentials are set
295
- */
296
- async setCredentials(payload) {
297
- await this.postMessage({
298
- type: 'CORTI_EMBEDDED',
299
- version: 'v1',
300
- action: 'setCredentials',
301
- payload,
302
- });
303
- }
304
- /**
305
- * Helper method to get templates
306
- * @returns Promise that resolves with a list of templates
307
- */
308
- async getTemplates() {
309
- const response = await this.postMessage({
310
- type: 'CORTI_EMBEDDED',
311
- version: 'v1',
312
- action: 'getTemplates',
313
- });
314
- if (response.payload && response.success) {
315
- return response.payload;
316
- }
317
- throw new Error(response.error);
318
- }
319
217
  static generateRequestId() {
320
- return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
218
+ return `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
321
219
  }
322
220
  /**
323
221
  * Derive the trusted origin from the iframe src (constructed from baseURL).
@@ -325,9 +223,7 @@ export class PostMessageHandler {
325
223
  */
326
224
  getTrustedOrigin() {
327
225
  try {
328
- // If iframe.src is relative, URL() will resolve against the current location.
329
- // Embeds should provide an absolute baseURL; enforcing strict origin here.
330
- const src = this.iframe.getAttribute('src') || this.iframe.src;
226
+ const src = this.iframe.getAttribute("src") || this.iframe.src;
331
227
  if (!src)
332
228
  return null;
333
229
  const url = new URL(src, window.location.href);
@@ -338,4 +234,5 @@ export class PostMessageHandler {
338
234
  }
339
235
  }
340
236
  }
237
+ PostMessageHandler.SUPPORTED_PROTOCOL_VERSION = "v1";
341
238
  //# sourceMappingURL=PostMessageHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PostMessageHandler.js","sourceRoot":"","sources":["../../src/utils/PostMessageHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AddFactsPayload,\n AnyEvent,\n AuthPayload,\n AuthResponse,\n ConfigureAppPayload,\n ConfigureAppResponse,\n ConfigureSessionPayload,\n CreateInteractionPayload,\n CreateInteractionResponse,\n EmbeddedRequest,\n EmbeddedResponse,\n GetStatusResponse,\n NavigatePayload,\n SetCredentialsPayload,\n GetTemplatesResponse,\n} from '../types';\n\nexport interface PostMessageHandlerCallbacks {\n onEvent?: (event: { name: string; payload: unknown }) => void;\n onError?: (error: {\n message: string;\n code?: string;\n details?: unknown;\n }) => void;\n}\n\nexport class PostMessageHandler {\n private pendingRequests = new Map<\n string,\n { resolve: (value: any) => void; reject: (reason: any) => void }\n >();\n\n private messageListener: ((event: MessageEvent) => void) | null = null;\n\n private iframe: HTMLIFrameElement;\n\n private isReady = false;\n\n private callbacks: PostMessageHandlerCallbacks;\n\n constructor(\n iframe: HTMLIFrameElement,\n callbacks: PostMessageHandlerCallbacks = {},\n ) {\n this.iframe = iframe;\n this.callbacks = callbacks;\n this.setupMessageListener();\n }\n\n private setupMessageListener() {\n this.messageListener = (event: MessageEvent) => {\n // Only handle messages from our iframe\n if (event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Enforce origin to match the trusted iframe origin\n const trustedOrigin = this.getTrustedOrigin();\n if (!trustedOrigin || event.origin !== trustedOrigin) {\n return;\n }\n\n const { data } = event;\n\n // Check for Corti embedded events\n if (data?.type === 'CORTI_EMBEDDED_EVENT') {\n this.handleEvent(data);\n return;\n }\n\n // Check if this is a response to a pending request\n if (data.requestId && this.pendingRequests.has(data.requestId)) {\n this.handleResponse(data);\n }\n };\n\n window.addEventListener('message', this.messageListener);\n }\n\n private handleEvent(eventData: AnyEvent): void {\n const eventType = (eventData as any).event;\n const { payload } = eventData;\n\n // Handle ready-like events\n if (\n eventType === 'ready' ||\n eventType === 'loaded' ||\n eventType === 'embedded.ready'\n ) {\n this.isReady = true;\n }\n\n this.callbacks.onEvent?.({\n name: eventType,\n payload,\n });\n }\n\n private handleResponse(data: any): void {\n const pendingRequest = this.pendingRequests.get(data.requestId);\n if (pendingRequest) {\n const { resolve, reject } = pendingRequest;\n this.pendingRequests.delete(data.requestId);\n\n if (data.success === false || data.error) {\n const error = {\n message: data.error || 'Request failed',\n code: data.errorCode,\n details: data.errorDetails,\n };\n this.callbacks.onError?.(error);\n reject(error);\n } else {\n resolve(data);\n }\n }\n }\n\n destroy() {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n this.pendingRequests.clear();\n }\n\n /**\n * Update callbacks after construction\n */\n updateCallbacks(callbacks: PostMessageHandlerCallbacks) {\n this.callbacks = { ...this.callbacks, ...callbacks };\n }\n\n /**\n * Check if the iframe is ready to receive postMessages\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * Wait for the iframe to be ready\n * @param timeout - Optional timeout in milliseconds (default: 30000ms)\n * @returns Promise that resolves when ready\n */\n async waitForReady(timeout = 30000): Promise<void> {\n if (this.isReady) {\n return Promise.resolve();\n }\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error('Timeout waiting for iframe to be ready'));\n }, timeout);\n\n // Create a one-time listener for the ready event\n const readyListener = (event: MessageEvent) => {\n if (\n event.source === this.iframe.contentWindow &&\n event.origin === this.getTrustedOrigin() &&\n event.data?.type === 'CORTI_EMBEDDED_EVENT' &&\n (event.data.event === 'ready' ||\n event.data.event === 'loaded' ||\n event.data.event === 'embedded.ready')\n ) {\n clearTimeout(timeoutId);\n window.removeEventListener('message', readyListener);\n resolve();\n }\n };\n\n window.addEventListener('message', readyListener);\n });\n }\n\n /**\n * Sends a postMessage to the iframe and returns a Promise that resolves with the response\n * @param message - The message to send\n * @param timeout - Optional timeout in milliseconds (default: 10000ms)\n * @returns Promise that resolves with the response\n */\n async postMessage(\n message: Omit<EmbeddedRequest, 'requestId'>,\n timeout = 10000,\n ): Promise<EmbeddedResponse> {\n if (!this.iframe.contentWindow) {\n throw new Error('Iframe not ready');\n }\n\n // Ensure the iframe has signaled readiness before sending\n await this.waitForReady();\n\n const { contentWindow } = this.iframe;\n const requestId = PostMessageHandler.generateRequestId();\n\n return new Promise((resolve, reject) => {\n // Set up timeout\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(requestId);\n reject(new Error('Request timeout'));\n }, timeout);\n\n // Store the promise handlers\n const handlers = {\n resolve: (value: any) => {\n clearTimeout(timeoutId);\n resolve(value);\n },\n reject: (reason: any) => {\n clearTimeout(timeoutId);\n reject(reason);\n },\n };\n\n this.pendingRequests.set(requestId, handlers);\n\n // Send the message\n const fullMessage: EmbeddedRequest = {\n ...message,\n requestId,\n };\n\n const targetOrigin = this.getTrustedOrigin();\n if (!targetOrigin) {\n this.pendingRequests.delete(requestId);\n reject(new Error('Cannot determine trusted origin for postMessage'));\n return;\n }\n contentWindow.postMessage(fullMessage, targetOrigin);\n });\n }\n\n /**\n * Helper method to send an auth message and return clean user data\n * @param payload - Auth payload\n * @returns Promise that resolves with user data\n */\n async auth(payload: AuthPayload): Promise<AuthResponse['user']> {\n const response = await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'auth',\n payload,\n });\n\n if (response.payload && response.success) {\n return (response.payload as AuthResponse).user;\n }\n throw new Error(response.error);\n }\n\n /**\n * Helper method to configure a session\n * @param payload - Session configuration payload\n * @returns Promise that resolves when configuration is complete\n */\n async configureSession(payload: ConfigureSessionPayload): Promise<void> {\n await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'configureSession',\n payload,\n });\n }\n\n /**\n * Helper method to navigate to a specific path\n * @param payload - Navigation payload\n * @returns Promise that resolves when navigation is complete\n */\n async navigate(payload: NavigatePayload): Promise<void> {\n await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'navigate',\n payload,\n });\n }\n\n /**\n * Helper method to add facts to the session\n * @param payload - Facts payload\n * @returns Promise that resolves when facts are added\n */\n async addFacts(payload: AddFactsPayload): Promise<void> {\n await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'addFacts',\n payload,\n });\n }\n\n /**\n * Helper method to create a new interaction and return clean interaction data\n * @param payload - Interaction creation payload\n * @returns Promise that resolves with interaction details\n */\n async createInteraction(\n payload: CreateInteractionPayload,\n ): Promise<CreateInteractionResponse> {\n const response = await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'createInteraction',\n payload,\n });\n\n if (response.payload && response.success) {\n return response.payload as CreateInteractionResponse;\n }\n throw new Error(response.error);\n }\n\n /**\n * Helper method to start recording\n * @returns Promise that resolves when recording starts\n */\n async startRecording(): Promise<void> {\n await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'startRecording',\n payload: {},\n });\n }\n\n /**\n * Helper method to stop recording\n * @returns Promise that resolves when recording stops\n */\n async stopRecording(): Promise<void> {\n await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'stopRecording',\n payload: {},\n });\n }\n\n /**\n * Helper method to get current status\n * @returns Promise that resolves with current status\n */\n async getStatus(): Promise<GetStatusResponse> {\n const response = await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'getStatus',\n payload: {},\n });\n\n if (response.payload && response.success) {\n return response.payload as GetStatusResponse;\n }\n throw new Error(response.error);\n }\n\n /**\n * Helper method to configure the component\n * @param payload - Component configuration payload\n * @returns Promise that resolves when configuration is applied\n */\n async configure(payload: ConfigureAppPayload): Promise<ConfigureAppResponse> {\n const response = await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'configure',\n payload,\n });\n\n if (response.payload && response.success) {\n return response.payload as ConfigureAppResponse;\n }\n throw new Error(response.error);\n }\n\n /**\n * Helper method to set credentials without triggering auth flow\n * @param payload - Credentials payload\n * @returns Promise that resolves when credentials are set\n */\n async setCredentials(payload: SetCredentialsPayload): Promise<void> {\n await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'setCredentials',\n payload,\n });\n }\n\n /**\n * Helper method to get templates\n * @returns Promise that resolves with a list of templates\n */\n async getTemplates(): Promise<GetTemplatesResponse> {\n const response = await this.postMessage({\n type: 'CORTI_EMBEDDED',\n version: 'v1',\n action: 'getTemplates',\n });\n\n if (response.payload && response.success) {\n return response.payload as GetTemplatesResponse;\n }\n throw new Error(response.error);\n }\n\n private static generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n /**\n * Derive the trusted origin from the iframe src (constructed from baseURL).\n * Returns null if it cannot be determined.\n */\n private getTrustedOrigin(): string | null {\n try {\n // If iframe.src is relative, URL() will resolve against the current location.\n // Embeds should provide an absolute baseURL; enforcing strict origin here.\n const src = this.iframe.getAttribute('src') || this.iframe.src;\n if (!src) return null;\n const url = new URL(src, window.location.href);\n return url.origin;\n } catch {\n return null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"PostMessageHandler.js","sourceRoot":"","sources":["../../src/utils/PostMessageHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnyEvent, EmbeddedRequest, EmbeddedResponse } from \"../types\";\n\nexport interface PostMessageHandlerCallbacks {\n onEvent?: (event: { name: string; payload: unknown }) => void;\n onError?: (error: {\n message: string;\n code?: string;\n details?: unknown;\n }) => void;\n /**\n * Default timeout in milliseconds for postMessage requests.\n * @default 10000\n */\n requestTimeout?: number;\n}\n\ninterface PostMessageHandlerError {\n message: string;\n code?: string;\n details?: unknown;\n}\n\ninterface PendingRequest {\n resolve: (value: EmbeddedResponse) => void;\n reject: (reason: PostMessageHandlerError) => void;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isEmbeddedEventMessage(value: unknown): value is AnyEvent {\n return (\n isRecord(value) &&\n value.type === \"CORTI_EMBEDDED_EVENT\" &&\n typeof value.event === \"string\"\n );\n}\n\nfunction isEmbeddedResponseMessage(value: unknown): value is EmbeddedResponse {\n return (\n isRecord(value) &&\n value.type === \"CORTI_EMBEDDED_RESPONSE\" &&\n typeof value.action === \"string\" &&\n typeof value.requestId === \"string\" &&\n typeof value.success === \"boolean\"\n );\n}\n\nexport class PostMessageHandler {\n private pendingRequests = new Map<string, PendingRequest>();\n\n private messageListener: ((event: MessageEvent) => void) | null = null;\n\n private iframe: HTMLIFrameElement;\n\n private isReady = false;\n\n private _protocolVersion: string | null = null;\n\n private static readonly SUPPORTED_PROTOCOL_VERSION = \"v1\";\n\n private readonly requestTimeout: number;\n\n private callbacks: PostMessageHandlerCallbacks;\n\n constructor(\n iframe: HTMLIFrameElement,\n callbacks: PostMessageHandlerCallbacks = {},\n ) {\n this.iframe = iframe;\n this.callbacks = callbacks;\n this.requestTimeout = callbacks.requestTimeout ?? 10000;\n this.setupMessageListener();\n }\n\n private setupMessageListener() {\n this.messageListener = (event: MessageEvent) => {\n // Only handle messages from our iframe\n if (event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Enforce origin to match the trusted iframe origin\n const trustedOrigin = this.getTrustedOrigin();\n if (!trustedOrigin || event.origin !== trustedOrigin) {\n return;\n }\n\n const { data } = event;\n\n // Check for Corti embedded events\n if (isEmbeddedEventMessage(data)) {\n this.handleEvent(data);\n return;\n }\n\n // Check if this is a response to a pending request\n if (\n isEmbeddedResponseMessage(data) &&\n this.pendingRequests.has(data.requestId)\n ) {\n this.handleResponse(data);\n }\n };\n\n window.addEventListener(\"message\", this.messageListener);\n }\n\n private handleEvent(eventData: AnyEvent): void {\n const eventType = eventData.event;\n const { payload } = eventData;\n\n // Only 'embedded.ready' signals that the iframe is ready to receive messages\n if (eventType === \"embedded.ready\") {\n this.isReady = true;\n\n // Store and validate the protocol version from the ready payload\n const version =\n isRecord(payload) && typeof payload.version === \"string\"\n ? payload.version\n : undefined;\n if (typeof version === \"string\") {\n this._protocolVersion = version;\n if (version !== PostMessageHandler.SUPPORTED_PROTOCOL_VERSION) {\n this.callbacks.onError?.({\n message: `Protocol version mismatch: host supports '${PostMessageHandler.SUPPORTED_PROTOCOL_VERSION}', iframe reported '${version}'. Some features may not work correctly.`,\n });\n }\n }\n }\n\n if (eventType === \"error.triggered\") {\n const errorPayload =\n payload && typeof payload === \"object\"\n ? (payload as Record<string, unknown>)\n : undefined;\n const payloadMessage =\n errorPayload && typeof errorPayload.message === \"string\"\n ? errorPayload.message\n : undefined;\n const payloadCode =\n errorPayload && typeof errorPayload.code === \"string\"\n ? errorPayload.code\n : undefined;\n\n this.callbacks.onError?.({\n message:\n payloadMessage ||\n (typeof payload === \"string\"\n ? payload\n : \"Embedded event reported an error\"),\n code: payloadCode,\n details: eventData,\n });\n return;\n }\n\n this.callbacks.onEvent?.({\n name: eventType,\n payload,\n });\n }\n\n private handleResponse(data: EmbeddedResponse): void {\n const pendingRequest = this.pendingRequests.get(data.requestId);\n if (pendingRequest) {\n const { resolve, reject } = pendingRequest;\n this.pendingRequests.delete(data.requestId);\n\n if (data.success === false || data.error) {\n const error = {\n message: data.error || \"Request failed\",\n code: data.errorCode,\n details: data.errorDetails,\n };\n this.callbacks.onError?.(error);\n reject(error);\n } else {\n resolve(data);\n }\n }\n }\n\n destroy() {\n if (this.messageListener) {\n window.removeEventListener(\"message\", this.messageListener);\n this.messageListener = null;\n }\n this.pendingRequests.clear();\n }\n\n /**\n * Update callbacks after construction\n */\n updateCallbacks(callbacks: PostMessageHandlerCallbacks) {\n this.callbacks = { ...this.callbacks, ...callbacks };\n }\n\n /**\n * Whether the iframe has signaled it is ready to receive postMessages\n */\n get ready(): boolean {\n return this.isReady;\n }\n\n /**\n * The protocol version reported by the iframe in its 'embedded.ready' event,\n * or null if the version was not included in the ready payload.\n */\n get protocolVersion(): string | null {\n return this._protocolVersion;\n }\n\n /**\n * Wait for the iframe to signal readiness via the 'embedded.ready' event.\n * @param timeout - Optional timeout in milliseconds (default: 30000ms)\n */\n async waitForReady(timeout = 30000): Promise<void> {\n if (this.isReady) {\n return Promise.resolve();\n }\n\n return new Promise((resolve, reject) => {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let readyListener: (event: MessageEvent) => void = () => {};\n\n function cleanup() {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n window.removeEventListener(\"message\", readyListener);\n }\n\n // Create a one-time listener for the ready event\n readyListener = (event: MessageEvent) => {\n if (\n event.source === this.iframe.contentWindow &&\n event.origin === this.getTrustedOrigin() &&\n event.data?.type === \"CORTI_EMBEDDED_EVENT\" &&\n event.data.event === \"embedded.ready\"\n ) {\n cleanup();\n resolve();\n }\n };\n\n timeoutId = setTimeout(() => {\n cleanup();\n reject(new Error(\"Timeout waiting for iframe to be ready\"));\n }, timeout);\n\n window.addEventListener(\"message\", readyListener);\n });\n }\n\n /**\n * Sends a postMessage to the iframe and returns a Promise that resolves with the response.\n * @param message - The message to send\n * @param timeout - Optional timeout in milliseconds. Defaults to the requestTimeout set at construction.\n */\n async postMessage(\n message: Omit<EmbeddedRequest, \"requestId\">,\n timeout?: number,\n ): Promise<EmbeddedResponse> {\n if (!this.iframe.contentWindow) {\n throw new Error(\"Iframe not ready\");\n }\n\n // Ensure the iframe has signaled readiness before sending\n await this.waitForReady();\n\n const { contentWindow } = this.iframe;\n const requestId = PostMessageHandler.generateRequestId();\n const effectiveTimeout = timeout ?? this.requestTimeout;\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(requestId);\n reject(new Error(\"Request timeout\"));\n }, effectiveTimeout);\n\n this.pendingRequests.set(requestId, {\n resolve: value => {\n clearTimeout(timeoutId);\n resolve(value);\n },\n reject: reason => {\n clearTimeout(timeoutId);\n reject(reason);\n },\n });\n\n const fullMessage: EmbeddedRequest = {\n ...message,\n requestId,\n };\n\n const targetOrigin = this.getTrustedOrigin();\n if (!targetOrigin) {\n this.pendingRequests.delete(requestId);\n reject(new Error(\"Cannot determine trusted origin for postMessage\"));\n return;\n }\n contentWindow.postMessage(fullMessage, targetOrigin);\n });\n }\n\n private static generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Derive the trusted origin from the iframe src (constructed from baseURL).\n * Returns null if it cannot be determined.\n */\n private getTrustedOrigin(): string | null {\n try {\n const src = this.iframe.getAttribute(\"src\") || this.iframe.src;\n if (!src) return null;\n const url = new URL(src, window.location.href);\n return url.origin;\n } catch {\n return null;\n }\n }\n}\n"]}
@@ -4,22 +4,22 @@ export function validateAndNormalizeBaseURL(url) {
4
4
  parsed = new URL(url);
5
5
  }
6
6
  catch {
7
- throw new Error('Invalid baseURL: not a parseable URL');
7
+ throw new Error("Invalid baseURL: not a parseable URL");
8
8
  }
9
- if (parsed.protocol !== 'https:') {
10
- throw new Error('Invalid baseURL: must use https');
9
+ if (parsed.protocol !== "https:") {
10
+ throw new Error("Invalid baseURL: must use https");
11
11
  }
12
12
  const host = parsed.host.toLowerCase();
13
13
  const pattern = /^assistant\.[a-z0-9-]+\.corti\.app$/i;
14
14
  if (!pattern.test(host)) {
15
- throw new Error('Invalid baseURL: host must match assistant.xxx.corti.app');
15
+ throw new Error("Invalid baseURL: host must match assistant.xxx.corti.app");
16
16
  }
17
- if (parsed.pathname && parsed.pathname !== '/' && parsed.pathname !== '') {
18
- throw new Error('Invalid baseURL: must not include a path');
17
+ if (parsed.pathname && parsed.pathname !== "/" && parsed.pathname !== "") {
18
+ throw new Error("Invalid baseURL: must not include a path");
19
19
  }
20
20
  if (parsed.username || parsed.password) {
21
- throw new Error('Invalid baseURL: must not include credentials');
21
+ throw new Error("Invalid baseURL: must not include credentials");
22
22
  }
23
- return parsed.origin.replace(/\/+$/, '');
23
+ return parsed.origin.replace(/\/+$/, "");
24
24
  }
25
25
  //# sourceMappingURL=baseUrl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"baseUrl.js","sourceRoot":"","sources":["../../src/utils/baseUrl.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,sCAAsC,CAAC;IACvD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG,IAAI,MAAM,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC","sourcesContent":["export function validateAndNormalizeBaseURL(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error('Invalid baseURL: not a parseable URL');\n }\n if (parsed.protocol !== 'https:') {\n throw new Error('Invalid baseURL: must use https');\n }\n const host = parsed.host.toLowerCase();\n const pattern = /^assistant\\.[a-z0-9-]+\\.corti\\.app$/i;\n if (!pattern.test(host)) {\n throw new Error('Invalid baseURL: host must match assistant.xxx.corti.app');\n }\n if (parsed.pathname && parsed.pathname !== '/' && parsed.pathname !== '') {\n throw new Error('Invalid baseURL: must not include a path');\n }\n if (parsed.username || parsed.password) {\n throw new Error('Invalid baseURL: must not include credentials');\n }\n return parsed.origin.replace(/\\/+$/, '');\n}\n"]}
1
+ {"version":3,"file":"baseUrl.js","sourceRoot":"","sources":["../../src/utils/baseUrl.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,2BAA2B,CAAC,GAAW;IACrD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,sCAAsC,CAAC;IACvD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG,IAAI,MAAM,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC","sourcesContent":["export function validateAndNormalizeBaseURL(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(\"Invalid baseURL: not a parseable URL\");\n }\n if (parsed.protocol !== \"https:\") {\n throw new Error(\"Invalid baseURL: must use https\");\n }\n const host = parsed.host.toLowerCase();\n const pattern = /^assistant\\.[a-z0-9-]+\\.corti\\.app$/i;\n if (!pattern.test(host)) {\n throw new Error(\"Invalid baseURL: host must match assistant.xxx.corti.app\");\n }\n if (parsed.pathname && parsed.pathname !== \"/\" && parsed.pathname !== \"\") {\n throw new Error(\"Invalid baseURL: must not include a path\");\n }\n if (parsed.username || parsed.password) {\n throw new Error(\"Invalid baseURL: must not include credentials\");\n }\n return parsed.origin.replace(/\\/+$/, \"\");\n}\n"]}
@@ -2,7 +2,7 @@ export function buildEmbeddedUrl(normalizedBaseURL) {
2
2
  return `${normalizedBaseURL}/embedded`;
3
3
  }
4
4
  export function isRealEmbeddedLoad(src, normalizedBaseURL) {
5
- if (!src || src.startsWith('about:')) {
5
+ if (!src || src.startsWith("about:")) {
6
6
  return false;
7
7
  }
8
8
  try {
@@ -13,8 +13,8 @@ export function isRealEmbeddedLoad(src, normalizedBaseURL) {
13
13
  return false;
14
14
  }
15
15
  // Accept /embedded with optional trailing slash; allow query/hash
16
- const normalizedPath = srcUrl.pathname.replace(/\/+$/, '');
17
- return normalizedPath === '/embedded';
16
+ const normalizedPath = srcUrl.pathname.replace(/\/+$/, "");
17
+ return normalizedPath === "/embedded";
18
18
  }
19
19
  catch {
20
20
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"embedUrl.js","sourceRoot":"","sources":["../../src/utils/embedUrl.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,iBAAyB;IACxD,OAAO,GAAG,iBAAiB,WAAW,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,iBAAyB;IAEzB,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC3C,6BAA6B;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,kEAAkE;QAClE,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3D,OAAO,cAAc,KAAK,WAAW,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["export function buildEmbeddedUrl(normalizedBaseURL: string): string {\n return `${normalizedBaseURL}/embedded`;\n}\n\nexport function isRealEmbeddedLoad(\n src: string,\n normalizedBaseURL: string,\n): boolean {\n if (!src || src.startsWith('about:')) {\n return false;\n }\n try {\n const srcUrl = new URL(src, window.location.href);\n const baseUrl = new URL(normalizedBaseURL);\n // Require exact origin match\n if (srcUrl.origin !== baseUrl.origin) {\n return false;\n }\n // Accept /embedded with optional trailing slash; allow query/hash\n const normalizedPath = srcUrl.pathname.replace(/\\/+$/, '');\n return normalizedPath === '/embedded';\n } catch {\n return false;\n }\n}\n"]}
1
+ {"version":3,"file":"embedUrl.js","sourceRoot":"","sources":["../../src/utils/embedUrl.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,iBAAyB;IACxD,OAAO,GAAG,iBAAiB,WAAW,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,iBAAyB;IAEzB,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC3C,6BAA6B;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,kEAAkE;QAClE,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3D,OAAO,cAAc,KAAK,WAAW,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["export function buildEmbeddedUrl(normalizedBaseURL: string): string {\n return `${normalizedBaseURL}/embedded`;\n}\n\nexport function isRealEmbeddedLoad(\n src: string,\n normalizedBaseURL: string,\n): boolean {\n if (!src || src.startsWith(\"about:\")) {\n return false;\n }\n try {\n const srcUrl = new URL(src, window.location.href);\n const baseUrl = new URL(normalizedBaseURL);\n // Require exact origin match\n if (srcUrl.origin !== baseUrl.origin) {\n return false;\n }\n // Accept /embedded with optional trailing slash; allow query/hash\n const normalizedPath = srcUrl.pathname.replace(/\\/+$/, \"\");\n return normalizedPath === \"/embedded\";\n } catch {\n return false;\n }\n}\n"]}