@glideidentity/web-client-sdk 5.0.1-beta.0 → 5.1.1-beta.1

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.
Files changed (97) hide show
  1. package/README.md +8 -108
  2. package/dist/adapters/angular/index.js +1 -0
  3. package/dist/adapters/angular/phone-auth.service.d.ts +18 -0
  4. package/dist/adapters/angular/phone-auth.service.js +26 -0
  5. package/dist/adapters/react/index.js +3 -0
  6. package/dist/adapters/react/useClient.js +1 -0
  7. package/dist/adapters/react/usePhoneAuth.js +16 -1
  8. package/dist/adapters/vanilla/client.js +1 -0
  9. package/dist/adapters/vanilla/index.js +1 -0
  10. package/dist/adapters/vanilla/phone-auth.js +31 -0
  11. package/dist/adapters/vue/index.js +4 -0
  12. package/dist/adapters/vue/useClient.js +5 -0
  13. package/dist/adapters/vue/usePhoneAuth.js +20 -1
  14. package/dist/browser/web-client-sdk.min.js +1 -2
  15. package/dist/browser.js +6 -0
  16. package/dist/core/client.js +12 -0
  17. package/dist/core/logger.js +81 -1
  18. package/dist/core/phone-auth/api-types.d.ts +1 -4
  19. package/dist/core/phone-auth/api-types.js +83 -0
  20. package/dist/core/phone-auth/client.js +374 -38
  21. package/dist/core/phone-auth/error-utils.js +83 -1
  22. package/dist/core/phone-auth/index.d.ts +1 -1
  23. package/dist/core/phone-auth/index.js +2 -2
  24. package/dist/core/phone-auth/status-types.d.ts +78 -0
  25. package/dist/core/phone-auth/status-types.js +17 -0
  26. package/dist/core/phone-auth/strategies/desktop.d.ts +2 -0
  27. package/dist/core/phone-auth/strategies/desktop.js +136 -13
  28. package/dist/core/phone-auth/strategies/index.d.ts +4 -0
  29. package/dist/core/phone-auth/strategies/index.js +4 -0
  30. package/dist/core/phone-auth/strategies/link.d.ts +2 -0
  31. package/dist/core/phone-auth/strategies/link.js +97 -13
  32. package/dist/core/phone-auth/strategies/ts43.d.ts +19 -0
  33. package/dist/core/phone-auth/strategies/ts43.js +33 -2
  34. package/dist/core/phone-auth/strategies/types.js +4 -0
  35. package/dist/core/phone-auth/type-guards.js +131 -0
  36. package/dist/core/phone-auth/types.d.ts +5 -0
  37. package/dist/core/phone-auth/types.js +32 -0
  38. package/dist/core/phone-auth/ui/mobile-debug-console.js +28 -2
  39. package/dist/core/phone-auth/ui/modal.d.ts +55 -33
  40. package/dist/core/phone-auth/ui/modal.js +422 -889
  41. package/dist/core/phone-auth/validation-utils.d.ts +0 -9
  42. package/dist/core/phone-auth/validation-utils.js +34 -25
  43. package/dist/core/version.js +2 -1
  44. package/dist/esm/adapters/angular/index.js +1 -0
  45. package/dist/esm/adapters/angular/phone-auth.service.d.ts +18 -0
  46. package/dist/esm/adapters/angular/phone-auth.service.js +26 -0
  47. package/dist/esm/adapters/react/index.js +3 -0
  48. package/dist/esm/adapters/react/useClient.js +1 -0
  49. package/dist/esm/adapters/react/usePhoneAuth.js +16 -1
  50. package/dist/esm/adapters/vanilla/client.js +1 -0
  51. package/dist/esm/adapters/vanilla/index.js +1 -0
  52. package/dist/esm/adapters/vanilla/phone-auth.d.ts +24 -0
  53. package/dist/esm/adapters/vanilla/phone-auth.js +31 -0
  54. package/dist/esm/adapters/vue/index.js +4 -0
  55. package/dist/esm/adapters/vue/useClient.js +5 -0
  56. package/dist/esm/adapters/vue/usePhoneAuth.js +20 -1
  57. package/dist/esm/browser.js +6 -0
  58. package/dist/esm/core/client.d.ts +10 -0
  59. package/dist/esm/core/client.js +12 -0
  60. package/dist/esm/core/logger.d.ts +53 -0
  61. package/dist/esm/core/logger.js +81 -1
  62. package/dist/esm/core/phone-auth/api-types.d.ts +313 -1
  63. package/dist/esm/core/phone-auth/api-types.js +83 -0
  64. package/dist/esm/core/phone-auth/client.d.ts +144 -0
  65. package/dist/esm/core/phone-auth/client.js +375 -39
  66. package/dist/esm/core/phone-auth/error-utils.d.ts +29 -0
  67. package/dist/esm/core/phone-auth/error-utils.js +83 -1
  68. package/dist/esm/core/phone-auth/index.d.ts +1 -1
  69. package/dist/esm/core/phone-auth/index.js +4 -2
  70. package/dist/esm/core/phone-auth/status-types.d.ts +78 -0
  71. package/dist/esm/core/phone-auth/status-types.js +17 -0
  72. package/dist/esm/core/phone-auth/strategies/desktop.d.ts +65 -0
  73. package/dist/esm/core/phone-auth/strategies/desktop.js +136 -13
  74. package/dist/esm/core/phone-auth/strategies/index.d.ts +4 -0
  75. package/dist/esm/core/phone-auth/strategies/index.js +4 -0
  76. package/dist/esm/core/phone-auth/strategies/link.d.ts +50 -0
  77. package/dist/esm/core/phone-auth/strategies/link.js +97 -13
  78. package/dist/esm/core/phone-auth/strategies/ts43.d.ts +19 -0
  79. package/dist/esm/core/phone-auth/strategies/ts43.js +33 -2
  80. package/dist/esm/core/phone-auth/strategies/types.d.ts +13 -0
  81. package/dist/esm/core/phone-auth/strategies/types.js +4 -0
  82. package/dist/esm/core/phone-auth/type-guards.d.ts +128 -0
  83. package/dist/esm/core/phone-auth/type-guards.js +131 -0
  84. package/dist/esm/core/phone-auth/types.d.ts +113 -0
  85. package/dist/esm/core/phone-auth/types.js +32 -0
  86. package/dist/esm/core/phone-auth/ui/mobile-debug-console.d.ts +4 -0
  87. package/dist/esm/core/phone-auth/ui/mobile-debug-console.js +28 -2
  88. package/dist/esm/core/phone-auth/ui/modal.d.ts +68 -27
  89. package/dist/esm/core/phone-auth/ui/modal.js +422 -889
  90. package/dist/esm/core/phone-auth/validation-utils.d.ts +26 -4
  91. package/dist/esm/core/phone-auth/validation-utils.js +34 -24
  92. package/dist/esm/core/types.d.ts +35 -0
  93. package/dist/esm/core/version.js +2 -1
  94. package/dist/esm/index.js +9 -1
  95. package/dist/index.js +7 -0
  96. package/package.json +1 -1
  97. package/dist/browser/web-client-sdk.min.js.LICENSE.txt +0 -1
