@corti/embedded-web 0.1.0 → 0.2.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 +70 -47
- package/dist/CortiEmbedded.d.ts +5 -4
- package/dist/CortiEmbedded.js +186 -103
- package/dist/CortiEmbedded.js.map +1 -1
- package/dist/bundle.js +1615 -20
- package/dist/corti-embedded.d.ts +17 -1
- package/dist/corti-embedded.js +4 -3
- package/dist/corti-embedded.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/react/CortiEmbeddedReact.d.ts +30 -23
- package/dist/react/CortiEmbeddedReact.js +67 -21
- package/dist/react/CortiEmbeddedReact.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/styles/base.js +1 -1
- package/dist/styles/base.js.map +1 -1
- package/dist/styles/container-styles.js +2 -2
- package/dist/styles/container-styles.js.map +1 -1
- package/dist/styles/theme.js +2 -2
- package/dist/styles/theme.js.map +1 -1
- package/dist/types/api.d.ts +3 -14
- package/dist/types/api.js.map +1 -1
- package/dist/types/payloads.d.ts +1 -4
- package/dist/types/payloads.js.map +1 -1
- package/dist/types/protocol.d.ts +0 -1
- package/dist/types/protocol.js.map +1 -1
- package/dist/utils/PostMessageHandler.d.ts +19 -70
- package/dist/utils/PostMessageHandler.js +98 -202
- package/dist/utils/PostMessageHandler.js.map +1 -1
- package/dist/utils/baseUrl.js +8 -8
- package/dist/utils/baseUrl.js.map +1 -1
- package/dist/utils/embedUrl.js +3 -3
- package/dist/utils/embedUrl.js.map +1 -1
- package/dist/utils/errorFormatter.js +44 -20
- package/dist/utils/errorFormatter.js.map +1 -1
- package/dist/web-bundle.js +1473 -13
- package/dist/web-index.d.ts +3 -3
- package/dist/web-index.js +3 -3
- package/dist/web-index.js.map +1 -1
- package/package.json +18 -10
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EmbeddedRequest, EmbeddedResponse } from "../types";
|
|
2
2
|
export interface PostMessageHandlerCallbacks {
|
|
3
3
|
onEvent?: (event: {
|
|
4
4
|
name: string;
|
|
@@ -9,12 +9,20 @@ export interface PostMessageHandlerCallbacks {
|
|
|
9
9
|
code?: string;
|
|
10
10
|
details?: unknown;
|
|
11
11
|
}) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Default timeout in milliseconds for postMessage requests.
|
|
14
|
+
* @default 10000
|
|
15
|
+
*/
|
|
16
|
+
requestTimeout?: number;
|
|
12
17
|
}
|
|
13
18
|
export declare class PostMessageHandler {
|
|
14
19
|
private pendingRequests;
|
|
15
20
|
private messageListener;
|
|
16
21
|
private iframe;
|
|
17
22
|
private isReady;
|
|
23
|
+
private _protocolVersion;
|
|
24
|
+
private static readonly SUPPORTED_PROTOCOL_VERSION;
|
|
25
|
+
private readonly requestTimeout;
|
|
18
26
|
private callbacks;
|
|
19
27
|
constructor(iframe: HTMLIFrameElement, callbacks?: PostMessageHandlerCallbacks);
|
|
20
28
|
private setupMessageListener;
|
|
@@ -26,84 +34,25 @@ export declare class PostMessageHandler {
|
|
|
26
34
|
*/
|
|
27
35
|
updateCallbacks(callbacks: PostMessageHandlerCallbacks): void;
|
|
28
36
|
/**
|
|
29
|
-
*
|
|
37
|
+
* Whether the iframe has signaled it is ready to receive postMessages
|
|
30
38
|
*/
|
|
31
39
|
get ready(): boolean;
|
|
32
40
|
/**
|
|
33
|
-
*
|
|
41
|
+
* The protocol version reported by the iframe in its 'embedded.ready' event,
|
|
42
|
+
* or null if the version was not included in the ready payload.
|
|
43
|
+
*/
|
|
44
|
+
get protocolVersion(): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Wait for the iframe to signal readiness via the 'embedded.ready' event.
|
|
34
47
|
* @param timeout - Optional timeout in milliseconds (default: 30000ms)
|
|
35
|
-
* @returns Promise that resolves when ready
|
|
36
48
|
*/
|
|
37
49
|
waitForReady(timeout?: number): Promise<void>;
|
|
38
50
|
/**
|
|
39
|
-
* Sends a postMessage to the iframe and returns a Promise that resolves with the response
|
|
51
|
+
* Sends a postMessage to the iframe and returns a Promise that resolves with the response.
|
|
40
52
|
* @param message - The message to send
|
|
41
|
-
* @param timeout - Optional timeout in milliseconds
|
|
42
|
-
* @returns Promise that resolves with the response
|
|
43
|
-
*/
|
|
44
|
-
postMessage(message: Omit<EmbeddedRequest, 'requestId'>, timeout?: number): Promise<EmbeddedResponse>;
|
|
45
|
-
/**
|
|
46
|
-
* Helper method to send an auth message and return clean user data
|
|
47
|
-
* @param payload - Auth payload
|
|
48
|
-
* @returns Promise that resolves with user data
|
|
49
|
-
*/
|
|
50
|
-
auth(payload: AuthPayload): Promise<AuthResponse['user']>;
|
|
51
|
-
/**
|
|
52
|
-
* Helper method to configure a session
|
|
53
|
-
* @param payload - Session configuration payload
|
|
54
|
-
* @returns Promise that resolves when configuration is complete
|
|
55
|
-
*/
|
|
56
|
-
configureSession(payload: ConfigureSessionPayload): Promise<void>;
|
|
57
|
-
/**
|
|
58
|
-
* Helper method to navigate to a specific path
|
|
59
|
-
* @param payload - Navigation payload
|
|
60
|
-
* @returns Promise that resolves when navigation is complete
|
|
61
|
-
*/
|
|
62
|
-
navigate(payload: NavigatePayload): Promise<void>;
|
|
63
|
-
/**
|
|
64
|
-
* Helper method to add facts to the session
|
|
65
|
-
* @param payload - Facts payload
|
|
66
|
-
* @returns Promise that resolves when facts are added
|
|
67
|
-
*/
|
|
68
|
-
addFacts(payload: AddFactsPayload): Promise<void>;
|
|
69
|
-
/**
|
|
70
|
-
* Helper method to create a new interaction and return clean interaction data
|
|
71
|
-
* @param payload - Interaction creation payload
|
|
72
|
-
* @returns Promise that resolves with interaction details
|
|
73
|
-
*/
|
|
74
|
-
createInteraction(payload: CreateInteractionPayload): Promise<CreateInteractionResponse>;
|
|
75
|
-
/**
|
|
76
|
-
* Helper method to start recording
|
|
77
|
-
* @returns Promise that resolves when recording starts
|
|
78
|
-
*/
|
|
79
|
-
startRecording(): Promise<void>;
|
|
80
|
-
/**
|
|
81
|
-
* Helper method to stop recording
|
|
82
|
-
* @returns Promise that resolves when recording stops
|
|
83
|
-
*/
|
|
84
|
-
stopRecording(): Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* Helper method to get current status
|
|
87
|
-
* @returns Promise that resolves with current status
|
|
88
|
-
*/
|
|
89
|
-
getStatus(): Promise<GetStatusResponse>;
|
|
90
|
-
/**
|
|
91
|
-
* Helper method to configure the component
|
|
92
|
-
* @param payload - Component configuration payload
|
|
93
|
-
* @returns Promise that resolves when configuration is applied
|
|
94
|
-
*/
|
|
95
|
-
configure(payload: ConfigureAppPayload): Promise<ConfigureAppResponse>;
|
|
96
|
-
/**
|
|
97
|
-
* Helper method to set credentials without triggering auth flow
|
|
98
|
-
* @param payload - Credentials payload
|
|
99
|
-
* @returns Promise that resolves when credentials are set
|
|
100
|
-
*/
|
|
101
|
-
setCredentials(payload: SetCredentialsPayload): Promise<void>;
|
|
102
|
-
/**
|
|
103
|
-
* Helper method to get templates
|
|
104
|
-
* @returns Promise that resolves with a list of templates
|
|
53
|
+
* @param timeout - Optional timeout in milliseconds. Defaults to the requestTimeout set at construction.
|
|
105
54
|
*/
|
|
106
|
-
|
|
55
|
+
postMessage(message: Omit<EmbeddedRequest, "requestId">, timeout?: number): Promise<EmbeddedResponse>;
|
|
107
56
|
private static generateRequestId;
|
|
108
57
|
/**
|
|
109
58
|
* Derive the trusted origin from the iframe src (constructed from baseURL).
|
|
@@ -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
|
|
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 (
|
|
45
|
+
if (isEmbeddedResponseMessage(data) &&
|
|
46
|
+
this.pendingRequests.has(data.requestId)) {
|
|
29
47
|
this.handleResponse(data);
|
|
30
48
|
}
|
|
31
49
|
};
|
|
32
|
-
window.addEventListener(
|
|
50
|
+
window.addEventListener("message", this.messageListener);
|
|
33
51
|
}
|
|
34
52
|
handleEvent(eventData) {
|
|
35
53
|
const eventType = eventData.event;
|
|
36
54
|
const { payload } = eventData;
|
|
37
|
-
//
|
|
38
|
-
if (eventType ===
|
|
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 ||
|
|
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(
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
159
|
+
readyListener = (event) => {
|
|
101
160
|
if (event.source === this.iframe.contentWindow &&
|
|
102
161
|
event.origin === this.getTrustedOrigin() &&
|
|
103
|
-
event.data?.type ===
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
180
|
+
async postMessage(message, timeout) {
|
|
122
181
|
if (!this.iframe.contentWindow) {
|
|
123
|
-
throw new Error(
|
|
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(
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
|
|
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:
|
|
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,173 +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(
|
|
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
|
-
this.isReady = false;
|
|
174
|
-
if (response.payload && response.success) {
|
|
175
|
-
return response.payload.user;
|
|
176
|
-
}
|
|
177
|
-
throw new Error(response.error);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Helper method to configure a session
|
|
181
|
-
* @param payload - Session configuration payload
|
|
182
|
-
* @returns Promise that resolves when configuration is complete
|
|
183
|
-
*/
|
|
184
|
-
async configureSession(payload) {
|
|
185
|
-
await this.postMessage({
|
|
186
|
-
type: 'CORTI_EMBEDDED',
|
|
187
|
-
version: 'v1',
|
|
188
|
-
action: 'configureSession',
|
|
189
|
-
payload,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Helper method to navigate to a specific path
|
|
194
|
-
* @param payload - Navigation payload
|
|
195
|
-
* @returns Promise that resolves when navigation is complete
|
|
196
|
-
*/
|
|
197
|
-
async navigate(payload) {
|
|
198
|
-
await this.postMessage({
|
|
199
|
-
type: 'CORTI_EMBEDDED',
|
|
200
|
-
version: 'v1',
|
|
201
|
-
action: 'navigate',
|
|
202
|
-
payload,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Helper method to add facts to the session
|
|
207
|
-
* @param payload - Facts payload
|
|
208
|
-
* @returns Promise that resolves when facts are added
|
|
209
|
-
*/
|
|
210
|
-
async addFacts(payload) {
|
|
211
|
-
await this.postMessage({
|
|
212
|
-
type: 'CORTI_EMBEDDED',
|
|
213
|
-
version: 'v1',
|
|
214
|
-
action: 'addFacts',
|
|
215
|
-
payload,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Helper method to create a new interaction and return clean interaction data
|
|
220
|
-
* @param payload - Interaction creation payload
|
|
221
|
-
* @returns Promise that resolves with interaction details
|
|
222
|
-
*/
|
|
223
|
-
async createInteraction(payload) {
|
|
224
|
-
const response = await this.postMessage({
|
|
225
|
-
type: 'CORTI_EMBEDDED',
|
|
226
|
-
version: 'v1',
|
|
227
|
-
action: 'createInteraction',
|
|
228
|
-
payload,
|
|
229
|
-
});
|
|
230
|
-
if (response.payload && response.success) {
|
|
231
|
-
return response.payload;
|
|
232
|
-
}
|
|
233
|
-
throw new Error(response.error);
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Helper method to start recording
|
|
237
|
-
* @returns Promise that resolves when recording starts
|
|
238
|
-
*/
|
|
239
|
-
async startRecording() {
|
|
240
|
-
await this.postMessage({
|
|
241
|
-
type: 'CORTI_EMBEDDED',
|
|
242
|
-
version: 'v1',
|
|
243
|
-
action: 'startRecording',
|
|
244
|
-
payload: {},
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Helper method to stop recording
|
|
249
|
-
* @returns Promise that resolves when recording stops
|
|
250
|
-
*/
|
|
251
|
-
async stopRecording() {
|
|
252
|
-
await this.postMessage({
|
|
253
|
-
type: 'CORTI_EMBEDDED',
|
|
254
|
-
version: 'v1',
|
|
255
|
-
action: 'stopRecording',
|
|
256
|
-
payload: {},
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Helper method to get current status
|
|
261
|
-
* @returns Promise that resolves with current status
|
|
262
|
-
*/
|
|
263
|
-
async getStatus() {
|
|
264
|
-
const response = await this.postMessage({
|
|
265
|
-
type: 'CORTI_EMBEDDED',
|
|
266
|
-
version: 'v1',
|
|
267
|
-
action: 'getStatus',
|
|
268
|
-
payload: {},
|
|
269
|
-
});
|
|
270
|
-
if (response.payload && response.success) {
|
|
271
|
-
return response.payload;
|
|
272
|
-
}
|
|
273
|
-
throw new Error(response.error);
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Helper method to configure the component
|
|
277
|
-
* @param payload - Component configuration payload
|
|
278
|
-
* @returns Promise that resolves when configuration is applied
|
|
279
|
-
*/
|
|
280
|
-
async configure(payload) {
|
|
281
|
-
const response = await this.postMessage({
|
|
282
|
-
type: 'CORTI_EMBEDDED',
|
|
283
|
-
version: 'v1',
|
|
284
|
-
action: 'configure',
|
|
285
|
-
payload,
|
|
286
|
-
});
|
|
287
|
-
if (response.payload && response.success) {
|
|
288
|
-
return response.payload;
|
|
289
|
-
}
|
|
290
|
-
throw new Error(response.error);
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Helper method to set credentials without triggering auth flow
|
|
294
|
-
* @param payload - Credentials payload
|
|
295
|
-
* @returns Promise that resolves when credentials are set
|
|
296
|
-
*/
|
|
297
|
-
async setCredentials(payload) {
|
|
298
|
-
await this.postMessage({
|
|
299
|
-
type: 'CORTI_EMBEDDED',
|
|
300
|
-
version: 'v1',
|
|
301
|
-
action: 'setCredentials',
|
|
302
|
-
payload,
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Helper method to get templates
|
|
307
|
-
* @returns Promise that resolves with a list of templates
|
|
308
|
-
*/
|
|
309
|
-
async getTemplates() {
|
|
310
|
-
const response = await this.postMessage({
|
|
311
|
-
type: 'CORTI_EMBEDDED',
|
|
312
|
-
version: 'v1',
|
|
313
|
-
action: 'getTemplates',
|
|
314
|
-
});
|
|
315
|
-
if (response.payload && response.success) {
|
|
316
|
-
return response.payload;
|
|
317
|
-
}
|
|
318
|
-
throw new Error(response.error);
|
|
319
|
-
}
|
|
320
217
|
static generateRequestId() {
|
|
321
|
-
return `req_${Date.now()}_${Math.random().toString(36).
|
|
218
|
+
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
322
219
|
}
|
|
323
220
|
/**
|
|
324
221
|
* Derive the trusted origin from the iframe src (constructed from baseURL).
|
|
@@ -326,9 +223,7 @@ export class PostMessageHandler {
|
|
|
326
223
|
*/
|
|
327
224
|
getTrustedOrigin() {
|
|
328
225
|
try {
|
|
329
|
-
|
|
330
|
-
// Embeds should provide an absolute baseURL; enforcing strict origin here.
|
|
331
|
-
const src = this.iframe.getAttribute('src') || this.iframe.src;
|
|
226
|
+
const src = this.iframe.getAttribute("src") || this.iframe.src;
|
|
332
227
|
if (!src)
|
|
333
228
|
return null;
|
|
334
229
|
const url = new URL(src, window.location.href);
|
|
@@ -339,4 +234,5 @@ export class PostMessageHandler {
|
|
|
339
234
|
}
|
|
340
235
|
}
|
|
341
236
|
}
|
|
237
|
+
PostMessageHandler.SUPPORTED_PROTOCOL_VERSION = "v1";
|
|
342
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 this.isReady = false;\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"]}
|
package/dist/utils/baseUrl.js
CHANGED
|
@@ -4,22 +4,22 @@ export function validateAndNormalizeBaseURL(url) {
|
|
|
4
4
|
parsed = new URL(url);
|
|
5
5
|
}
|
|
6
6
|
catch {
|
|
7
|
-
throw new Error(
|
|
7
|
+
throw new Error("Invalid baseURL: not a parseable URL");
|
|
8
8
|
}
|
|
9
|
-
if (parsed.protocol !==
|
|
10
|
-
throw new Error(
|
|
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(
|
|
15
|
+
throw new Error("Invalid baseURL: host must match assistant.xxx.corti.app");
|
|
16
16
|
}
|
|
17
|
-
if (parsed.pathname && parsed.pathname !==
|
|
18
|
-
throw new Error(
|
|
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(
|
|
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
|