@polyguard/sdk 1.1.3 → 1.1.6

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 CHANGED
@@ -10969,7 +10969,7 @@
10969
10969
  var PolyguardWebsocketClientImpl = class {
10970
10970
  constructor(params = {}) {
10971
10971
  this.apiClient = new ApiClient_default();
10972
- const { apiKey, baseUrl, appId, apiServer, requiredProofs = ["Full Name"], scanType = "single", redirectUrl, callbackUrl, cookieName } = params;
10972
+ const { apiKey, baseUrl, appId, apiServer, requiredProofs = ["Full Name"], scanType = "single", redirectUrl, callbackUrl, cookieName, link_uuid } = params;
10973
10973
  if (baseUrl) {
10974
10974
  this.apiClient.basePath = baseUrl;
10975
10975
  }
@@ -10992,6 +10992,7 @@
10992
10992
  this.redirectUrl = redirectUrl;
10993
10993
  this.callbackUrl = callbackUrl;
10994
10994
  this.cookieName = cookieName;
10995
+ this.link_uuid = link_uuid;
10995
10996
  }
10996
10997
  buildModal() {
10997
10998
  const modal = document.createElement("div");
@@ -11024,33 +11025,60 @@
11024
11025
  `;
11025
11026
  return modal;
11026
11027
  }
11027
- async verify() {
11028
- const modal = this.buildModal();
11029
- document.body.appendChild(modal);
11030
- const qrDiv = modal.querySelector("#polyguard-qr");
11028
+ async verify(target = null, rawJwt = false) {
11029
+ let modal = null;
11030
+ let qrDiv = null;
11031
+ let isTargetMode = false;
11032
+ if (target) {
11033
+ isTargetMode = true;
11034
+ qrDiv = document.getElementById(target);
11035
+ if (!qrDiv) {
11036
+ throw new Error(`Target element with ID '${target}' not found`);
11037
+ }
11038
+ } else {
11039
+ modal = this.buildModal();
11040
+ }
11041
+ if (!isTargetMode) {
11042
+ document.body.appendChild(modal);
11043
+ qrDiv = modal.querySelector("#polyguard-qr");
11044
+ }
11031
11045
  if (qrDiv) {
11032
11046
  qrDiv.innerHTML = LOADING_SPINNER;
11033
11047
  }
11034
11048
  function cleanup() {
11035
- if (modal.parentNode) modal.parentNode.removeChild(modal);
11049
+ if (isTargetMode) {
11050
+ if (qrDiv) {
11051
+ qrDiv.innerHTML = "";
11052
+ }
11053
+ } else if (modal && modal.parentNode) {
11054
+ modal.parentNode.removeChild(modal);
11055
+ }
11036
11056
  }
11037
11057
  return new Promise(async (resolve, reject) => {
11038
11058
  let ws = null;
11039
11059
  let closed = false;
11040
11060
  function returnError(msg, score = "OFFLINE") {
11041
- const errDiv = modal.querySelector("#polyguard-error");
11042
- if (errDiv) {
11043
- errDiv.textContent = msg;
11044
- errDiv.style.display = "block";
11045
- }
11046
- setTimeout(() => {
11061
+ if (isTargetMode) {
11062
+ console.error("Polyguard Error:", msg);
11047
11063
  cleanup();
11048
11064
  resolve({ presence: { score, msg } });
11049
- }, 1250);
11065
+ } else {
11066
+ const errDiv = modal.querySelector("#polyguard-error");
11067
+ if (errDiv) {
11068
+ errDiv.textContent = msg;
11069
+ errDiv.style.display = "block";
11070
+ }
11071
+ setTimeout(() => {
11072
+ cleanup();
11073
+ resolve({ presence: { score, msg } });
11074
+ }, 1250);
11075
+ }
11050
11076
  }
11051
11077
  function clearError() {
11052
- const errDiv = modal.querySelector("#polyguard-error");
11053
- if (errDiv) errDiv.style.display = "none";
11078
+ if (!isTargetMode) {
11079
+ const errDiv = modal.querySelector("#polyguard-error");
11080
+ if (errDiv) errDiv.style.display = "none";
11081
+ }
11054
11082
  }
11055
11083
  function handleClose() {
11056
11084
  closed = true;
@@ -11058,12 +11086,15 @@
11058
11086
  cleanup();
11059
11087
  reject(new Error("User cancelled"));
11060
11088
  }
11061
- modal.querySelector("#polyguard-modal-close").onclick = handleClose;
11062
- modal.querySelector("#polyguard-modal-cancel").onclick = handleClose;
11089
+ if (!isTargetMode) {
11090
+ modal.querySelector("#polyguard-modal-close").onclick = handleClose;
11091
+ modal.querySelector("#polyguard-modal-cancel").onclick = handleClose;
11092
+ }
11063
11093
  try {
11064
11094
  clearError();
11065
11095
  const wsProtocol = window.location.protocol === "https:" ? "wss" : "ws";
11066
- const ticketRes = await fetch(`https://${this.apiServer}/v2/ticket/${this.appId}`, {
11096
+ const ticketUrl = this.link_uuid ? `https://${this.apiServer}/v2/ticket/${this.appId}/${this.link_uuid}` : `https://${this.apiServer}/v2/ticket/${this.appId}`;
11097
+ const ticketRes = await fetch(ticketUrl, {
11067
11098
  method: "POST",
11068
11099
  headers: { "Content-Type": "application/json" },
11069
11100
  body: JSON.stringify({ requiredProofs: this.requiredProofs, scanType: this.scanType })
@@ -11103,26 +11134,27 @@
11103
11134
  if (pcre) {
11104
11135
  ws.send(JSON.stringify({ type: "pong", seq: pcre[1] }));
11105
11136
  }
11106
- const qrDiv2 = modal.querySelector("#polyguard-qr");
11107
- if (!qrDiv2) return;
11137
+ if (!qrDiv) return;
11108
11138
  const isMobile = /Mobi|Android/i.test(navigator.userAgent);
11109
11139
  if (isMobile) {
11110
- 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>`;
11111
- qrDiv2.style.background = "transparent";
11112
- qrDiv2.querySelector("#polyguard-open-app-button").onclick = () => window.location.assign(data.qr_url);
11113
- const instructionText = qrDiv2.nextElementSibling;
11114
- if (instructionText) {
11115
- instructionText.textContent = "Tap the button to verify with the Polyguard app.";
11116
- }
11117
- const instructionList = instructionText.nextElementSibling;
11118
- if (instructionList && instructionList.children[1]) {
11119
- instructionList.children[1].textContent = "If you do not have the Polyguard app, you will be redirected to download it.";
11140
+ qrDiv.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>`;
11141
+ qrDiv.style.background = "transparent";
11142
+ qrDiv.querySelector("#polyguard-open-app-button").onclick = () => window.location.assign(data.qr_url);
11143
+ if (!isTargetMode) {
11144
+ const instructionText = qrDiv.nextElementSibling;
11145
+ if (instructionText) {
11146
+ instructionText.textContent = "Tap the button to verify with the Polyguard app.";
11147
+ }
11148
+ const instructionList = instructionText.nextElementSibling;
11149
+ if (instructionList && instructionList.children[1]) {
11150
+ instructionList.children[1].textContent = "If you do not have the Polyguard app, you will be redirected to download it.";
11151
+ }
11120
11152
  }
11121
11153
  } else {
11122
11154
  const startTime = Date.now();
11123
11155
  console.log("time before qr code", startTime);
11124
11156
  import_qrcode.default.toString(data.qr_url, { type: "svg" }, (err, svg) => {
11125
- if (!err) qrDiv2.innerHTML = svg;
11157
+ if (!err) qrDiv.innerHTML = svg;
11126
11158
  });
11127
11159
  console.log("time to generate qr code", Date.now() - startTime);
11128
11160
  }
@@ -11130,12 +11162,11 @@
11130
11162
  } else if (data && data.jwt) {
11131
11163
  cleanup();
11132
11164
  ws.close();
11133
- resolve(data.jwt);
11165
+ resolve(rawJwt ? data : data.jwt);
11134
11166
  return;
11135
11167
  } else if (data && data.status) {
11136
- const qrDiv2 = modal.querySelector("#polyguard-qr");
11137
- if (!qrDiv2) return;
11138
- qrDiv2.innerHTML = LOADING_SPINNER;
11168
+ if (!qrDiv) return;
11169
+ qrDiv.innerHTML = LOADING_SPINNER;
11139
11170
  return;
11140
11171
  } else if (data && data.error) {
11141
11172
  returnError(data.error);
@@ -11167,11 +11198,12 @@
11167
11198
  /**
11168
11199
  * Wrapper around verify that checks received proof values against expected values.
11169
11200
  * @param {Object} expectedProofs - An object mapping proof names to expected values.
11201
+ * @param {string} target - Optional ID of target element to render QR code in.
11170
11202
  * @returns {Promise<boolean>} - Resolves to true if all expected proofs match, false otherwise or if cancelled.
11171
11203
  */
11172
- async require(expectedProofs = {}) {
11204
+ async require(expectedProofs = {}, target = null) {
11173
11205
  try {
11174
- const jwt = await this.verify();
11206
+ const jwt = await this.verify(target);
11175
11207
  if (!jwt) return false;
11176
11208
  const payload = JSON.parse(atob(jwt.split(".")[1]));
11177
11209
  console.dir(payload);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polyguard/sdk",
3
- "version": "1.1.3",
3
+ "version": "1.1.6",
4
4
  "main": "dist/sdk.js",
5
5
  "module": "dist/sdk.js",
6
6
  "browser": "dist/sdk.js",
@@ -20,7 +20,7 @@
20
20
  "superagent": "^8.1.2"
21
21
  },
22
22
  "devDependencies": {
23
- "esbuild": "^0.21.4"
23
+ "esbuild": "^0.25.0"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
@@ -24,7 +24,7 @@ const LOADING_SPINNER = `<svg xmlns="http://www.w3.org/2000/svg" width="200" hei
24
24
  export class PolyguardWebsocketClientImpl {
25
25
  constructor(params = {}) {
26
26
  this.apiClient = new PolyguardApi.ApiClient();
27
- const { apiKey, baseUrl, appId, apiServer, requiredProofs = ['Full Name'], scanType = 'single', redirectUrl, callbackUrl, cookieName } = params;
27
+ const { apiKey, baseUrl, appId, apiServer, requiredProofs = ['Full Name'], scanType = 'single', redirectUrl, callbackUrl, cookieName, link_uuid } = params;
28
28
  if (baseUrl) {
29
29
  this.apiClient.basePath = baseUrl;
30
30
  }
@@ -49,6 +49,7 @@ export class PolyguardWebsocketClientImpl {
49
49
  this.redirectUrl = redirectUrl;
50
50
  this.callbackUrl = callbackUrl;
51
51
  this.cookieName = cookieName;
52
+ this.link_uuid = link_uuid;
52
53
  }
53
54
 
54
55
  buildModal() {
@@ -83,23 +84,46 @@ export class PolyguardWebsocketClientImpl {
83
84
  return modal;
84
85
  }
85
86
 
86
- async verify() {
87
+ async verify(target = null, rawJwt = false) {
87
88
  // Only websocket integration is supported for modal
88
- // Create modal DOM
89
- const modal = this.buildModal();
89
+ let modal = null;
90
+ let qrDiv = null;
91
+ let isTargetMode = false;
90
92
 
91
- // Show modal immediately with spinner
92
- document.body.appendChild(modal);
93
+ if (target) {
94
+ // Target mode: render QR code in specified element
95
+ isTargetMode = true;
96
+ qrDiv = document.getElementById(target);
97
+ if (!qrDiv) {
98
+ throw new Error(`Target element with ID '${target}' not found`);
99
+ }
100
+ } else {
101
+ // Modal mode: create modal DOM
102
+ modal = this.buildModal();
103
+ }
104
+
105
+ if (!isTargetMode) {
106
+ // Show modal immediately with spinner
107
+ document.body.appendChild(modal);
108
+
109
+ // Initialize QR div with spinner
110
+ qrDiv = modal.querySelector('#polyguard-qr');
111
+ }
93
112
 
94
- // Initialize QR div with spinner
95
- const qrDiv = modal.querySelector('#polyguard-qr');
96
113
  if (qrDiv) {
97
114
  qrDiv.innerHTML = LOADING_SPINNER;
98
115
  }
99
116
 
100
- // Helper to cleanup modal
117
+ // Helper to cleanup modal or target
101
118
  function cleanup() {
102
- if (modal.parentNode) modal.parentNode.removeChild(modal);
119
+ if (isTargetMode) {
120
+ // Clear target element content
121
+ if (qrDiv) {
122
+ qrDiv.innerHTML = '';
123
+ }
124
+ } else if (modal && modal.parentNode) {
125
+ modal.parentNode.removeChild(modal);
126
+ }
103
127
  }
104
128
  // Promise for JWT
105
129
  return new Promise(async (resolve, reject) => {
@@ -107,19 +131,28 @@ export class PolyguardWebsocketClientImpl {
107
131
  let closed = false;
108
132
 
109
133
  function returnError(msg, score = "OFFLINE") {
110
- const errDiv = modal.querySelector('#polyguard-error');
111
- if (errDiv) {
112
- errDiv.textContent = msg;
113
- errDiv.style.display = 'block';
114
- }
115
- setTimeout(() => {
134
+ if (isTargetMode) {
135
+ // In target mode, just log the error and resolve with error data
136
+ console.error('Polyguard Error:', msg);
116
137
  cleanup();
117
138
  resolve({presence: { score: score, msg: msg }});
118
- }, 1250);
139
+ } else {
140
+ const errDiv = modal.querySelector('#polyguard-error');
141
+ if (errDiv) {
142
+ errDiv.textContent = msg;
143
+ errDiv.style.display = 'block';
144
+ }
145
+ setTimeout(() => {
146
+ cleanup();
147
+ resolve({presence: { score: score, msg: msg }});
148
+ }, 1250);
149
+ }
119
150
  }
120
151
  function clearError() {
121
- const errDiv = modal.querySelector('#polyguard-error');
122
- if (errDiv) errDiv.style.display = 'none';
152
+ if (!isTargetMode) {
153
+ const errDiv = modal.querySelector('#polyguard-error');
154
+ if (errDiv) errDiv.style.display = 'none';
155
+ }
123
156
  }
124
157
  // Close/cancel handler
125
158
  function handleClose() {
@@ -129,15 +162,20 @@ export class PolyguardWebsocketClientImpl {
129
162
  reject(new Error('User cancelled'));
130
163
  }
131
164
 
132
- // Set up close/cancel handlers
133
- modal.querySelector('#polyguard-modal-close').onclick = handleClose;
134
- modal.querySelector('#polyguard-modal-cancel').onclick = handleClose;
165
+ // Set up close/cancel handlers (only in modal mode)
166
+ if (!isTargetMode) {
167
+ modal.querySelector('#polyguard-modal-close').onclick = handleClose;
168
+ modal.querySelector('#polyguard-modal-cancel').onclick = handleClose;
169
+ }
135
170
 
136
171
  // Start ticket/ws flow
137
172
  try {
138
173
  clearError();
139
174
  const wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
140
- const ticketRes = await fetch(`https://${this.apiServer}/v2/ticket/${this.appId}`, {
175
+ const ticketUrl = this.link_uuid
176
+ ? `https://${this.apiServer}/v2/ticket/${this.appId}/${this.link_uuid}`
177
+ : `https://${this.apiServer}/v2/ticket/${this.appId}`;
178
+ const ticketRes = await fetch(ticketUrl, {
141
179
  method: 'POST',
142
180
  headers: { 'Content-Type': 'application/json' },
143
181
  body: JSON.stringify({ requiredProofs: this.requiredProofs, scanType: this.scanType }),
@@ -182,7 +220,6 @@ export class PolyguardWebsocketClientImpl {
182
220
  ws.send(JSON.stringify({ type: 'pong', seq: pcre[1] }));
183
221
  }
184
222
 
185
- const qrDiv = modal.querySelector('#polyguard-qr');
186
223
  if (!qrDiv) return;
187
224
 
188
225
  const isMobile = /Mobi|Android/i.test(navigator.userAgent);
@@ -193,14 +230,16 @@ export class PolyguardWebsocketClientImpl {
193
230
  qrDiv.style.background = 'transparent';
194
231
  qrDiv.querySelector('#polyguard-open-app-button').onclick = () => window.location.assign(data.qr_url);
195
232
 
196
- // Update surrounding text
197
- const instructionText = qrDiv.nextElementSibling;
198
- if (instructionText) {
199
- instructionText.textContent = 'Tap the button to verify with the Polyguard app.';
200
- }
201
- const instructionList = instructionText.nextElementSibling;
202
- if (instructionList && instructionList.children[1]) {
203
- instructionList.children[1].textContent = 'If you do not have the Polyguard app, you will be redirected to download it.';
233
+ // Update surrounding text only in modal mode
234
+ if (!isTargetMode) {
235
+ const instructionText = qrDiv.nextElementSibling;
236
+ if (instructionText) {
237
+ instructionText.textContent = 'Tap the button to verify with the Polyguard app.';
238
+ }
239
+ const instructionList = instructionText.nextElementSibling;
240
+ if (instructionList && instructionList.children[1]) {
241
+ instructionList.children[1].textContent = 'If you do not have the Polyguard app, you will be redirected to download it.';
242
+ }
204
243
  }
205
244
  } else {
206
245
  const startTime = Date.now();
@@ -215,12 +254,11 @@ export class PolyguardWebsocketClientImpl {
215
254
  } else if (data && data.jwt) {
216
255
  cleanup();
217
256
  ws.close();
218
- resolve(data.jwt);
257
+ resolve(rawJwt ? data : data.jwt);
219
258
  return;
220
259
  } else if (data && data.status) {
221
260
  // ignore
222
261
  // generate a spinner in svg and set the qr code to it
223
- const qrDiv = modal.querySelector('#polyguard-qr');
224
262
  if (!qrDiv) return;
225
263
  qrDiv.innerHTML = LOADING_SPINNER;
226
264
  return;
@@ -257,11 +295,12 @@ export class PolyguardWebsocketClientImpl {
257
295
  /**
258
296
  * Wrapper around verify that checks received proof values against expected values.
259
297
  * @param {Object} expectedProofs - An object mapping proof names to expected values.
298
+ * @param {string} target - Optional ID of target element to render QR code in.
260
299
  * @returns {Promise<boolean>} - Resolves to true if all expected proofs match, false otherwise or if cancelled.
261
300
  */
262
- async require(expectedProofs = {}) {
301
+ async require(expectedProofs = {}, target = null) {
263
302
  try {
264
- const jwt = await this.verify();
303
+ const jwt = await this.verify(target);
265
304
  if (!jwt) return false;
266
305
  // Decode JWT (without verifying signature)
267
306
  const payload = JSON.parse(atob(jwt.split('.')[1]));