@@ -1,4 +1,9 @@
1
1
  "use strict";
2
+ /**
3
+ * Desktop Strategy Handler
4
+ * Handles QR code-based authentication for desktop browsers
5
+ * Manages QR code display and polling for authentication status
6
+ */
2
7
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
8
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
9
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -18,33 +23,49 @@ class DesktopHandler {
18
23
  this.isCancelled = false;
19
24
  this.isPollingInProgress = false;
20
25
  }
26
+ /**
27
+ * Maps backend HTTP status codes to client status
28
+ * @param httpStatus HTTP status code from backend
29
+ * @param bodyStatus Optional status from response body (for 200 OK responses)
30
+ * @returns Mapped status string for client use
31
+ */
21
32
  mapBackendStatus(httpStatus, bodyStatus) {
22
33
  switch (httpStatus) {
23
34
  case 200:
35
+ // For 200 OK, check the body status
24
36
  return bodyStatus === 'completed' ? 'authenticated' : 'pending';
25
37
  case 410:
26
38
  return 'expired';
27
39
  case 422:
28
- return 'error';
40
+ return 'error'; // Failed or cancelled
29
41
  case 404:
30
- return 'error';
42
+ return 'error'; // Session not found
31
43
  case 400:
32
- return 'error';
44
+ return 'error'; // Invalid session key
33
45
  default:
34
46
  return 'error';
35
47
  }
36
48
  }
