iframe-pubsub 1.0.21 → 1.0.22

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
@@ -26,37 +26,14 @@ declare class Client {
26
26
  protected targetAIChatClientId: string;
27
27
  private pageId;
28
28
  private callback?;
29
- private pubsub;
29
+ private pubsub?;
30
30
  private isIframe;
31
+ private isMainApp;
31
32
  private boundHandleMessage;
32
- /**
33
- * Create a new client instance.
34
- *
35
- * @param pageId The ID of the page or component to register to.
36
- */
37
33
  constructor(pageId: string, targetAIChatClientId?: string);
38
- /**
39
- * Unregister the client from the pubsub.
40
- */
41
34
  unregister(): void;
42
- /**
43
- * Clean up the aichat registration if the iframe is removed.
44
- *
45
- * Note: aichat itself does not know the iframe is removed then we have to clean up from parent
46
- */
47
35
  cleanAIChat(): boolean;
48
- /**
49
- * Listen for messages from the parent page with a callback.
50
- *
51
- * @param callback The callback function to register.
52
- */
53
36
  onMessage(callback: MessageCallback): void;
54
- /**
55
- * Send a message to the another page or component.
56
- *
57
- * @param to The ID of the page or component to send the message to.
58
- * @param payload The payload of the message.
59
- */
60
37
  sendMessage(to: string, payload: any): void;
61
38
  /**
62
39
  * Check if a client with the given ID exists in the PubSub system.
@@ -74,10 +51,15 @@ declare class Client {
74
51
  * @param clientId The ID of the client to check.
75
52
  * @param retryCount The current retry count.
76
53
  * @returns A Promise that resolves to true if the client exists, false otherwise.
77
- * @private
78
54
  */
79
55
  private checkClientExistsWithRetry;
80
56
  private handleMessage;
57
+ getDebugInfo(): {
58
+ pageId: string;
59
+ isMainApp: boolean;
60
+ isIframe: boolean;
61
+ windowLevel: string;
62
+ };
81
63
  }
82
64
 
