iframe-pubsub 1.0.0 → 1.0.2

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/dist/index.d.mts CHANGED
@@ -10,7 +10,153 @@ interface IMessage {
10
10
  to: string;
11
11
  payload: any;
12
12
  }
13
+ /**
14
+ * Message to register a page or component.
15
+ *
16
+ * @property {string} type - The type of the message.
17
+ * @property {string} pageId - The ID of the page or component.
18
+ */
19
+ interface IRegistrationMessage {
20
+ type: 'REGISTER' | 'UNREGISTER';
21
+ pageId: string;
22
+ }
13
23
  type MessageCallback = (message: IMessage) => void | Promise<void>;
24
+
25
+ declare class Client {
26
+ private pageId;
27
+ private callback?;
28
+ private pubsub;
29
+ private isIframe;
30
+ /**
31
+ * Create a new client instance.
32
+ *
33
+ * @param pageId The ID of the page or component to register to.
34
+ */
35
+ constructor(pageId: string);
36
+ /**
37
+ * Unregister the client from the pubsub.
38
+ */
39
+ unregister(): void;
40
+ /**
41
+ * Listen for messages from the parent page with a callback.
42
+ *
43
+ * @param callback The callback function to register.
44
+ */
45
+ onMessage(callback: MessageCallback): void;
46
+ /**
47
+ * Send a message to the another page or component.
48
+ *
49
+ * @param to The ID of the page or component to send the message to.
50
+ * @param payload The payload of the message.
51
+ */
52
+ sendMessage(to: string, payload: any): void;
53
+ /**
54
+ * Check if a client with the given ID exists in the PubSub system.
55
+ *
56
+ * @param clientId The ID of the client to check.
57
+ * @param maxRetries Maximum number of retries. Default is 3.
58
+ * @param retryInterval Interval between retries in milliseconds. Default is 1000ms.
59
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
60
+ */
61
+ checkClientExists(clientId: string, maxRetries?: number, retryInterval?: number): Promise<boolean>;
62
+ /**
63
+ * Check if a client with the given ID exists in the PubSub system with retry mechanism.
64
+ * Will retry up to 3 times with 1 second delay between retries.
65
+ *
66
+ * @param clientId The ID of the client to check.
67
+ * @param retryCount The current retry count.
68
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
69
+ * @private
70
+ */
71
+ private checkClientExistsWithRetry;
72
+ private handleMessage;
73
+ }
74
+
75
+ declare enum AIChatNameEnum {
76
+ AI_CHAT_CLIENT_ID = "aichat",
77
+ AI_CHAT_INTERNAL_COMM_TYPE = "pubsub",
78
+ SET_PARENT_NAME = "setParentName",
79
+ SET_USER_ID = "setUserId",
80
+ SET_CUSTOM_HEADERS = "setCustomHeaders",
81
+ SET_CUSTOM_PAYLOAD = "setCustomPayload",
82
+ SET_SUGGESTIONS = "setSuggestions",
83
+ SHOW_SUGGESTIONS = "showSuggestions",
84
+ SHOW_CHAT_MESSAGE = "showChatMessage",
85
+ CONFIRM_ACTION = "confirmAction",
86
+ SHOW_OPTIONS = "showOptions",
87
+ SEND_CHAT_PROMPT = "sendChatPrompt",
88
+ DEFAULT = "default"
89
+ }
90
+ declare class AIChatClient extends Client {
91
+ /**
92
+ * Create a new client instance.
93
+ *
94
+ * @param pageId The ID of the page or component to register to.
95
+ */
96
+ constructor(pageId: string);
97
+ private sendAIChatMethod;
98
+ /**
99
+ * Set the parent name then the AI Chat can know who should it communicate with.
100
+ *
101
+ * @param parentName The name of the parent page.
102
+ */
103
+ setParentName(parentName: string): void;
104
+ /**
105
+ * Set the user ID for the AI Chat component.
106
+ *
107
+ * @param userId The user ID.
108
+ */
109
+ setUserId(userId: string): void;
110
+ /**
111
+ * Set custom headers for the AI Chat component.
112
+ *
113
+ * @param headers The custom headers.
114
+ */
115
+ setCustomHeaders(headers: Record<string, string>): void;
116
+ /**
117
+ * Set custom payload for the AI Chat component.
118
+ *
119
+ * @param payload The custom payload.
120
+ */
121
+ setCustomPayload(payload: Record<string, any>): void;
122
+ /**
123
+ * Set suggestions for the AI Chat component.
124
+ *
125
+ * @param suggestions The suggestions to set.
126
+ */
127
+ setSuggestions(suggestions: any[]): void;
128
+ /**
129
+ * Show suggestions in the AI Chat component.
130
+ *
131
+ * @param show Whether to show suggestions.
132
+ */
133
+ showSuggestions(show: boolean): void;
134
+ /**
135
+ * Show a chat message in the AI Chat component.
136
+ *
137
+ * @param message The message to show.
138
+ */
139
+ showChatMessage(message: string): void;
140
+ /**
141
+ * Confirm an action in the AI Chat component.
142
+ *
143
+ * @param action The action to confirm.
144
+ */
145
+ confirmAction(action: any): void;
146
+ /**
147
+ * Show options in the AI Chat component.
148
+ *
149
+ * @param options The options to show.
150
+ */
151
+ showOptions(options: any[]): void;
152
+ /**
153
+ * Send a chat prompt to the AI Chat component.
154
+ *
155
+ * @param prompt The prompt to send.
156
+ */
157
+ sendChatPrompt(prompt: string): void;
158
+ }
159
+
14
160
  declare class PubSub {
15
161
  private static instance;
16
162
  private subscribers;
@@ -33,33 +179,22 @@ declare class PubSub {
33
179
  */
34
180
  unregister(pageId: string): void;
35
181
  sendMessage(message: IMessage): void;
36
- private handleMessage;
37
- }
38
- declare class Client {
39
- private pageId;
40
- private callback?;
41
- private pubsub;
42
- private isIframe;
43
182
  /**
44
- * Create a new client instance.
183
+ * Try to send a message to a client with retry logic.
184
+ * Will retry up to 3 times with 1 second delay between retries.
45
185
  *
46
- * @param pageId The ID of the page or component to register to.
186
+ * @param message The message to send.
187
+ * @param retryCount The current retry count.
47
188
  */
48
- constructor(pageId: string);
49
- /**
50
- * Listen for messages from the parent page with a callback.
51
- *
52
- * @param callback The callback function to register.
53
- */
54
- onMessage(callback: MessageCallback): void;
189
+ private trySendMessageWithRetry;
190
+ private handleMessage;
55
191
  /**
56
- * Send a message to the another page or component.
192
+ * Check if a client with the given ID exists in the PubSub system.
57
193
  *
58
- * @param to The ID of the page or component to send the message to.
59
- * @param payload The payload of the message.
194
+ * @param clientId The ID of the client to check.
195
+ * @returns True if the client exists, false otherwise.
60
196
  */
61
- sendMessage(to: string, payload: any): void;
62
- private handleMessage;
197
+ isClientExists(clientId: string): boolean;
63
198
  }
64
199
 
65
- export { Client, type IMessage, type MessageCallback, PubSub };
200
+ export { AIChatClient, AIChatNameEnum, Client, type IMessage, type IRegistrationMessage, type MessageCallback, PubSub };
package/dist/index.d.ts CHANGED
@@ -10,7 +10,153 @@ interface IMessage {
10
10
  to: string;
11
11
  payload: any;
12
12
  }
13
+ /**
14
+ * Message to register a page or component.
15
+ *
16
+ * @property {string} type - The type of the message.
17
+ * @property {string} pageId - The ID of the page or component.
18
+ */
19
+ interface IRegistrationMessage {
20
+ type: 'REGISTER' | 'UNREGISTER';
21
+ pageId: string;
22
+ }
13
23
  type MessageCallback = (message: IMessage) => void | Promise<void>;
24
+
25
+ declare class Client {
26
+ private pageId;
27
+ private callback?;
28
+ private pubsub;
29
+ private isIframe;
30
+ /**
31
+ * Create a new client instance.
32
+ *
33
+ * @param pageId The ID of the page or component to register to.
34
+ */
35
+ constructor(pageId: string);
36
+ /**
37
+ * Unregister the client from the pubsub.
38
+ */
39
+ unregister(): void;
40
+ /**
41
+ * Listen for messages from the parent page with a callback.
42
+ *
43
+ * @param callback The callback function to register.
44
+ */
45
+ onMessage(callback: MessageCallback): void;
46
+ /**
47
+ * Send a message to the another page or component.
48
+ *
49
+ * @param to The ID of the page or component to send the message to.
50
+ * @param payload The payload of the message.
51
+ */
52
+ sendMessage(to: string, payload: any): void;
53
+ /**
54
+ * Check if a client with the given ID exists in the PubSub system.
55
+ *
56
+ * @param clientId The ID of the client to check.
57
+ * @param maxRetries Maximum number of retries. Default is 3.
58
+ * @param retryInterval Interval between retries in milliseconds. Default is 1000ms.
59
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
60
+ */
61
+ checkClientExists(clientId: string, maxRetries?: number, retryInterval?: number): Promise<boolean>;
62
+ /**
63
+ * Check if a client with the given ID exists in the PubSub system with retry mechanism.
64
+ * Will retry up to 3 times with 1 second delay between retries.
65
+ *
66
+ * @param clientId The ID of the client to check.
67
+ * @param retryCount The current retry count.
68
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
69
+ * @private
70
+ */
71
+ private checkClientExistsWithRetry;
72
+ private handleMessage;
73
+ }
74
+
75
+ declare enum AIChatNameEnum {
76
+ AI_CHAT_CLIENT_ID = "aichat",
77
+ AI_CHAT_INTERNAL_COMM_TYPE = "pubsub",
78
+ SET_PARENT_NAME = "setParentName",
79
+ SET_USER_ID = "setUserId",
80
+ SET_CUSTOM_HEADERS = "setCustomHeaders",
81
+ SET_CUSTOM_PAYLOAD = "setCustomPayload",
82
+ SET_SUGGESTIONS = "setSuggestions",
83
+ SHOW_SUGGESTIONS = "showSuggestions",
84
+ SHOW_CHAT_MESSAGE = "showChatMessage",
85
+ CONFIRM_ACTION = "confirmAction",
86
+ SHOW_OPTIONS = "showOptions",
87
+ SEND_CHAT_PROMPT = "sendChatPrompt",
88
+ DEFAULT = "default"
89
+ }
90
+ declare class AIChatClient extends Client {
91
+ /**
92
+ * Create a new client instance.
93
+ *
94
+ * @param pageId The ID of the page or component to register to.
95
+ */
96
+ constructor(pageId: string);
97
+ private sendAIChatMethod;
98
+ /**
99
+ * Set the parent name then the AI Chat can know who should it communicate with.
100
+ *
101
+ * @param parentName The name of the parent page.
102
+ */
103
+ setParentName(parentName: string): void;
104
+ /**
105
+ * Set the user ID for the AI Chat component.
106
+ *
107
+ * @param userId The user ID.
108
+ */
109
+ setUserId(userId: string): void;
110
+ /**
111
+ * Set custom headers for the AI Chat component.
112
+ *
113
+ * @param headers The custom headers.
114
+ */
115
+ setCustomHeaders(headers: Record<string, string>): void;
116
+ /**
117
+ * Set custom payload for the AI Chat component.
118
+ *
119
+ * @param payload The custom payload.
120
+ */
121
+ setCustomPayload(payload: Record<string, any>): void;
122
+ /**
123
+ * Set suggestions for the AI Chat component.
124
+ *
125
+ * @param suggestions The suggestions to set.
126
+ */
127
+ setSuggestions(suggestions: any[]): void;
128
+ /**
129
+ * Show suggestions in the AI Chat component.
130
+ *
131
+ * @param show Whether to show suggestions.
132
+ */
133
+ showSuggestions(show: boolean): void;
134
+ /**
135
+ * Show a chat message in the AI Chat component.
136
+ *
137
+ * @param message The message to show.
138
+ */
139
+ showChatMessage(message: string): void;
140
+ /**
141
+ * Confirm an action in the AI Chat component.
142
+ *
143
+ * @param action The action to confirm.
144
+ */
145
+ confirmAction(action: any): void;
146
+ /**
147
+ * Show options in the AI Chat component.
148
+ *
149
+ * @param options The options to show.
150
+ */
151
+ showOptions(options: any[]): void;
152
+ /**
153
+ * Send a chat prompt to the AI Chat component.
154
+ *
155
+ * @param prompt The prompt to send.
156
+ */
157
+ sendChatPrompt(prompt: string): void;
158
+ }
159
+
14
160
  declare class PubSub {
15
161
  private static instance;
16
162
  private subscribers;
@@ -33,33 +179,22 @@ declare class PubSub {
33
179
  */
34
180
  unregister(pageId: string): void;
35
181
  sendMessage(message: IMessage): void;
36
- private handleMessage;
37
- }
38
- declare class Client {
39
- private pageId;
40
- private callback?;
41
- private pubsub;
42
- private isIframe;
43
182
  /**
44
- * Create a new client instance.
183
+ * Try to send a message to a client with retry logic.
184
+ * Will retry up to 3 times with 1 second delay between retries.
45
185
  *
46
- * @param pageId The ID of the page or component to register to.
186
+ * @param message The message to send.
187
+ * @param retryCount The current retry count.
47
188
  */
48
- constructor(pageId: string);
49
- /**
50
- * Listen for messages from the parent page with a callback.
51
- *
52
- * @param callback The callback function to register.
53
- */
54
- onMessage(callback: MessageCallback): void;
189
+ private trySendMessageWithRetry;
190
+ private handleMessage;
55
191
  /**
56
- * Send a message to the another page or component.
192
+ * Check if a client with the given ID exists in the PubSub system.
57
193
  *
58
- * @param to The ID of the page or component to send the message to.
59
- * @param payload The payload of the message.
194
+ * @param clientId The ID of the client to check.
195
+ * @returns True if the client exists, false otherwise.
60
196
  */
61
- sendMessage(to: string, payload: any): void;
62
- private handleMessage;
197
+ isClientExists(clientId: string): boolean;
63
198
  }
64
199
 
65
- export { Client, type IMessage, type MessageCallback, PubSub };
200
+ export { AIChatClient, AIChatNameEnum, Client, type IMessage, type IRegistrationMessage, type MessageCallback, PubSub };
package/dist/index.js CHANGED
@@ -22,10 +22,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
22
22
  // src/index.ts
23
23
  var index_exports = {};
24
24
  __export(index_exports, {
25
+ AIChatClient: () => AIChatClient,
26
+ AIChatNameEnum: () => AIChatNameEnum,
25
27
  Client: () => Client,
26
28
  PubSub: () => PubSub
27
29
  });
28
30
  module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/PubSub.ts
29
33
  var _PubSub = class _PubSub {
30
34
  constructor() {
31
35
  __publicField(this, "subscribers");
@@ -65,12 +69,31 @@ var _PubSub = class _PubSub {
65
69
  if (this.mainCallback) {
66
70
  this.mainCallback(message);
67
71
  }
72
+ this.trySendMessageWithRetry(message, 0);
73
+ }
74
+ /**
75
+ * Try to send a message to a client with retry logic.
76
+ * Will retry up to 3 times with 1 second delay between retries.
77
+ *
78
+ * @param message The message to send.
79
+ * @param retryCount The current retry count.
80
+ */
81
+ trySendMessageWithRetry(message, retryCount) {
68
82
  const subscriber = this.subscribers.get(message.to);
69
- if (!subscriber) return;
70
- if (subscriber.source) {
71
- subscriber.source.postMessage(message, "*");
83
+ if (subscriber) {
84
+ if (subscriber.source) {
85
+ subscriber.source.postMessage(message, "*");
86
+ } else {
87
+ subscriber.callback(message);
88
+ }
89
+ return;
90
+ }
91
+ if (retryCount < 10) {
92
+ setTimeout(() => {
93
+ this.trySendMessageWithRetry(message, retryCount + 1);
94
+ }, 1e3);
72
95
  } else {
73
- subscriber.callback(message);
96
+ console.warn(`Failed to send message to client ${message.to} after 10 retries`);
74
97
  }
75
98
  }
76
99
  async handleMessage(event) {
@@ -86,6 +109,19 @@ var _PubSub = class _PubSub {
86
109
  });
87
110
  return;
88
111
  }
112
+ if (data?.type === "UNREGISTER") {
113
+ const unregistration = data;
114
+ this.subscribers.delete(unregistration.pageId);
115
+ return;
116
+ }
117
+ if (data?.type === "CLIENT_EXISTS_CHECK") {
118
+ source.postMessage({
119
+ type: "CLIENT_EXISTS_RESPONSE",
120
+ requestId: data.requestId,
121
+ exists: this.subscribers.has(data.clientId)
122
+ }, "*");
123
+ return;
124
+ }
89
125
  if (!data || !data.from || !data.to) return;
90
126
  const message = data;
91
127
  if (this.mainCallback) {
@@ -99,9 +135,20 @@ var _PubSub = class _PubSub {
99
135
  await subscriber.callback(message);
100
136
  }
101
137
  }
138
+ /**
139
+ * Check if a client with the given ID exists in the PubSub system.
140
+ *
141
+ * @param clientId The ID of the client to check.
142
+ * @returns True if the client exists, false otherwise.
143
+ */
144
+ isClientExists(clientId) {
145
+ return this.subscribers.has(clientId);
146
+ }
102
147
  };
103
148
  __publicField(_PubSub, "instance");
104
149
  var PubSub = _PubSub;
150
+
151
+ // src/Client.ts
105
152
  var Client = class {
106
153
  /**
107
154
  * Create a new client instance.
@@ -126,6 +173,19 @@ var Client = class {
126
173
  this.pubsub.register(pageId, this.handleMessage.bind(this));
127
174
  }
128
175
  }
176
+ /**
177
+ * Unregister the client from the pubsub.
178
+ */
179
+ unregister() {
180
+ if (this.isIframe) {
181
+ window.parent.postMessage({
182
+ type: "UNREGISTER",
183
+ pageId: this.pageId
184
+ }, "*");
185
+ } else {
186
+ this.pubsub.unregister(this.pageId);
187
+ }
188
+ }
129
189
  /**
130
190
  * Listen for messages from the parent page with a callback.
131
191
  *
@@ -152,6 +212,71 @@ var Client = class {
152
212
  this.pubsub.sendMessage(message);
153
213
  }
154
214
  }
215
+ /**
216
+ * Check if a client with the given ID exists in the PubSub system.
217
+ *
218
+ * @param clientId The ID of the client to check.
219
+ * @param maxRetries Maximum number of retries. Default is 3.
220
+ * @param retryInterval Interval between retries in milliseconds. Default is 1000ms.
221
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
222
+ */
223
+ checkClientExists(clientId, maxRetries = 3, retryInterval = 1e3) {
224
+ return this.checkClientExistsWithRetry(clientId, 0, maxRetries, retryInterval);
225
+ }
226
+ /**
227
+ * Check if a client with the given ID exists in the PubSub system with retry mechanism.
228
+ * Will retry up to 3 times with 1 second delay between retries.
229
+ *
230
+ * @param clientId The ID of the client to check.
231
+ * @param retryCount The current retry count.
232
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
233
+ * @private
234
+ */
235
+ checkClientExistsWithRetry(clientId, retryCount, maxRetries, retryInterval) {
236
+ return new Promise((resolve) => {
237
+ if (this.isIframe) {
238
+ const requestId = `check-client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
239
+ const messageHandler = (event) => {
240
+ const data = event.data;
241
+ if (data && data.type === "CLIENT_EXISTS_RESPONSE" && data.requestId === requestId) {
242
+ window.removeEventListener("message", messageHandler);
243
+ clearTimeout(removeHandlerTimeout);
244
+ if (data.exists) {
245
+ resolve(true);
246
+ } else if (retryCount < maxRetries - 1) {
247
+ setTimeout(() => {
248
+ this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists) => resolve(exists));
249
+ }, retryInterval);
250
+ } else {
251
+ resolve(false);
252
+ }
253
+ }
254
+ };
255
+ window.addEventListener("message", messageHandler);
256
+ window.parent.postMessage({
257
+ type: "CLIENT_EXISTS_CHECK",
258
+ clientId,
259
+ requestId,
260
+ from: this.pageId
261
+ }, "*");
262
+ const removeHandlerTimeout = setTimeout(() => {
263
+ window.removeEventListener("message", messageHandler);
264
+ resolve(false);
265
+ }, retryInterval + 1e3);
266
+ } else {
267
+ const exists = this.pubsub.isClientExists(clientId);
268
+ if (exists) {
269
+ resolve(true);
270
+ } else if (retryCount < maxRetries - 1) {
271
+ setTimeout(() => {
272
+ this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists2) => resolve(exists2));
273
+ }, retryInterval);
274
+ } else {
275
+ resolve(false);
276
+ }
277
+ }
278
+ });
279
+ }
155
280
  async handleMessage(event) {
156
281
  let message;
157
282
  if (event.data) {
@@ -170,8 +295,130 @@ var Client = class {
170
295
  }
171
296
  }
172
297
  };
298
+
299
+ // src/aichat/AIChatClient.ts
300
+ var AIChatNameEnum = /* @__PURE__ */ ((AIChatNameEnum2) => {
301
+ AIChatNameEnum2["AI_CHAT_CLIENT_ID"] = "aichat";
302
+ AIChatNameEnum2["AI_CHAT_INTERNAL_COMM_TYPE"] = "pubsub";
303
+ AIChatNameEnum2["SET_PARENT_NAME"] = "setParentName";
304
+ AIChatNameEnum2["SET_USER_ID"] = "setUserId";
305
+ AIChatNameEnum2["SET_CUSTOM_HEADERS"] = "setCustomHeaders";
306
+ AIChatNameEnum2["SET_CUSTOM_PAYLOAD"] = "setCustomPayload";
307
+ AIChatNameEnum2["SET_SUGGESTIONS"] = "setSuggestions";
308
+ AIChatNameEnum2["SHOW_SUGGESTIONS"] = "showSuggestions";
309
+ AIChatNameEnum2["SHOW_CHAT_MESSAGE"] = "showChatMessage";
310
+ AIChatNameEnum2["CONFIRM_ACTION"] = "confirmAction";
311
+ AIChatNameEnum2["SHOW_OPTIONS"] = "showOptions";
312
+ AIChatNameEnum2["SEND_CHAT_PROMPT"] = "sendChatPrompt";
313
+ AIChatNameEnum2["DEFAULT"] = "default";
314
+ return AIChatNameEnum2;
315
+ })(AIChatNameEnum || {});
316
+ var AIChatClient = class extends Client {
317
+ /**
318
+ * Create a new client instance.
319
+ *
320
+ * @param pageId The ID of the page or component to register to.
321
+ */
322
+ constructor(pageId) {
323
+ super(pageId);
324
+ }
325
+ sendAIChatMethod(methodName, arg) {
326
+ this.sendMessage(
327
+ "aichat" /* AI_CHAT_CLIENT_ID */,
328
+ // This name is hardcode, do not change it
329
+ {
330
+ type: "pubsub" /* AI_CHAT_INTERNAL_COMM_TYPE */,
331
+ // This name is hardcode, do not change it
332
+ methodName,
333
+ arg
334
+ }
335
+ );
336
+ }
337
+ /**
338
+ * Set the parent name then the AI Chat can know who should it communicate with.
339
+ *
340
+ * @param parentName The name of the parent page.
341
+ */
342
+ setParentName(parentName) {
343
+ this.sendAIChatMethod("setParentName" /* SET_PARENT_NAME */, parentName);
344
+ }
345
+ /**
346
+ * Set the user ID for the AI Chat component.
347
+ *
348
+ * @param userId The user ID.
349
+ */
350
+ setUserId(userId) {
351
+ this.sendAIChatMethod("setUserId" /* SET_USER_ID */, userId);
352
+ }
353
+ /**
354
+ * Set custom headers for the AI Chat component.
355
+ *
356
+ * @param headers The custom headers.
357
+ */
358
+ setCustomHeaders(headers) {
359
+ this.sendAIChatMethod("setCustomHeaders" /* SET_CUSTOM_HEADERS */, headers);
360
+ }
361
+ /**
362
+ * Set custom payload for the AI Chat component.
363
+ *
364
+ * @param payload The custom payload.
365
+ */
366
+ setCustomPayload(payload) {
367
+ this.sendAIChatMethod("setCustomPayload" /* SET_CUSTOM_PAYLOAD */, payload);
368
+ }
369
+ /**
370
+ * Set suggestions for the AI Chat component.
371
+ *
372
+ * @param suggestions The suggestions to set.
373
+ */
374
+ setSuggestions(suggestions) {
375
+ this.sendAIChatMethod("setSuggestions" /* SET_SUGGESTIONS */, suggestions);
376
+ }
377
+ /**
378
+ * Show suggestions in the AI Chat component.
379
+ *
380
+ * @param show Whether to show suggestions.
381
+ */
382
+ showSuggestions(show) {
383
+ this.sendAIChatMethod("showSuggestions" /* SHOW_SUGGESTIONS */, show);
384
+ }
385
+ /**
386
+ * Show a chat message in the AI Chat component.
387
+ *
388
+ * @param message The message to show.
389
+ */
390
+ showChatMessage(message) {
391
+ this.sendAIChatMethod("showChatMessage" /* SHOW_CHAT_MESSAGE */, message);
392
+ }
393
+ /**
394
+ * Confirm an action in the AI Chat component.
395
+ *
396
+ * @param action The action to confirm.
397
+ */
398
+ confirmAction(action) {
399
+ this.sendAIChatMethod("confirmAction" /* CONFIRM_ACTION */, action);
400
+ }
401
+ /**
402
+ * Show options in the AI Chat component.
403
+ *
404
+ * @param options The options to show.
405
+ */
406
+ showOptions(options) {
407
+ this.sendAIChatMethod("showOptions" /* SHOW_OPTIONS */, options);
408
+ }
409
+ /**
410
+ * Send a chat prompt to the AI Chat component.
411
+ *
412
+ * @param prompt The prompt to send.
413
+ */
414
+ sendChatPrompt(prompt) {
415
+ this.sendAIChatMethod("sendChatPrompt" /* SEND_CHAT_PROMPT */, prompt);
416
+ }
417
+ };
173
418
  // Annotate the CommonJS export names for ESM import in node:
174
419
  0 && (module.exports = {
420
+ AIChatClient,
421
+ AIChatNameEnum,
175
422
  Client,
176
423
  PubSub
177
424
  });
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
 
5
- // src/index.ts
5
+ // src/PubSub.ts
6
6
  var _PubSub = class _PubSub {
7
7
  constructor() {
8
8
  __publicField(this, "subscribers");
@@ -42,12 +42,31 @@ var _PubSub = class _PubSub {
42
42
  if (this.mainCallback) {
43
43
  this.mainCallback(message);
44
44
  }
45
+ this.trySendMessageWithRetry(message, 0);
46
+ }
47
+ /**
48
+ * Try to send a message to a client with retry logic.
49
+ * Will retry up to 3 times with 1 second delay between retries.
50
+ *
51
+ * @param message The message to send.
52
+ * @param retryCount The current retry count.
53
+ */
54
+ trySendMessageWithRetry(message, retryCount) {
45
55
  const subscriber = this.subscribers.get(message.to);
46
- if (!subscriber) return;
47
- if (subscriber.source) {
48
- subscriber.source.postMessage(message, "*");
56
+ if (subscriber) {
57
+ if (subscriber.source) {
58
+ subscriber.source.postMessage(message, "*");
59
+ } else {
60
+ subscriber.callback(message);
61
+ }
62
+ return;
63
+ }
64
+ if (retryCount < 10) {
65
+ setTimeout(() => {
66
+ this.trySendMessageWithRetry(message, retryCount + 1);
67
+ }, 1e3);
49
68
  } else {
50
- subscriber.callback(message);
69
+ console.warn(`Failed to send message to client ${message.to} after 10 retries`);
51
70
  }
52
71
  }
53
72
  async handleMessage(event) {
@@ -63,6 +82,19 @@ var _PubSub = class _PubSub {
63
82
  });
64
83
  return;
65
84
  }
85
+ if (data?.type === "UNREGISTER") {
86
+ const unregistration = data;
87
+ this.subscribers.delete(unregistration.pageId);
88
+ return;
89
+ }
90
+ if (data?.type === "CLIENT_EXISTS_CHECK") {
91
+ source.postMessage({
92
+ type: "CLIENT_EXISTS_RESPONSE",
93
+ requestId: data.requestId,
94
+ exists: this.subscribers.has(data.clientId)
95
+ }, "*");
96
+ return;
97
+ }
66
98
  if (!data || !data.from || !data.to) return;
67
99
  const message = data;
68
100
  if (this.mainCallback) {
@@ -76,9 +108,20 @@ var _PubSub = class _PubSub {
76
108
  await subscriber.callback(message);
77
109
  }
78
110
  }
111
+ /**
112
+ * Check if a client with the given ID exists in the PubSub system.
113
+ *
114
+ * @param clientId The ID of the client to check.
115
+ * @returns True if the client exists, false otherwise.
116
+ */
117
+ isClientExists(clientId) {
118
+ return this.subscribers.has(clientId);
119
+ }
79
120
  };
80
121
  __publicField(_PubSub, "instance");
81
122
  var PubSub = _PubSub;
123
+
124
+ // src/Client.ts
82
125
  var Client = class {
83
126
  /**
84
127
  * Create a new client instance.
@@ -103,6 +146,19 @@ var Client = class {
103
146
  this.pubsub.register(pageId, this.handleMessage.bind(this));
104
147
  }
105
148
  }
149
+ /**
150
+ * Unregister the client from the pubsub.
151
+ */
152
+ unregister() {
153
+ if (this.isIframe) {
154
+ window.parent.postMessage({
155
+ type: "UNREGISTER",
156
+ pageId: this.pageId
157
+ }, "*");
158
+ } else {
159
+ this.pubsub.unregister(this.pageId);
160
+ }
161
+ }
106
162
  /**
107
163
  * Listen for messages from the parent page with a callback.
108
164
  *
@@ -129,6 +185,71 @@ var Client = class {
129
185
  this.pubsub.sendMessage(message);
130
186
  }
131
187
  }
188
+ /**
189
+ * Check if a client with the given ID exists in the PubSub system.
190
+ *
191
+ * @param clientId The ID of the client to check.
192
+ * @param maxRetries Maximum number of retries. Default is 3.
193
+ * @param retryInterval Interval between retries in milliseconds. Default is 1000ms.
194
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
195
+ */
196
+ checkClientExists(clientId, maxRetries = 3, retryInterval = 1e3) {
197
+ return this.checkClientExistsWithRetry(clientId, 0, maxRetries, retryInterval);
198
+ }
199
+ /**
200
+ * Check if a client with the given ID exists in the PubSub system with retry mechanism.
201
+ * Will retry up to 3 times with 1 second delay between retries.
202
+ *
203
+ * @param clientId The ID of the client to check.
204
+ * @param retryCount The current retry count.
205
+ * @returns A Promise that resolves to true if the client exists, false otherwise.
206
+ * @private
207
+ */
208
+ checkClientExistsWithRetry(clientId, retryCount, maxRetries, retryInterval) {
209
+ return new Promise((resolve) => {
210
+ if (this.isIframe) {
211
+ const requestId = `check-client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
212
+ const messageHandler = (event) => {
213
+ const data = event.data;
214
+ if (data && data.type === "CLIENT_EXISTS_RESPONSE" && data.requestId === requestId) {
215
+ window.removeEventListener("message", messageHandler);
216
+ clearTimeout(removeHandlerTimeout);
217
+ if (data.exists) {
218
+ resolve(true);
219
+ } else if (retryCount < maxRetries - 1) {
220
+ setTimeout(() => {
221
+ this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists) => resolve(exists));
222
+ }, retryInterval);
223
+ } else {
224
+ resolve(false);
225
+ }
226
+ }
227
+ };
228
+ window.addEventListener("message", messageHandler);
229
+ window.parent.postMessage({
230
+ type: "CLIENT_EXISTS_CHECK",
231
+ clientId,
232
+ requestId,
233
+ from: this.pageId
234
+ }, "*");
235
+ const removeHandlerTimeout = setTimeout(() => {
236
+ window.removeEventListener("message", messageHandler);
237
+ resolve(false);
238
+ }, retryInterval + 1e3);
239
+ } else {
240
+ const exists = this.pubsub.isClientExists(clientId);
241
+ if (exists) {
242
+ resolve(true);
243
+ } else if (retryCount < maxRetries - 1) {
244
+ setTimeout(() => {
245
+ this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists2) => resolve(exists2));
246
+ }, retryInterval);
247
+ } else {
248
+ resolve(false);
249
+ }
250
+ }
251
+ });
252
+ }
132
253
  async handleMessage(event) {
133
254
  let message;
134
255
  if (event.data) {
@@ -147,7 +268,129 @@ var Client = class {
147
268
  }
148
269
  }
149
270
  };