49
+ /**
50
+ * Invoke desktop authentication with QR code
51
+ * Returns QR code data for display and starts polling if endpoint is provided
52
+ */
37
53
  invoke(data, options) {
38
54
  return __awaiter(this, void 0, void 0, function* () {
39
55
  const desktopData = data.data;
56
+ // Extract QR code from nested or flat structure, checking multiple field names
40
57
  let qrCode;
41
58
  let sessionId;
42
59
  let pollingEndpoint;
43
60
  let pollingInterval;
44
61
  let expiresIn;
62
+ // Check nested structure first (data.data.qr_code_image or data.data.qr_code)
45
63
  if (desktopData && desktopData.data && typeof desktopData.data === 'object') {
46
64
  const innerData = desktopData.data;
65
+ // Try to extract from inner data
66
+ // Support both single QR (qr_code_image) and dual-platform QR (ios/android)
47
67
  if (innerData.ios_qr_image && innerData.android_qr_image) {
68
+ // Dual-platform QR format - both must be present
48
69
  qrCode = {
49
70
  iosQRCode: innerData.ios_qr_image,
50
71
  androidQRCode: innerData.android_qr_image,
@@ -53,9 +74,11 @@ class DesktopHandler {
53
74
  };
54
75
  }
55
76
  else if (innerData.ios_qr_image || innerData.android_qr_image) {
77
+ // Only one platform QR - use as single QR format
56
78
  qrCode = innerData.ios_qr_image || innerData.android_qr_image;
57
79
  }
58
80
  else {
81
+ // Single QR format (legacy)
59
82
  qrCode = innerData.qr_code_image || innerData.qr_code;
60
83
  }
61
84
  sessionId = innerData.session_id;
@@ -63,6 +86,7 @@ class DesktopHandler {
63
86
  pollingInterval = innerData.polling_interval;
64
87
  expiresIn = innerData.expires_in;
65
88
  }
89
+ // Fall back to flat structure if no QR code found
66
90
  if (!qrCode && desktopData) {
67
91
  qrCode = desktopData.qr_code_image || desktopData.qr_code;
68
92
  sessionId = sessionId || desktopData.session_id;
@@ -70,47 +94,65 @@ class DesktopHandler {
70
94
  pollingInterval = pollingInterval || desktopData.polling_interval;
71
95
  expiresIn = expiresIn || desktopData.expires_in;
72
96
  }
97
+ // Validate QR code exists
73
98
  if (!qrCode) {
74
99
  throw new Error('Invalid desktop authentication data: missing QR code');
75
100
  }
101
+ // Validate session ID exists
76
102
  if (!sessionId) {
77
103
  throw new Error('Invalid desktop authentication data: missing session ID');
78
104
  }
105
+ // Notify that QR code is ready
79
106
  if (options === null || options === void 0 ? void 0 : options.onQRCodeReady) {
80
107
  options.onQRCodeReady(qrCode);
81
108
  }
109
+ // Use polling endpoint with this priority:
110
+ // 1. Developer-provided endpoint from options (highest priority)
111
+ // 2. Backend-provided endpoint
112
+ // 3. Hardcoded fallback
82
113
  console.log('[Desktop QR] Polling endpoint selection:');
83
114
  console.log(' - options?.pollingEndpoint:', options === null || options === void 0 ? void 0 : options.pollingEndpoint);
84
115
  console.log(' - backend pollingEndpoint:', pollingEndpoint);
85
116
  let finalPollingEndpoint = options === null || options === void 0 ? void 0 : options.pollingEndpoint;
86
117
  let endpointSource = 'options';
87
118
  if (!finalPollingEndpoint) {
88
- finalPollingEndpoint = pollingEndpoint;
119
+ finalPollingEndpoint = pollingEndpoint; // Backend-provided status_url
89
120
  endpointSource = 'backend';
90
121
  }
91
122
  if (!finalPollingEndpoint) {
123
+ // Use hardcoded fallback - this will be constructed in the polling function
92
124
  console.log('[Desktop QR] No polling endpoint provided, will use hardcoded fallback');
93
125
  endpointSource = 'fallback';
94
126
  }
95
127
  console.log('[Desktop QR] Selected endpoint:', finalPollingEndpoint, 'from source:', endpointSource);
128
+ // Start polling for authentication status
96
129
  const finalPollingInterval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || pollingInterval || 2000;
97
- const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 30;
130
+ const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 30; // Default to 1 minute
98
131
  console.log(`[Desktop QR] Starting polling - endpoint source: ${endpointSource}, interval: ${finalPollingInterval}ms, max attempts: ${maxAttempts}`);
99
- return this.startPolling(finalPollingEndpoint || '', sessionId, finalPollingInterval, maxAttempts, expiresIn || 300, options, endpointSource);
132
+ return this.startPolling(finalPollingEndpoint || '', // Pass empty string if undefined, will use fallback
133
+ sessionId, finalPollingInterval, maxAttempts, expiresIn || 300, // Default 5 minutes expiry
134
+ options, endpointSource // Pass the endpoint source for logging
135
+ );
100
136
  });
101
137
  }
138
+ /**
139
+ * Start polling for authentication status
140
+ */
102
141
  startPolling(endpoint_1, sessionId_1, interval_1, maxAttempts_1, expiresIn_1, options_1) {
103
142
  return __awaiter(this, arguments, void 0, function* (endpoint, sessionId, interval, maxAttempts, expiresIn, options, endpointSource = 'unknown') {
104
143
  const startTime = Date.now();
105
144
  const expiryTime = startTime + (expiresIn * 1000);
106
145
  return new Promise((resolve, reject) => {
146
+ // Store the reject function so we can call it from cancel()
107
147
  this.pollingReject = reject;
108
148
  const poll = () => __awaiter(this, void 0, void 0, function* () {
149
+ // Skip if another poll is already in progress
109
150
  if (this.isPollingInProgress) {
110
151
  return;
111
152
  }
112
153
  try {
113
154
  this.isPollingInProgress = true;
155
+ // Check if cancelled
114
156
  if (this.isCancelled) {
115
157
  this.stopPolling();
116
158
  if (options === null || options === void 0 ? void 0 : options.onCancel) {
@@ -122,12 +164,14 @@ class DesktopHandler {
122
164
  message: 'Authentication cancelled'
123
165
  });
124
166
  }
167
+ // Reject the promise with a cancellation error
125
168
  reject({
126
169
  code: 'USER_DENIED',
127
170
  message: 'Authentication cancelled by user'
128
171
  });
129
172
  return;
130
173
  }
174
+ // Check if expired
131
175
  if (Date.now() > expiryTime) {
132
176
  this.stopPolling();
133
177
  if (options === null || options === void 0 ? void 0 : options.onExpired) {
@@ -145,6 +189,7 @@ class DesktopHandler {
145
189
  });
146
190
  return;
147
191
  }
192
+ // Check max attempts
148
193
  if (this.pollingAttempts >= maxAttempts) {
149
194
  this.stopPolling();
150
195
  if (options === null || options === void 0 ? void 0 : options.onTimeout) {
@@ -162,35 +207,58 @@ class DesktopHandler {
162
207
  });
163
208
  return;
164
209
  }
210
+ // Build public status endpoint URL - use relative path for proxied requests
165
211
  let statusUrl;
212
+ // Extract base URL and construct public endpoint
166
213
  if (endpoint && (endpoint.startsWith('http://') || endpoint.startsWith('https://'))) {
167
- const url = new URL(endpoint);
168
- statusUrl = `${url.protocol}//${url.host}/public/public/status/${sessionId}`;
214
+ // Full URL provided - use as is
215
+ statusUrl = endpoint;
169
216
  }
170
217
  else if (endpoint && endpoint !== '') {
218
+ // Relative path provided (e.g. '/api/phone-auth/status')
219
+ // Append session ID to the provided endpoint
171
220
  statusUrl = `${endpoint}/${sessionId}`;
172
221
  }
173
222
  else {
223
+ // No endpoint provided - use hardcoded fallback
224
+ // This ensures it goes through the same domain and uses the app's API configuration
174
225
  statusUrl = `/api/phone-auth/status/${sessionId}`;
175
226
  }
227
+ // Poll the public endpoint - no authentication required
176
228
  console.log(`[Desktop QR] Polling status (attempt ${this.pollingAttempts}/${maxAttempts})`);
177
229
  console.log(`[Desktop QR] Using ${endpointSource} endpoint: ${statusUrl}`);
230
+ // Build headers
231
+ const headers = {
232
+ 'Accept': 'application/json'
233
+ };
234
+ // Add developer header if devEnv is set
235
+ if (options === null || options === void 0 ? void 0 : options.devEnv) {
236
+ headers['developer'] = options.devEnv;
237
+ console.log(`[Desktop QR] Adding developer header: ${options.devEnv}`);
238
+ }
178
239
  const response = yield fetch(statusUrl, {
179
240
  method: 'GET',
180
- headers: {
181
- 'Accept': 'application/json'
182
- }
241
+ headers
183
242
  });
184
243
  console.log(`[Desktop QR] Status response: ${response.status} ${response.statusText}`);
244
+ // Backend Status Code Mapping:
245
+ // - 200 OK: Session exists (body has 'pending' or 'completed' status)
246
+ // - 410 Gone: Session expired after timeout
247
+ // - 422 Unprocessable Entity: Authentication failed or cancelled
248
+ // - 404 Not Found: Session doesn't exist
249
+ // - 400 Bad Request: Invalid session key format
250
+ // Handle response based on HTTP status code
185
251
  if (response.status === 200) {
186
252
  const result = yield response.json();
187
253
  if (result.status === 'completed') {
254
+ // Authentication completed successfully
188
255
  this.stopPolling();
256
+ // Close the modal if it exists
189
257
  const modal = document.querySelector('[style*="position: fixed"]');
190
258
  if (modal && modal.querySelector('#desktop-auth-status')) {
191
259
  setTimeout(() => {
192
260
  modal.remove();
193
- }, 500);
261
+ }, 500); // Brief delay to show success message
194
262
  }
195
263
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
196
264
  options.onStatusUpdate({
@@ -199,7 +267,8 @@ class DesktopHandler {
199
267
  data: result
200
268
  });
201
269
  }
202
- this.pollingReject = undefined;
270
+ // Return the session data for next steps
271
+ this.pollingReject = undefined; // Clear the reject function on success
203
272
  resolve({
204
273
  authenticated: true,
205
274
  credential: result.credential || result.session_key || sessionId,
@@ -213,6 +282,7 @@ class DesktopHandler {
213
282
  });
214
283
  }
215
284
  else if (result.status === 'pending') {
285
+ // Continue polling
216
286
  this.pollingAttempts++;
217
287
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
218
288
  options.onStatusUpdate({
@@ -223,8 +293,10 @@ class DesktopHandler {
223
293
  }
224
294
  }
225
295
  else if (response.status === 410) {
296
+ // Session expired
226
297
  this.stopPolling();
227
298
  const errorData = yield response.json().catch(() => ({ message: 'Session expired' }));
299
+ // Close the modal on error
228
300
  const modal = document.querySelector('[style*="position: fixed"]');
229
301
  if (modal && modal.querySelector('#desktop-auth-status')) {
230
302
  setTimeout(() => {
@@ -246,8 +318,10 @@ class DesktopHandler {
246
318
  });
247
319
  }
248
320
  else if (response.status === 422) {
321
+ // Authentication failed
249
322
  this.stopPolling();
250
323
  const errorData = yield response.json().catch(() => ({ message: 'Authentication failed' }));
324
+ // Close the modal on error
251
325
  const modal = document.querySelector('[style*="position: fixed"]');
252
326
  if (modal && modal.querySelector('#desktop-auth-status')) {
253
327
  setTimeout(() => {
@@ -269,6 +343,7 @@ class DesktopHandler {
269
343
  });
270
344
  }
271
345
  else if (response.status === 404) {
346
+ // Session not found
272
347
  this.stopPolling();
273
348
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
274
349
  options.onStatusUpdate({
@@ -282,6 +357,7 @@ class DesktopHandler {
282
357
  });
283
358
  }
284
359
  else if (response.status === 400) {
360
+ // Invalid session key
285
361
  this.stopPolling();
286
362
  const errorData = yield response.json().catch(() => ({ message: 'Invalid session key' }));
287
363
  resolve({
@@ -290,10 +366,12 @@ class DesktopHandler {
290
366
  });
291
367
  }
292
368
  else {
369
+ // Unexpected status - continue polling
293
370
  this.pollingAttempts++;
294
371
  }
295
372
  }
296
373
  catch (error) {
374
+ // Network or other error - continue polling
297
375
  this.pollingAttempts++;
298
376
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
299
377
  options.onStatusUpdate({
@@ -303,14 +381,20 @@ class DesktopHandler {
303
381
  }
304
382
  }
305
383
  finally {
384
+ // Always clear the polling flag when done
306
385
  this.isPollingInProgress = false;
307
386
  }
308
387
  });
388
+ // Start initial poll
309
389
  poll();
390
+ // Set up interval for subsequent polls
310
391
  this.pollingIntervalId = setInterval(poll, interval);
311
392
  });
312
393
  });
313
394
  }
395
+ /**
396
+ * Stop polling
397
+ */
314
398
  stopPolling() {
315
399
  if (this.pollingIntervalId) {
316
400
  console.log('[Desktop QR] Stopping polling');
@@ -319,10 +403,18 @@ class DesktopHandler {
319
403
  }
320
404
  this.pollingAttempts = 0;
321
405
  this.isPollingInProgress = false;
406
+ // Don't clear pollingReject here - it's needed by cancel()
322
407
  }
408
+ /**
409
+ * Check if polling is currently active
410
+ */
323
411
  isPolling() {
324
412
  return this.pollingIntervalId !== undefined;
325
413
  }
414
+ /**
415
+ * Format response for backend processing
416
+ * Desktop strategy typically returns the credential from mobile authentication
417
+ */
326
418
  formatResponse(response) {
327
419
  if (!response.authenticated || !response.credential) {
328
420
  throw new Error('Authentication not completed');
@@ -332,23 +424,35 @@ class DesktopHandler {
332
424
  session: response.session
333
425
  };
334
426
  }
427
+ /**
428
+ * Check if desktop authentication is supported
429
+ * Desktop auth with QR codes works in any modern browser
430
+ */
335
431
  isSupported() {
432
+ // Check for required browser APIs
336
433
  return typeof window !== 'undefined' &&
337
434
  typeof fetch !== 'undefined' &&
338
435
  typeof Promise !== 'undefined';
339
436
  }
437
+ /**
438
+ * Clean up resources (stop polling if active)
439
+ */
340
440
  cleanup() {
341
441
  this.stopPolling();
342
442
  this.isCancelled = false;
343
443
  this.onCancel = undefined;
344
444
  this.pollingReject = undefined;
345
445
  }
446
+ /**
447
+ * Cancel the ongoing authentication
448
+ */
346
449
  cancel() {
347
450
  var _a;
348
451
  console.log('[Desktop QR] Cancelling authentication');
349
452
  this.isCancelled = true;
350
453
  this.stopPolling();
351
454
  (_a = this.onCancel) === null || _a === void 0 ? void 0 : _a.call(this);
455
+ // Immediately reject the polling promise
352
456
  if (this.pollingReject) {
353
457
  this.pollingReject({
354
458
  code: 'USER_DENIED',
@@ -359,14 +463,20 @@ class DesktopHandler {
359
463
  }
360
464
  }
361
465
  exports.DesktopHandler = DesktopHandler;
466
+ /**
467
+ * Helper function to display QR code in a modal or inline
468
+ */
362
469
  function createQRCodeDisplay(qrCodeData, options) {
363
470
  const container = (options === null || options === void 0 ? void 0 : options.container) || document.createElement('div');
364
471
  container.className = 'phone-auth-qr-container';
472
+ // Determine QR code to display
365
473
  let qrCodeSrc;
366
474
  if (typeof qrCodeData === 'string') {
475
+ // Simple string QR code
367
476
  qrCodeSrc = qrCodeData;
368
477
  }
369
478
  else if (qrCodeData && typeof qrCodeData === 'object') {
479
+ // QRCodeData object - prefer iOS QR if available
370
480
  if (qrCodeData.iosQRCode) {
371
481
  qrCodeSrc = qrCodeData.iosQRCode;
372
482
  }
@@ -380,6 +490,7 @@ function createQRCodeDisplay(qrCodeData, options) {
380
490
  else {
381
491
  throw new Error('Invalid qrCodeData: must be string or QRCodeData object');
382
492
  }
493
+ // Create QR code image
383
494
  const img = document.createElement('img');
384
495
  img.src = qrCodeSrc;
385
496
  img.alt = 'QR Code for authentication';
@@ -387,6 +498,7 @@ function createQRCodeDisplay(qrCodeData, options) {
387
498
  img.style.height = `${(options === null || options === void 0 ? void 0 : options.size) || 256}px`;
388
499
  img.style.display = 'block';
389
500
  img.style.margin = '0 auto';
501
+ // Add title if provided
390
502
  if (options === null || options === void 0 ? void 0 : options.title) {
391
503
  const title = document.createElement('h3');
392
504
  title.textContent = options.title;
@@ -395,6 +507,7 @@ function createQRCodeDisplay(qrCodeData, options) {
395
507
  container.appendChild(title);
396
508
  }
397
509
  container.appendChild(img);
510
+ // Add description if provided
398
511
  if (options === null || options === void 0 ? void 0 : options.description) {
399
512
  const desc = document.createElement('p');
400
513
  desc.textContent = options.description;
@@ -405,7 +518,12 @@ function createQRCodeDisplay(qrCodeData, options) {
405
518
  }
406
519
  return container;
407
520
  }
521
+ /**
522
+ * Helper function to create a modal for QR code display
523
+ * Supports both string QR codes and QRCodeData objects for dual-platform support
524
+ */
408
525
  function showQRCodeModal(qrCodeData, options) {
526
+ // Create modal overlay
409
527
  const overlay = document.createElement('div');
410
528
  overlay.style.cssText = `
411
529
  position: fixed;
@@ -419,6 +537,7 @@ function showQRCodeModal(qrCodeData, options) {
419
537
  justify-content: center;
420
538
  z-index: 9999;
421
539
  `;
540
+ // Create modal content
422
541
  const modal = document.createElement('div');
423
542
  modal.style.cssText = `
424
543
  background: white;
@@ -427,6 +546,7 @@ function showQRCodeModal(qrCodeData, options) {
427
546
  max-width: 400px;
428
547
  position: relative;
429
548
  `;
549
+ // Add close button
430
550
  const closeBtn = document.createElement('button');
431
551
  closeBtn.textContent = '×';
432
552
  closeBtn.style.cssText = `
@@ -446,11 +566,13 @@ function showQRCodeModal(qrCodeData, options) {
446
566
  }
447
567
  };
448
568
  modal.appendChild(closeBtn);
569
+ // Add QR code display
449
570
  const qrDisplay = createQRCodeDisplay(qrCodeData, {
450
571
  title: (options === null || options === void 0 ? void 0 : options.title) || 'Scan QR Code to Authenticate',
451
572
  description: (options === null || options === void 0 ? void 0 : options.description) || 'Use your mobile device to scan this QR code'
452
573
  });
453
574
  modal.appendChild(qrDisplay);
575
+ // Add loading spinner placeholder
454
576
  const statusDiv = document.createElement('div');
455
577
  statusDiv.id = 'desktop-auth-status';
456
578
  statusDiv.style.cssText = `
@@ -462,6 +584,7 @@ function showQRCodeModal(qrCodeData, options) {
462
584
  modal.appendChild(statusDiv);
463
585
  overlay.appendChild(modal);
464
586
  document.body.appendChild(overlay);
587
+ // Close modal on overlay click
465
588
  overlay.onclick = (e) => {
466
589
  if (e.target === overlay) {
467
590
  document.body.removeChild(overlay);
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Strategy Handlers Export
3
+ * Provides implementations for TS43, Link, and Desktop authentication strategies
4
+ */
1
5
  export type { StrategyHandler } from './types';
2
6
  export { TS43Handler } from './ts43';
3
7
  export { LinkHandler } from './link';
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
+ /**
3
+ * Strategy Handlers Export
4
+ * Provides implementations for TS43, Link, and Desktop authentication strategies
5
+ */
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
7
  exports.showQRCodeModal = exports.createQRCodeDisplay = exports.DesktopHandler = exports.LinkHandler = exports.TS43Handler = void 0;
4
8
  var ts43_1 = require("./ts43");
@@ -12,6 +12,8 @@ export interface LinkAuthOptions {
12
12
  maxPollingAttempts?: number;
13
13
  /** Custom polling endpoint (overrides backend-provided or configured endpoint) */
14
14
  pollingEndpoint?: string;
15
+ /** Developer environment (adds 'developer' header to requests) */
16
+ devEnv?: string;
15
17
  /** Callback when link is opened */
16
18
  onLinkOpened?: () => void;
17
19
  /** Callback for polling status updates */