@polyguard/sdk 1.0.8 → 1.0.9
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.js +38 -37
- package/package.json +1 -1
- package/src/PolyguardWebsocketClientImpl.js +41 -35
package/dist/sdk.js
CHANGED
|
@@ -10950,6 +10950,22 @@
|
|
|
10950
10950
|
|
|
10951
10951
|
// src/PolyguardWebsocketClientImpl.js
|
|
10952
10952
|
var import_qrcode = __toESM(require_browser());
|
|
10953
|
+
var LOADING_SPINNER = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200" fill="none">
|
|
10954
|
+
<style>
|
|
10955
|
+
.spinner-circle {
|
|
10956
|
+
animation: spin 1s linear infinite;
|
|
10957
|
+
transform-origin: 100px 100px;
|
|
10958
|
+
}
|
|
10959
|
+
@keyframes spin {
|
|
10960
|
+
from { transform: rotate(0deg); }
|
|
10961
|
+
to { transform: rotate(360deg); }
|
|
10962
|
+
}
|
|
10963
|
+
</style>
|
|
10964
|
+
<circle cx="100" cy="100" r="80" stroke="#e0e0e0" stroke-width="8" fill="none" />
|
|
10965
|
+
<circle cx="100" cy="100" r="80" stroke="#7be7c2" stroke-width="8" fill="none"
|
|
10966
|
+
stroke-dasharray="251.2" stroke-dashoffset="188.4"
|
|
10967
|
+
class="spinner-circle" stroke-linecap="round" />
|
|
10968
|
+
</svg>`;
|
|
10953
10969
|
var PolyguardWebsocketClientImpl = class {
|
|
10954
10970
|
constructor(params = {}) {
|
|
10955
10971
|
this.apiClient = new ApiClient_default();
|
|
@@ -10977,7 +10993,7 @@
|
|
|
10977
10993
|
this.callbackUrl = callbackUrl;
|
|
10978
10994
|
this.cookieName = cookieName;
|
|
10979
10995
|
}
|
|
10980
|
-
|
|
10996
|
+
buildModal() {
|
|
10981
10997
|
const modal = document.createElement("div");
|
|
10982
10998
|
modal.style.position = "fixed";
|
|
10983
10999
|
modal.style.top = "0";
|
|
@@ -11006,13 +11022,21 @@
|
|
|
11006
11022
|
<button id="polyguard-modal-cancel" style="background: #7be7c2; color: #222; font-weight: 600; border-radius: 8px; border: none; padding: 10px 32px; font-size: 16px; cursor: pointer; margin-top: 8px; width: 100%; max-width: 240px;">Cancel</button>
|
|
11007
11023
|
</div>
|
|
11008
11024
|
`;
|
|
11025
|
+
return modal;
|
|
11026
|
+
}
|
|
11027
|
+
async verify() {
|
|
11028
|
+
const modal = this.buildModal();
|
|
11029
|
+
document.body.appendChild(modal);
|
|
11030
|
+
const qrDiv = modal.querySelector("#polyguard-qr");
|
|
11031
|
+
if (qrDiv) {
|
|
11032
|
+
qrDiv.innerHTML = LOADING_SPINNER;
|
|
11033
|
+
}
|
|
11009
11034
|
function cleanup() {
|
|
11010
11035
|
if (modal.parentNode) modal.parentNode.removeChild(modal);
|
|
11011
11036
|
}
|
|
11012
11037
|
return new Promise(async (resolve, reject) => {
|
|
11013
11038
|
let ws = null;
|
|
11014
11039
|
let closed = false;
|
|
11015
|
-
let modalShown = false;
|
|
11016
11040
|
function showError(msg) {
|
|
11017
11041
|
const errDiv = modal.querySelector("#polyguard-error");
|
|
11018
11042
|
if (errDiv) {
|
|
@@ -11030,11 +11054,8 @@
|
|
|
11030
11054
|
cleanup();
|
|
11031
11055
|
reject(new Error("User cancelled"));
|
|
11032
11056
|
}
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
modal.querySelector("#polyguard-modal-close").onclick = handleClose;
|
|
11036
|
-
modal.querySelector("#polyguard-modal-cancel").onclick = handleClose;
|
|
11037
|
-
}
|
|
11057
|
+
modal.querySelector("#polyguard-modal-close").onclick = handleClose;
|
|
11058
|
+
modal.querySelector("#polyguard-modal-cancel").onclick = handleClose;
|
|
11038
11059
|
try {
|
|
11039
11060
|
clearError();
|
|
11040
11061
|
const wsProtocol = window.location.protocol === "https:" ? "wss" : "ws";
|
|
@@ -11066,23 +11087,19 @@
|
|
|
11066
11087
|
window.location.assign(data.url);
|
|
11067
11088
|
return;
|
|
11068
11089
|
} else if (data && data.qr_url) {
|
|
11069
|
-
if (!modalShown) {
|
|
11070
|
-
showModal();
|
|
11071
|
-
modalShown = true;
|
|
11072
|
-
}
|
|
11073
11090
|
const pcre = data.qr_url.match(/pcre=([^&]*)/);
|
|
11074
11091
|
console.log("pcre", pcre);
|
|
11075
11092
|
if (pcre) {
|
|
11076
11093
|
ws.send(JSON.stringify({ type: "pong", seq: pcre[1] }));
|
|
11077
11094
|
}
|
|
11078
|
-
const
|
|
11079
|
-
if (!
|
|
11095
|
+
const qrDiv2 = modal.querySelector("#polyguard-qr");
|
|
11096
|
+
if (!qrDiv2) return;
|
|
11080
11097
|
const isMobile = /Mobi|Android/i.test(navigator.userAgent);
|
|
11081
11098
|
if (isMobile) {
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
const instructionText =
|
|
11099
|
+
qrDiv2.innerHTML = `<button id="polyguard-open-app-button" style="background: #7be7c2; color: #222; font-weight: 600; border-radius: 8px; border: none; padding: 10px 32px; font-size: 16px; cursor: pointer;">Open Polyguard App</button>`;
|
|
11100
|
+
qrDiv2.style.background = "transparent";
|
|
11101
|
+
qrDiv2.querySelector("#polyguard-open-app-button").onclick = () => window.location.assign(data.qr_url);
|
|
11102
|
+
const instructionText = qrDiv2.nextElementSibling;
|
|
11086
11103
|
if (instructionText) {
|
|
11087
11104
|
instructionText.textContent = "Tap the button to verify with the Polyguard app.";
|
|
11088
11105
|
}
|
|
@@ -11094,7 +11111,7 @@
|
|
|
11094
11111
|
const startTime = Date.now();
|
|
11095
11112
|
console.log("time before qr code", startTime);
|
|
11096
11113
|
import_qrcode.default.toString(data.qr_url, { type: "svg" }, (err, svg) => {
|
|
11097
|
-
if (!err)
|
|
11114
|
+
if (!err) qrDiv2.innerHTML = svg;
|
|
11098
11115
|
});
|
|
11099
11116
|
console.log("time to generate qr code", Date.now() - startTime);
|
|
11100
11117
|
}
|
|
@@ -11105,25 +11122,9 @@
|
|
|
11105
11122
|
ws.close();
|
|
11106
11123
|
return;
|
|
11107
11124
|
} else if (data && data.status) {
|
|
11108
|
-
const
|
|
11109
|
-
if (!
|
|
11110
|
-
|
|
11111
|
-
<style>
|
|
11112
|
-
.spinner-circle {
|
|
11113
|
-
animation: spin 1s linear infinite;
|
|
11114
|
-
transform-origin: 100px 100px;
|
|
11115
|
-
}
|
|
11116
|
-
@keyframes spin {
|
|
11117
|
-
from { transform: rotate(0deg); }
|
|
11118
|
-
to { transform: rotate(360deg); }
|
|
11119
|
-
}
|
|
11120
|
-
</style>
|
|
11121
|
-
<circle cx="100" cy="100" r="80" stroke="#e0e0e0" stroke-width="8" fill="none" />
|
|
11122
|
-
<circle cx="100" cy="100" r="80" stroke="#7be7c2" stroke-width="8" fill="none"
|
|
11123
|
-
stroke-dasharray="251.2" stroke-dashoffset="188.4"
|
|
11124
|
-
class="spinner-circle" stroke-linecap="round" />
|
|
11125
|
-
</svg>`;
|
|
11126
|
-
qrDiv.innerHTML = spinner;
|
|
11125
|
+
const qrDiv2 = modal.querySelector("#polyguard-qr");
|
|
11126
|
+
if (!qrDiv2) return;
|
|
11127
|
+
qrDiv2.innerHTML = LOADING_SPINNER;
|
|
11127
11128
|
return;
|
|
11128
11129
|
} else {
|
|
11129
11130
|
console.error("Unknown message type from server", data);
|
package/package.json
CHANGED
|
@@ -2,6 +2,24 @@ import ReconnectingWebSocket from 'reconnecting-websocket';
|
|
|
2
2
|
import * as PolyguardApi from './generated/src';
|
|
3
3
|
import QRCode from 'qrcode';
|
|
4
4
|
|
|
5
|
+
// Animated spinner SVG
|
|
6
|
+
const LOADING_SPINNER = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200" fill="none">
|
|
7
|
+
<style>
|
|
8
|
+
.spinner-circle {
|
|
9
|
+
animation: spin 1s linear infinite;
|
|
10
|
+
transform-origin: 100px 100px;
|
|
11
|
+
}
|
|
12
|
+
@keyframes spin {
|
|
13
|
+
from { transform: rotate(0deg); }
|
|
14
|
+
to { transform: rotate(360deg); }
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
<circle cx="100" cy="100" r="80" stroke="#e0e0e0" stroke-width="8" fill="none" />
|
|
18
|
+
<circle cx="100" cy="100" r="80" stroke="#7be7c2" stroke-width="8" fill="none"
|
|
19
|
+
stroke-dasharray="251.2" stroke-dashoffset="188.4"
|
|
20
|
+
class="spinner-circle" stroke-linecap="round" />
|
|
21
|
+
</svg>`;
|
|
22
|
+
|
|
5
23
|
// Implementation class for websocket integration
|
|
6
24
|
export class PolyguardWebsocketClientImpl {
|
|
7
25
|
constructor(params = {}) {
|
|
@@ -33,9 +51,7 @@ export class PolyguardWebsocketClientImpl {
|
|
|
33
51
|
this.cookieName = cookieName;
|
|
34
52
|
}
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
// Only websocket integration is supported for modal
|
|
38
|
-
// Create modal DOM
|
|
54
|
+
buildModal() {
|
|
39
55
|
const modal = document.createElement('div');
|
|
40
56
|
modal.style.position = 'fixed';
|
|
41
57
|
modal.style.top = '0';
|
|
@@ -64,17 +80,31 @@ export class PolyguardWebsocketClientImpl {
|
|
|
64
80
|
<button id="polyguard-modal-cancel" style="background: #7be7c2; color: #222; font-weight: 600; border-radius: 8px; border: none; padding: 10px 32px; font-size: 16px; cursor: pointer; margin-top: 8px; width: 100%; max-width: 240px;">Cancel</button>
|
|
65
81
|
</div>
|
|
66
82
|
`;
|
|
83
|
+
return modal;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async verify() {
|
|
87
|
+
// Only websocket integration is supported for modal
|
|
88
|
+
// Create modal DOM
|
|
89
|
+
const modal = this.buildModal();
|
|
90
|
+
|
|
91
|
+
// Show modal immediately with spinner
|
|
92
|
+
document.body.appendChild(modal);
|
|
93
|
+
|
|
94
|
+
// Initialize QR div with spinner
|
|
95
|
+
const qrDiv = modal.querySelector('#polyguard-qr');
|
|
96
|
+
if (qrDiv) {
|
|
97
|
+
qrDiv.innerHTML = LOADING_SPINNER;
|
|
98
|
+
}
|
|
67
99
|
|
|
68
100
|
// Helper to cleanup modal
|
|
69
101
|
function cleanup() {
|
|
70
102
|
if (modal.parentNode) modal.parentNode.removeChild(modal);
|
|
71
103
|
}
|
|
72
|
-
|
|
73
104
|
// Promise for JWT
|
|
74
105
|
return new Promise(async (resolve, reject) => {
|
|
75
106
|
let ws = null;
|
|
76
107
|
let closed = false;
|
|
77
|
-
let modalShown = false;
|
|
78
108
|
|
|
79
109
|
function showError(msg) {
|
|
80
110
|
const errDiv = modal.querySelector('#polyguard-error');
|
|
@@ -94,14 +124,10 @@ export class PolyguardWebsocketClientImpl {
|
|
|
94
124
|
cleanup();
|
|
95
125
|
reject(new Error('User cancelled'));
|
|
96
126
|
}
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// Set up close/cancel handlers after modal is in DOM
|
|
102
|
-
modal.querySelector('#polyguard-modal-close').onclick = handleClose;
|
|
103
|
-
modal.querySelector('#polyguard-modal-cancel').onclick = handleClose;
|
|
104
|
-
}
|
|
127
|
+
|
|
128
|
+
// Set up close/cancel handlers
|
|
129
|
+
modal.querySelector('#polyguard-modal-close').onclick = handleClose;
|
|
130
|
+
modal.querySelector('#polyguard-modal-cancel').onclick = handleClose;
|
|
105
131
|
|
|
106
132
|
// Start ticket/ws flow
|
|
107
133
|
try {
|
|
@@ -137,11 +163,7 @@ export class PolyguardWebsocketClientImpl {
|
|
|
137
163
|
window.location.assign(data.url);
|
|
138
164
|
return;
|
|
139
165
|
} else if (data && data.qr_url) {
|
|
140
|
-
//
|
|
141
|
-
if (!modalShown) {
|
|
142
|
-
showModal();
|
|
143
|
-
modalShown = true;
|
|
144
|
-
}
|
|
166
|
+
// Replace spinner with QR code content
|
|
145
167
|
|
|
146
168
|
const pcre = data.qr_url.match(/pcre=([^&]*)/);
|
|
147
169
|
console.log('pcre', pcre);
|
|
@@ -189,23 +211,7 @@ export class PolyguardWebsocketClientImpl {
|
|
|
189
211
|
// generate a spinner in svg and set the qr code to it
|
|
190
212
|
const qrDiv = modal.querySelector('#polyguard-qr');
|
|
191
213
|
if (!qrDiv) return;
|
|
192
|
-
|
|
193
|
-
<style>
|
|
194
|
-
.spinner-circle {
|
|
195
|
-
animation: spin 1s linear infinite;
|
|
196
|
-
transform-origin: 100px 100px;
|
|
197
|
-
}
|
|
198
|
-
@keyframes spin {
|
|
199
|
-
from { transform: rotate(0deg); }
|
|
200
|
-
to { transform: rotate(360deg); }
|
|
201
|
-
}
|
|
202
|
-
</style>
|
|
203
|
-
<circle cx="100" cy="100" r="80" stroke="#e0e0e0" stroke-width="8" fill="none" />
|
|
204
|
-
<circle cx="100" cy="100" r="80" stroke="#7be7c2" stroke-width="8" fill="none"
|
|
205
|
-
stroke-dasharray="251.2" stroke-dashoffset="188.4"
|
|
206
|
-
class="spinner-circle" stroke-linecap="round" />
|
|
207
|
-
</svg>`;
|
|
208
|
-
qrDiv.innerHTML = spinner;
|
|
214
|
+
qrDiv.innerHTML = LOADING_SPINNER;
|
|
209
215
|
return;
|
|
210
216
|
} else {
|
|
211
217
|
console.error('Unknown message type from server', data);
|