271
+
272
+ // src/aichat/AIChatClient.ts
273
+ var AIChatNameEnum = /* @__PURE__ */ ((AIChatNameEnum2) => {
274
+ AIChatNameEnum2["AI_CHAT_CLIENT_ID"] = "aichat";
275
+ AIChatNameEnum2["AI_CHAT_INTERNAL_COMM_TYPE"] = "pubsub";
276
+ AIChatNameEnum2["SET_PARENT_NAME"] = "setParentName";
277
+ AIChatNameEnum2["SET_USER_ID"] = "setUserId";
278
+ AIChatNameEnum2["SET_CUSTOM_HEADERS"] = "setCustomHeaders";
279
+ AIChatNameEnum2["SET_CUSTOM_PAYLOAD"] = "setCustomPayload";
280
+ AIChatNameEnum2["SET_SUGGESTIONS"] = "setSuggestions";
281
+ AIChatNameEnum2["SHOW_SUGGESTIONS"] = "showSuggestions";
282
+ AIChatNameEnum2["SHOW_CHAT_MESSAGE"] = "showChatMessage";
283
+ AIChatNameEnum2["CONFIRM_ACTION"] = "confirmAction";
284
+ AIChatNameEnum2["SHOW_OPTIONS"] = "showOptions";
285
+ AIChatNameEnum2["SEND_CHAT_PROMPT"] = "sendChatPrompt";
286
+ AIChatNameEnum2["DEFAULT"] = "default";
287
+ return AIChatNameEnum2;
288
+ })(AIChatNameEnum || {});
289
+ var AIChatClient = class extends Client {
290
+ /**
291
+ * Create a new client instance.
292
+ *
293
+ * @param pageId The ID of the page or component to register to.
294
+ */
295
+ constructor(pageId) {
296
+ super(pageId);
297
+ }
298
+ sendAIChatMethod(methodName, arg) {
299
+ this.sendMessage(
300
+ "aichat" /* AI_CHAT_CLIENT_ID */,
301
+ // This name is hardcode, do not change it
302
+ {
303
+ type: "pubsub" /* AI_CHAT_INTERNAL_COMM_TYPE */,
304
+ // This name is hardcode, do not change it
305
+ methodName,
306
+ arg
307
+ }
308
+ );
309
+ }
310
+ /**
311
+ * Set the parent name then the AI Chat can know who should it communicate with.
312
+ *
313
+ * @param parentName The name of the parent page.
314
+ */
315
+ setParentName(parentName) {
316
+ this.sendAIChatMethod("setParentName" /* SET_PARENT_NAME */, parentName);
317
+ }
318
+ /**
319
+ * Set the user ID for the AI Chat component.
320
+ *
321
+ * @param userId The user ID.
322
+ */
323
+ setUserId(userId) {
324
+ this.sendAIChatMethod("setUserId" /* SET_USER_ID */, userId);
325
+ }
326
+ /**
327
+ * Set custom headers for the AI Chat component.
328
+ *
329
+ * @param headers The custom headers.
330
+ */
331
+ setCustomHeaders(headers) {
332
+ this.sendAIChatMethod("setCustomHeaders" /* SET_CUSTOM_HEADERS */, headers);
333
+ }
334
+ /**
335
+ * Set custom payload for the AI Chat component.
336
+ *
337
+ * @param payload The custom payload.
338
+ */
339
+ setCustomPayload(payload) {
340
+ this.sendAIChatMethod("setCustomPayload" /* SET_CUSTOM_PAYLOAD */, payload);
341
+ }
342
+ /**
343
+ * Set suggestions for the AI Chat component.
344
+ *
345
+ * @param suggestions The suggestions to set.
346
+ */
347
+ setSuggestions(suggestions) {
348
+ this.sendAIChatMethod("setSuggestions" /* SET_SUGGESTIONS */, suggestions);
349
+ }
350
+ /**
351
+ * Show suggestions in the AI Chat component.
352
+ *
353
+ * @param show Whether to show suggestions.
354
+ */
355
+ showSuggestions(show) {
356
+ this.sendAIChatMethod("showSuggestions" /* SHOW_SUGGESTIONS */, show);
357
+ }
358
+ /**
359
+ * Show a chat message in the AI Chat component.
360
+ *
361
+ * @param message The message to show.
362
+ */
363
+ showChatMessage(message) {
364
+ this.sendAIChatMethod("showChatMessage" /* SHOW_CHAT_MESSAGE */, message);
365
+ }
366
+ /**
367
+ * Confirm an action in the AI Chat component.
368
+ *
369
+ * @param action The action to confirm.
370
+ */
371
+ confirmAction(action) {
372
+ this.sendAIChatMethod("confirmAction" /* CONFIRM_ACTION */, action);
373
+ }
374
+ /**
375
+ * Show options in the AI Chat component.
376
+ *
377
+ * @param options The options to show.
378
+ */
379
+ showOptions(options) {
380
+ this.sendAIChatMethod("showOptions" /* SHOW_OPTIONS */, options);
381
+ }
382
+ /**
383
+ * Send a chat prompt to the AI Chat component.
384
+ *
385
+ * @param prompt The prompt to send.
386
+ */
387
+ sendChatPrompt(prompt) {
388
+ this.sendAIChatMethod("sendChatPrompt" /* SEND_CHAT_PROMPT */, prompt);
389
+ }
390
+ };
150
391
  export {
392
+ AIChatClient,
393
+ AIChatNameEnum,
151
394
  Client,
152
395
  PubSub
153
396
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iframe-pubsub",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",