@polyguard/sdk 1.4.1 → 1.4.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/sdk.esm.js CHANGED
@@ -10984,6 +10984,7 @@ function handleWebSocketMessage(event, ctx) {
10984
10984
  const { sidebarUrl, link_uuid } = ctx;
10985
10985
  if (sidebarUrl && redirectUrl) {
10986
10986
  const hasMsftSession = document.cookie.includes("pg_msft_session");
10987
+ ctx.markClosed();
10987
10988
  cleanup();
10988
10989
  ws.close();
10989
10990
  if (hasMsftSession) {
@@ -11145,7 +11146,10 @@ var PolyguardWebsocketClientImpl = class {
11145
11146
  reconnectionDelayGrowFactor: 1.5
11146
11147
  };
11147
11148
  ws = new reconnecting_websocket_mjs_default(wsUrl, [], options);
11148
- const ctx = { ws, qrDiv, isTargetMode, modal, cleanup, returnError, clearError, resolve, rawJwt, sidebarUrl: this.sidebarUrl, link_uuid: this.link_uuid };
11149
+ const markClosed = () => {
11150
+ closed = true;
11151
+ };
11152
+ const ctx = { ws, qrDiv, isTargetMode, modal, cleanup, markClosed, returnError, clearError, resolve, rawJwt, sidebarUrl: this.sidebarUrl, link_uuid: this.link_uuid };
11149
11153
  ws.addEventListener("message", (event) => handleWebSocketMessage(event, ctx));
11150
11154
  ws.addEventListener("error", () => {
11151
11155
  console.error("WebSocket error");
package/dist/sdk.js CHANGED
@@ -11017,6 +11017,7 @@ var Polyguard = (() => {
11017
11017
  const { sidebarUrl, link_uuid } = ctx;
11018
11018
  if (sidebarUrl && redirectUrl) {
11019
11019
  const hasMsftSession = document.cookie.includes("pg_msft_session");
11020
+ ctx.markClosed();
11020
11021
  cleanup();
11021
11022
  ws.close();
11022
11023
  if (hasMsftSession) {
@@ -11178,7 +11179,10 @@ var Polyguard = (() => {
11178
11179
  reconnectionDelayGrowFactor: 1.5
11179
11180
  };
11180
11181
  ws = new reconnecting_websocket_mjs_default(wsUrl, [], options);
11181
- const ctx = { ws, qrDiv, isTargetMode, modal, cleanup, returnError, clearError, resolve, rawJwt, sidebarUrl: this.sidebarUrl, link_uuid: this.link_uuid };
11182
+ const markClosed = () => {
11183
+ closed = true;
11184
+ };
11185
+ const ctx = { ws, qrDiv, isTargetMode, modal, cleanup, markClosed, returnError, clearError, resolve, rawJwt, sidebarUrl: this.sidebarUrl, link_uuid: this.link_uuid };
11182
11186
  ws.addEventListener("message", (event) => handleWebSocketMessage(event, ctx));
11183
11187
  ws.addEventListener("error", () => {
11184
11188
  console.error("WebSocket error");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polyguard/sdk",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "type": "module",
5
5
  "main": "dist/sdk.esm.js",
6
6
  "module": "dist/sdk.esm.js",
@@ -136,7 +136,8 @@ export class PolyguardWebsocketClientImpl {
136
136
  };
137
137
  ws = new ReconnectingWebSocket(wsUrl, [], options);
138
138
 
139
- const ctx = { ws, qrDiv, isTargetMode, modal, cleanup, returnError, clearError, resolve, rawJwt, sidebarUrl: this.sidebarUrl, link_uuid: this.link_uuid };
139
+ const markClosed = () => { closed = true; };
140
+ const ctx = { ws, qrDiv, isTargetMode, modal, cleanup, markClosed, returnError, clearError, resolve, rawJwt, sidebarUrl: this.sidebarUrl, link_uuid: this.link_uuid };
140
141
  ws.addEventListener('message', (event) => handleWebSocketMessage(event, ctx));
141
142
 
142
143
  ws.addEventListener('error', () => {
@@ -243,6 +243,30 @@ describe('sidebarUrl feature', () => {
243
243
  await promise;
244
244
  expect(window.location.assign).toHaveBeenCalledWith('https://teams.microsoft.com/meet/123');
245
245
  });
246
+
247
+ it('button survives a late WebSocket close event (race regression)', async () => {
248
+ // Real browsers dispatch the 'close' event asynchronously after ws.close(),
249
+ // so it lands after the synchronous button append. If the close listener's
250
+ // cleanup() runs in that window, it wipes the qrDiv — and the button with it.
251
+ // markClosed() in the message handler must defuse the close listener.
252
+ clearCookies();
253
+ vi.stubGlobal('open', vi.fn().mockReturnValue({}));
254
+ const client = new PolyguardWebsocketClientImpl({
255
+ ...DEFAULT_PARAMS,
256
+ sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
257
+ link_uuid: 'link-abc',
258
+ });
259
+ document.body.innerHTML = '<div id="test-target"></div>';
260
+ const jwtClaims = { redirect_url: 'https://teams.microsoft.com/meet/123' };
261
+ const { promise, ws } = await startVerifyAndGetWs(client, 'test-target');
262
+ ws.simulateMessage({ jwt: jwtClaims });
263
+ expect(document.querySelector('#polyguard-join-meeting')).not.toBeNull();
264
+ // Mimic a real browser dispatching close on the next tick (after the message handler returned).
265
+ ws.simulateClose();
266
+ expect(document.querySelector('#polyguard-join-meeting')).not.toBeNull();
267
+ document.querySelector('#polyguard-join-meeting').click();
268
+ await promise;
269
+ });
246
270
  });
247
271
 
248
272
  describe('with sidebarUrl but no redirect_url in JWT (non-meeting links)', () => {
@@ -61,6 +61,11 @@ export function handleWebSocketMessage(event, ctx) {
61
61
  // the SDK handles the redirect (and optionally opens a sidebar popup).
62
62
  if (sidebarUrl && redirectUrl) {
63
63
  const hasMsftSession = document.cookie.includes('pg_msft_session');
64
+ // Mark the socket as intentionally closed BEFORE ws.close() so the
65
+ // 'close' event listener in verify() skips its own cleanup(). Otherwise
66
+ // the async close handler races with the synchronous button append below
67
+ // and wipes the qrDiv after we've put the button in it.
68
+ ctx.markClosed();
64
69
  cleanup();
65
70
  ws.close();
66
71