@polyguard/sdk 1.1.3 → 1.2.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polyguard/sdk",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
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]));
@@ -203,22 +203,6 @@ class ApiClient {
203
203
  * @returns {Boolean} <code>true</code> if <code>param</code> represents a file.
204
204
  */
205
205
  isFileParam(param) {
206
- // fs.ReadStream in Node.js and Electron (but not in runtime like browserify)
207
- if (typeof require === 'function') {
208
- let fs;
209
- try {
210
- fs = require('fs');
211
- } catch (err) {}
212
- if (fs && fs.ReadStream && param instanceof fs.ReadStream) {
213
- return true;
214
- }
215
- }
216
-
217
- // Buffer in Node.js
218
- if (typeof Buffer === 'function' && param instanceof Buffer) {
219
- return true;
220
- }
221
-
222
206
  // Blob in browser
223
207
  if (typeof Blob === 'function' && param instanceof Blob) {
224
208
  return true;
package/src/index.js CHANGED
@@ -9,12 +9,4 @@ if (typeof window !== 'undefined') {
9
9
  }
10
10
 
11
11
  export { PolyguardClient };
12
- export * from './generated/src/index.js';
13
-
14
- // Add this for CommonJS compatibility
15
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
16
- module.exports = {
17
- PolyguardClient,
18
- ...PolyguardApi
19
- };
20
- }
12
+ export * from './generated/src/index.js';