83
65
  declare enum AIChatNameEnum {
package/dist/index.d.ts CHANGED
@@ -26,37 +26,14 @@ declare class Client {
26
26
  protected targetAIChatClientId: string;
27
27
  private pageId;
28
28
  private callback?;
29
- private pubsub;
29
+ private pubsub?;
30
30
  private isIframe;
31
+ private isMainApp;
31
32
  private boundHandleMessage;
32
- /**
33
- * Create a new client instance.
34
- *
35
- * @param pageId The ID of the page or component to register to.
36
- */
37
33
  constructor(pageId: string, targetAIChatClientId?: string);
38
- /**
39
- * Unregister the client from the pubsub.
40
- */
41
34
  unregister(): void;
42
- /**
43
- * Clean up the aichat registration if the iframe is removed.
44
- *
45
- * Note: aichat itself does not know the iframe is removed then we have to clean up from parent
46
- */
47
35
  cleanAIChat(): boolean;
48
- /**
49
- * Listen for messages from the parent page with a callback.
50
- *
51
- * @param callback The callback function to register.
52
- */
53
36
  onMessage(callback: MessageCallback): void;
54
- /**
55
- * Send a message to the another page or component.
56
- *
57
- * @param to The ID of the page or component to send the message to.
58
- * @param payload The payload of the message.
59
- */
60
37
  sendMessage(to: string, payload: any): void;
61
38
  /**
62
39
  * Check if a client with the given ID exists in the PubSub system.
@@ -74,10 +51,15 @@ declare class Client {
74
51
  * @param clientId The ID of the client to check.
75
52
  * @param retryCount The current retry count.
76
53
  * @returns A Promise that resolves to true if the client exists, false otherwise.
77
- * @private
78
54
  */
79
55
  private checkClientExistsWithRetry;
80
56
  private handleMessage;
57
+ getDebugInfo(): {
58
+ pageId: string;
59
+ isMainApp: boolean;
60
+ isIframe: boolean;
61
+ windowLevel: string;
62
+ };
81
63
  }
82
64
 
83
65
  declare enum AIChatNameEnum {
package/dist/index.js CHANGED
@@ -151,82 +151,70 @@ var PubSub = _PubSub;
151
151
 
152
152
  // src/Client.ts
153
153
  var Client = class {
154
- /**
155
- * Create a new client instance.
156
- *
157
- * @param pageId The ID of the page or component to register to.
158
- */
159
154
  constructor(pageId, targetAIChatClientId = "aichat" /* AI_CHAT_CLIENT_ID */) {
160
155
  __publicField(this, "targetAIChatClientId");
161
156
  __publicField(this, "pageId");
162
157
  __publicField(this, "callback");
163
158
  __publicField(this, "pubsub");
164
159
  __publicField(this, "isIframe");
160
+ __publicField(this, "isMainApp");
165
161
  __publicField(this, "boundHandleMessage");
166
162
  this.targetAIChatClientId = targetAIChatClientId;
167
163
  this.pageId = pageId;
168
- this.pubsub = PubSub.getInstance();
169
164
  this.isIframe = window !== window.parent;
165
+ this.isMainApp = window === window.top;
170
166
  this.boundHandleMessage = this.handleMessage.bind(this);
171
- if (this.isIframe) {
172
- window.parent.postMessage({
173
- type: "REGISTER",
174
- pageId: this.pageId
175
- }, "*");
176
- window.addEventListener("message", this.boundHandleMessage);
177
- } else {
167
+ if (this.isMainApp) {
168
+ this.pubsub = PubSub.getInstance();
178
169
  this.pubsub.register(pageId, this.boundHandleMessage);
170
+ console.info(`\u2705 Client ${pageId} registered with main PubSub`);
171
+ } else {
172
+ console.info(
173
+ `\u{1F4E1} Client ${pageId} from iframe is registering with top window PubSub`
174
+ );
175
+ window.top.postMessage(
176
+ {
177
+ type: "REGISTER",
178
+ pageId: this.pageId
179
+ },
180
+ "*"
181
+ );
182
+ window.addEventListener("message", this.boundHandleMessage);
179
183
  }
180
184
  }
181
- /**
182
- * Unregister the client from the pubsub.
183
- */
184
185
  unregister() {
185
- if (this.isIframe) {
186
- window.parent.postMessage({
187
- type: "UNREGISTER",
188
- pageId: this.pageId
189
- }, "*");
190
- } else {
186
+ if (this.isMainApp && this.pubsub) {
191
187
  this.pubsub.unregister(this.pageId);
188
+ } else {
189
+ window.top.postMessage(
190
+ {
191
+ type: "UNREGISTER",
192
+ pageId: this.pageId
193
+ },
194
+ "*"
195
+ );
196
+ window.removeEventListener("message", this.boundHandleMessage);
192
197
  }
198
+ console.info(`\u274C Client ${this.pageId} unregistered from PubSub`);
193
199
  }
194
- /**
195
- * Clean up the aichat registration if the iframe is removed.
196
- *
197
- * Note: aichat itself does not know the iframe is removed then we have to clean up from parent
198
- */
200
+ // Will not support this method anymore.
199
201
  cleanAIChat() {
200
- if (this.isIframe) {
201
- throw new Error("You are not allowed to clean up aichat from iframe.");
202
- }
203
- window.removeEventListener("message", this.boundHandleMessage);
204
- return this.pubsub.unregister(this.targetAIChatClientId);
202
+ console.warn(`\u203C\uFE0F Unsupported operation cleanAIChat has been called from ${this.pageId}.`);
203
+ return false;
205
204
  }
206
- /**
207
- * Listen for messages from the parent page with a callback.
208
- *
209
- * @param callback The callback function to register.
210
- */
211
205
  onMessage(callback) {
212
206
  this.callback = callback;
213
207
  }
214
- /**
215
- * Send a message to the another page or component.
216
- *
217
- * @param to The ID of the page or component to send the message to.
218
- * @param payload The payload of the message.
219
- */
220
208
  sendMessage(to, payload) {
221
209
  const message = {
222
210
  from: this.pageId,
223
211
  to,
224
212
  payload
225
213
  };
226
- if (this.isIframe) {
227
- window.parent.postMessage(message, "*");
228
- } else {
214
+ if (this.isMainApp && this.pubsub) {
229
215
  this.pubsub.sendMessage(message);
216
+ } else {
217
+ window.top.postMessage(message, "*");
230
218
  }
231
219
  }
232
220
  /**
@@ -238,7 +226,12 @@ var Client = class {
238
226
  * @returns A Promise that resolves to true if the client exists, false otherwise.
239
227
  */
240
228
  checkClientExists(clientId, maxRetries = 3, retryInterval = 1e3) {
241
- return this.checkClientExistsWithRetry(clientId, 0, maxRetries, retryInterval);
229
+ return this.checkClientExistsWithRetry(
230
+ clientId,
231
+ 0,
232
+ maxRetries,
233
+ retryInterval
234
+ );
242
235
  }
243
236
  /**
244
237
  * Check if a client with the given ID exists in the PubSub system with retry mechanism.
@@ -247,11 +240,26 @@ var Client = class {
247
240
  * @param clientId The ID of the client to check.
248
241
  * @param retryCount The current retry count.
249
242
  * @returns A Promise that resolves to true if the client exists, false otherwise.
250
- * @private
251
243
  */
252
244
  checkClientExistsWithRetry(clientId, retryCount, maxRetries, retryInterval) {
253
245
  return new Promise((resolve) => {
254
- if (this.isIframe) {
246
+ if (this.isMainApp && this.pubsub) {
247
+ const exists = this.pubsub.isClientExists(clientId);
248
+ if (exists) {
249
+ resolve(true);
250
+ } else if (retryCount < maxRetries - 1) {
251
+ setTimeout(() => {
252
+ this.checkClientExistsWithRetry(
253
+ clientId,
254
+ retryCount + 1,
255
+ maxRetries,
256
+ retryInterval
257
+ ).then((exists2) => resolve(exists2));
258
+ }, retryInterval);
259
+ } else {
260
+ resolve(false);
261
+ }
262
+ } else {
255
263
  const requestId = `check-client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
256
264
  const messageHandler = (event) => {
257
265
  const data = event.data;
@@ -262,7 +270,12 @@ var Client = class {
262
270
  resolve(true);
263
271
  } else if (retryCount < maxRetries - 1) {
264
272
  setTimeout(() => {
265
- this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists) => resolve(exists));
273
+ this.checkClientExistsWithRetry(
274
+ clientId,
275
+ retryCount + 1,
276
+ maxRetries,
277
+ retryInterval
278
+ ).then((exists) => resolve(exists));
266
279
  }, retryInterval);
267
280
  } else {
268
281
  resolve(false);
@@ -270,27 +283,19 @@ var Client = class {
270
283
  }
271
284
  };
272
285
  window.addEventListener("message", messageHandler);
273
- window.parent.postMessage({
274
- type: "CLIENT_EXISTS_CHECK",
275
- clientId,
276
- requestId,
277
- from: this.pageId
278
- }, "*");
286
+ window.top.postMessage(
287
+ {
288
+ type: "CLIENT_EXISTS_CHECK",
289
+ clientId,
290
+ requestId,
291
+ from: this.pageId
292
+ },
293
+ "*"
294
+ );
279
295
  const removeHandlerTimeout = setTimeout(() => {
280
296
  window.removeEventListener("message", messageHandler);
281
297
  resolve(false);
282
298
  }, retryInterval + 1e3);
283
- } else {
284
- const exists = this.pubsub.isClientExists(clientId);
285
- if (exists) {
286
- resolve(true);
287
- } else if (retryCount < maxRetries - 1) {
288
- setTimeout(() => {
289
- this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists2) => resolve(exists2));
290
- }, retryInterval);
291
- } else {
292
- resolve(false);
293
- }
294
299
  }
295
300
  });
296
301
  }
@@ -302,14 +307,34 @@ var Client = class {
302
307
  } else {
303
308
  message = event;
304
309
  }
305
- if (!message || !message.from || !message.to || message.to !== this.pageId) return;
310
+ if (!message || !message.from || !message.to || message.to !== this.pageId)
311
+ return;
306
312
  if (this.callback) {
307
313
  try {
308
314
  this.callback(message);
309
315
  } catch (error) {
310
- console.error(`Client ${this.pageId} failed to process message:`, error);
316
+ console.error(
317
+ `Client ${this.pageId} failed to process message:`,
318
+ error
319
+ );
320
+ }
321
+ }
322
+ }
323
+ getDebugInfo() {
324
+ let windowLevel = "main";
325
+ if (window !== window.top) {
326
+ if (window.parent === window.top) {
327
+ windowLevel = "first-level-iframe";
328
+ } else {
329
+ windowLevel = "nested-iframe";
311
330
  }
312
331
  }
332
+ return {
333
+ pageId: this.pageId,
334
+ isMainApp: this.isMainApp,
335
+ isIframe: this.isIframe,
336
+ windowLevel
337
+ };
313
338
  }
314
339
  };
315
340
 
package/dist/index.mjs CHANGED
@@ -124,82 +124,70 @@ var PubSub = _PubSub;
124
124
 
125
125
  // src/Client.ts
126
126
  var Client = class {
127
- /**
128
- * Create a new client instance.
129
- *
130
- * @param pageId The ID of the page or component to register to.
131
- */
132
127
  constructor(pageId, targetAIChatClientId = "aichat" /* AI_CHAT_CLIENT_ID */) {
133
128
  __publicField(this, "targetAIChatClientId");
134
129
  __publicField(this, "pageId");
135
130
  __publicField(this, "callback");
136
131
  __publicField(this, "pubsub");
137
132
  __publicField(this, "isIframe");
133
+ __publicField(this, "isMainApp");
138
134
  __publicField(this, "boundHandleMessage");
139
135
  this.targetAIChatClientId = targetAIChatClientId;
140
136
  this.pageId = pageId;
141
- this.pubsub = PubSub.getInstance();
142
137
  this.isIframe = window !== window.parent;
138
+ this.isMainApp = window === window.top;
143
139
  this.boundHandleMessage = this.handleMessage.bind(this);
144
- if (this.isIframe) {
145
- window.parent.postMessage({
146
- type: "REGISTER",
147
- pageId: this.pageId
148
- }, "*");
149
- window.addEventListener("message", this.boundHandleMessage);
150
- } else {
140
+ if (this.isMainApp) {
141
+ this.pubsub = PubSub.getInstance();
151
142
  this.pubsub.register(pageId, this.boundHandleMessage);
143
+ console.info(`\u2705 Client ${pageId} registered with main PubSub`);
144
+ } else {
145
+ console.info(
146
+ `\u{1F4E1} Client ${pageId} from iframe is registering with top window PubSub`
147
+ );
148
+ window.top.postMessage(
149
+ {
150
+ type: "REGISTER",
151
+ pageId: this.pageId
152
+ },
153
+ "*"
154
+ );
155
+ window.addEventListener("message", this.boundHandleMessage);
152
156
  }
153
157
  }
154
- /**
155
- * Unregister the client from the pubsub.
156
- */
157
158
  unregister() {
158
- if (this.isIframe) {
159
- window.parent.postMessage({
160
- type: "UNREGISTER",
161
- pageId: this.pageId
162
- }, "*");
163
- } else {
159
+ if (this.isMainApp && this.pubsub) {
164
160
  this.pubsub.unregister(this.pageId);
161
+ } else {
162
+ window.top.postMessage(
163
+ {
164
+ type: "UNREGISTER",
165
+ pageId: this.pageId
166
+ },
167
+ "*"
168
+ );
169
+ window.removeEventListener("message", this.boundHandleMessage);
165
170
  }
171
+ console.info(`\u274C Client ${this.pageId} unregistered from PubSub`);
166
172
  }
167
- /**
168
- * Clean up the aichat registration if the iframe is removed.
169
- *
170
- * Note: aichat itself does not know the iframe is removed then we have to clean up from parent
171
- */
173
+ // Will not support this method anymore.
172
174
  cleanAIChat() {
173
- if (this.isIframe) {
174
- throw new Error("You are not allowed to clean up aichat from iframe.");
175
- }
176
- window.removeEventListener("message", this.boundHandleMessage);
177
- return this.pubsub.unregister(this.targetAIChatClientId);
175
+ console.warn(`\u203C\uFE0F Unsupported operation cleanAIChat has been called from ${this.pageId}.`);
176
+ return false;
178
177
  }
179
- /**
180
- * Listen for messages from the parent page with a callback.
181
- *
182
- * @param callback The callback function to register.
183
- */
184
178
  onMessage(callback) {
185
179
  this.callback = callback;
186
180
  }
187
- /**
188
- * Send a message to the another page or component.
189
- *
190
- * @param to The ID of the page or component to send the message to.
191
- * @param payload The payload of the message.
192
- */
193
181
  sendMessage(to, payload) {
194
182
  const message = {
195
183
  from: this.pageId,
196
184
  to,
197
185
  payload
198
186
  };
199
- if (this.isIframe) {
200
- window.parent.postMessage(message, "*");
201
- } else {
187
+ if (this.isMainApp && this.pubsub) {
202
188
  this.pubsub.sendMessage(message);
189
+ } else {
190
+ window.top.postMessage(message, "*");
203
191
  }
204
192
  }
205
193
  /**
@@ -211,7 +199,12 @@ var Client = class {
211
199
  * @returns A Promise that resolves to true if the client exists, false otherwise.
212
200
  */
213
201
  checkClientExists(clientId, maxRetries = 3, retryInterval = 1e3) {
214
- return this.checkClientExistsWithRetry(clientId, 0, maxRetries, retryInterval);
202
+ return this.checkClientExistsWithRetry(
203
+ clientId,
204
+ 0,
205
+ maxRetries,
206
+ retryInterval
207
+ );
215
208
  }
216
209
  /**
217
210
  * Check if a client with the given ID exists in the PubSub system with retry mechanism.
@@ -220,11 +213,26 @@ var Client = class {
220
213
  * @param clientId The ID of the client to check.
221
214
  * @param retryCount The current retry count.
222
215
  * @returns A Promise that resolves to true if the client exists, false otherwise.
223
- * @private
224
216
  */
225
217
  checkClientExistsWithRetry(clientId, retryCount, maxRetries, retryInterval) {
226
218
  return new Promise((resolve) => {
227
- if (this.isIframe) {
219
+ if (this.isMainApp && this.pubsub) {
220
+ const exists = this.pubsub.isClientExists(clientId);
221
+ if (exists) {
222
+ resolve(true);
223
+ } else if (retryCount < maxRetries - 1) {
224
+ setTimeout(() => {
225
+ this.checkClientExistsWithRetry(
226
+ clientId,
227
+ retryCount + 1,
228
+ maxRetries,
229
+ retryInterval
230
+ ).then((exists2) => resolve(exists2));
231
+ }, retryInterval);
232
+ } else {
233
+ resolve(false);
234
+ }
235
+ } else {
228
236
  const requestId = `check-client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
229
237
  const messageHandler = (event) => {
230
238
  const data = event.data;
@@ -235,7 +243,12 @@ var Client = class {
235
243
  resolve(true);
236
244
  } else if (retryCount < maxRetries - 1) {
237
245
  setTimeout(() => {
238
- this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists) => resolve(exists));
246
+ this.checkClientExistsWithRetry(
247
+ clientId,
248
+ retryCount + 1,
249
+ maxRetries,
250
+ retryInterval
251
+ ).then((exists) => resolve(exists));
239
252
  }, retryInterval);
240
253
  } else {
241
254
  resolve(false);
@@ -243,27 +256,19 @@ var Client = class {
243
256
  }
244
257
  };
245
258
  window.addEventListener("message", messageHandler);
246
- window.parent.postMessage({
247
- type: "CLIENT_EXISTS_CHECK",
248
- clientId,
249
- requestId,
250
- from: this.pageId
251
- }, "*");
259
+ window.top.postMessage(
260
+ {
261
+ type: "CLIENT_EXISTS_CHECK",
262
+ clientId,
263
+ requestId,
264
+ from: this.pageId
265
+ },
266
+ "*"
267
+ );
252
268
  const removeHandlerTimeout = setTimeout(() => {
253
269
  window.removeEventListener("message", messageHandler);
254
270
  resolve(false);
255
271
  }, retryInterval + 1e3);
256
- } else {
257
- const exists = this.pubsub.isClientExists(clientId);
258
- if (exists) {
259
- resolve(true);
260
- } else if (retryCount < maxRetries - 1) {
261
- setTimeout(() => {
262
- this.checkClientExistsWithRetry(clientId, retryCount + 1, maxRetries, retryInterval).then((exists2) => resolve(exists2));
263
- }, retryInterval);
264
- } else {
265
- resolve(false);
266
- }
267
272
  }
268
273
  });
269
274
  }
@@ -275,14 +280,34 @@ var Client = class {
275
280
  } else {
276
281
  message = event;
277
282
  }
278
- if (!message || !message.from || !message.to || message.to !== this.pageId) return;
283
+ if (!message || !message.from || !message.to || message.to !== this.pageId)
284
+ return;
279
285
  if (this.callback) {
280
286
  try {
281
287
  this.callback(message);
282
288
  } catch (error) {
283
- console.error(`Client ${this.pageId} failed to process message:`, error);
289
+ console.error(
290
+ `Client ${this.pageId} failed to process message:`,
291
+ error
292
+ );
293
+ }
294
+ }
295
+ }
296
+ getDebugInfo() {
297
+ let windowLevel = "main";
298
+ if (window !== window.top) {
299
+ if (window.parent === window.top) {
300
+ windowLevel = "first-level-iframe";
301
+ } else {
302
+ windowLevel = "nested-iframe";
284
303
  }
285
304
  }
305
+ return {
306
+ pageId: this.pageId,
307
+ isMainApp: this.isMainApp,
308
+ isIframe: this.isIframe,
309
+ windowLevel
310
+ };
286
311
  }
287
312
  };
288
313
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iframe-pubsub",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "A PubSub library for iframe communication.",
5
5
  "author": "Lap Tran",
6
6
  "license": "ISC",