@glideidentity/web-client-sdk 4.4.8-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 (136) hide show
  1. package/README.md +938 -0
  2. package/dist/adapters/angular/client.service.d.ts +7 -0
  3. package/dist/adapters/angular/client.service.js +30 -0
  4. package/dist/adapters/angular/index.d.ts +3 -0
  5. package/dist/adapters/angular/index.js +18 -0
  6. package/dist/adapters/angular/phone-auth.service.d.ts +38 -0
  7. package/dist/adapters/angular/phone-auth.service.js +130 -0
  8. package/dist/adapters/react/index.d.ts +9 -0
  9. package/dist/adapters/react/index.js +28 -0
  10. package/dist/adapters/react/useClient.d.ts +26 -0
  11. package/dist/adapters/react/useClient.js +121 -0
  12. package/dist/adapters/react/usePhoneAuth.d.ts +23 -0
  13. package/dist/adapters/react/usePhoneAuth.js +95 -0
  14. package/dist/adapters/vanilla/client.d.ts +8 -0
  15. package/dist/adapters/vanilla/client.js +33 -0
  16. package/dist/adapters/vanilla/index.d.ts +3 -0
  17. package/dist/adapters/vanilla/index.js +18 -0
  18. package/dist/adapters/vanilla/phone-auth.d.ts +46 -0
  19. package/dist/adapters/vanilla/phone-auth.js +138 -0
  20. package/dist/adapters/vue/index.d.ts +10 -0
  21. package/dist/adapters/vue/index.js +36 -0
  22. package/dist/adapters/vue/useClient.d.ts +115 -0
  23. package/dist/adapters/vue/useClient.js +131 -0
  24. package/dist/adapters/vue/usePhoneAuth.d.ts +94 -0
  25. package/dist/adapters/vue/usePhoneAuth.js +103 -0
  26. package/dist/browser/web-client-sdk.min.js +2 -0
  27. package/dist/browser/web-client-sdk.min.js.LICENSE.txt +1 -0
  28. package/dist/browser.d.ts +7 -0
  29. package/dist/browser.js +31 -0
  30. package/dist/core/client.d.ts +22 -0
  31. package/dist/core/client.js +77 -0
  32. package/dist/core/logger.d.ts +130 -0
  33. package/dist/core/logger.js +370 -0
  34. package/dist/core/phone-auth/api-types.d.ts +525 -0
  35. package/dist/core/phone-auth/api-types.js +215 -0
  36. package/dist/core/phone-auth/client.d.ts +187 -0
  37. package/dist/core/phone-auth/client.js +1353 -0
  38. package/dist/core/phone-auth/error-utils.d.ts +110 -0
  39. package/dist/core/phone-auth/error-utils.js +350 -0
  40. package/dist/core/phone-auth/index.d.ts +7 -0
  41. package/dist/core/phone-auth/index.js +47 -0
  42. package/dist/core/phone-auth/status-types.d.ts +107 -0
  43. package/dist/core/phone-auth/status-types.js +31 -0
  44. package/dist/core/phone-auth/strategies/desktop.d.ts +113 -0
  45. package/dist/core/phone-auth/strategies/desktop.js +502 -0
  46. package/dist/core/phone-auth/strategies/index.d.ts +11 -0
  47. package/dist/core/phone-auth/strategies/index.js +15 -0
  48. package/dist/core/phone-auth/strategies/link.d.ts +81 -0
  49. package/dist/core/phone-auth/strategies/link.js +265 -0
  50. package/dist/core/phone-auth/strategies/ts43.d.ts +32 -0
  51. package/dist/core/phone-auth/strategies/ts43.js +146 -0
  52. package/dist/core/phone-auth/strategies/types.d.ts +18 -0
  53. package/dist/core/phone-auth/strategies/types.js +6 -0
  54. package/dist/core/phone-auth/type-guards.d.ts +125 -0
  55. package/dist/core/phone-auth/type-guards.js +160 -0
  56. package/dist/core/phone-auth/types.d.ts +232 -0
  57. package/dist/core/phone-auth/types.js +93 -0
  58. package/dist/core/phone-auth/ui/mobile-debug-console.d.ts +25 -0
  59. package/dist/core/phone-auth/ui/mobile-debug-console.js +288 -0
  60. package/dist/core/phone-auth/ui/modal.d.ts +84 -0
  61. package/dist/core/phone-auth/ui/modal.js +574 -0
  62. package/dist/core/phone-auth/validation-utils.d.ts +66 -0
  63. package/dist/core/phone-auth/validation-utils.js +182 -0
  64. package/dist/core/types.d.ts +62 -0
  65. package/dist/core/types.js +2 -0
  66. package/dist/core/version.d.ts +1 -0
  67. package/dist/core/version.js +5 -0
  68. package/dist/esm/adapters/angular/client.service.d.ts +7 -0
  69. package/dist/esm/adapters/angular/client.service.js +27 -0
  70. package/dist/esm/adapters/angular/index.d.ts +3 -0
  71. package/dist/esm/adapters/angular/index.js +4 -0
  72. package/dist/esm/adapters/angular/phone-auth.service.d.ts +38 -0
  73. package/dist/esm/adapters/angular/phone-auth.service.js +127 -0
  74. package/dist/esm/adapters/react/index.d.ts +9 -0
  75. package/dist/esm/adapters/react/index.js +8 -0
  76. package/dist/esm/adapters/react/useClient.d.ts +26 -0
  77. package/dist/esm/adapters/react/useClient.js +116 -0
  78. package/dist/esm/adapters/react/usePhoneAuth.d.ts +23 -0
  79. package/dist/esm/adapters/react/usePhoneAuth.js +92 -0
  80. package/dist/esm/adapters/vanilla/client.d.ts +8 -0
  81. package/dist/esm/adapters/vanilla/client.js +29 -0
  82. package/dist/esm/adapters/vanilla/index.d.ts +3 -0
  83. package/dist/esm/adapters/vanilla/index.js +4 -0
  84. package/dist/esm/adapters/vanilla/phone-auth.d.ts +46 -0
  85. package/dist/esm/adapters/vanilla/phone-auth.js +134 -0
  86. package/dist/esm/adapters/vue/index.d.ts +10 -0
  87. package/dist/esm/adapters/vue/index.js +11 -0
  88. package/dist/esm/adapters/vue/useClient.d.ts +115 -0
  89. package/dist/esm/adapters/vue/useClient.js +127 -0
  90. package/dist/esm/adapters/vue/usePhoneAuth.d.ts +94 -0
  91. package/dist/esm/adapters/vue/usePhoneAuth.js +100 -0
  92. package/dist/esm/browser.d.ts +7 -0
  93. package/dist/esm/browser.js +11 -0
  94. package/dist/esm/core/client.d.ts +22 -0
  95. package/dist/esm/core/client.js +70 -0
  96. package/dist/esm/core/logger.d.ts +130 -0
  97. package/dist/esm/core/logger.js +359 -0
  98. package/dist/esm/core/phone-auth/api-types.d.ts +525 -0
  99. package/dist/esm/core/phone-auth/api-types.js +203 -0
  100. package/dist/esm/core/phone-auth/client.d.ts +187 -0
  101. package/dist/esm/core/phone-auth/client.js +1316 -0
  102. package/dist/esm/core/phone-auth/error-utils.d.ts +110 -0
  103. package/dist/esm/core/phone-auth/error-utils.js +338 -0
  104. package/dist/esm/core/phone-auth/index.d.ts +7 -0
  105. package/dist/esm/core/phone-auth/index.js +6 -0
  106. package/dist/esm/core/phone-auth/status-types.d.ts +107 -0
  107. package/dist/esm/core/phone-auth/status-types.js +26 -0
  108. package/dist/esm/core/phone-auth/strategies/desktop.d.ts +113 -0
  109. package/dist/esm/core/phone-auth/strategies/desktop.js +496 -0
  110. package/dist/esm/core/phone-auth/strategies/index.d.ts +11 -0
  111. package/dist/esm/core/phone-auth/strategies/index.js +7 -0
  112. package/dist/esm/core/phone-auth/strategies/link.d.ts +81 -0
  113. package/dist/esm/core/phone-auth/strategies/link.js +261 -0
  114. package/dist/esm/core/phone-auth/strategies/ts43.d.ts +32 -0
  115. package/dist/esm/core/phone-auth/strategies/ts43.js +142 -0
  116. package/dist/esm/core/phone-auth/strategies/types.d.ts +18 -0
  117. package/dist/esm/core/phone-auth/strategies/types.js +5 -0
  118. package/dist/esm/core/phone-auth/type-guards.d.ts +125 -0
  119. package/dist/esm/core/phone-auth/type-guards.js +150 -0
  120. package/dist/esm/core/phone-auth/types.d.ts +232 -0
  121. package/dist/esm/core/phone-auth/types.js +76 -0
  122. package/dist/esm/core/phone-auth/ui/mobile-debug-console.d.ts +25 -0
  123. package/dist/esm/core/phone-auth/ui/mobile-debug-console.js +284 -0
  124. package/dist/esm/core/phone-auth/ui/modal.d.ts +84 -0
  125. package/dist/esm/core/phone-auth/ui/modal.js +570 -0
  126. package/dist/esm/core/phone-auth/validation-utils.d.ts +66 -0
  127. package/dist/esm/core/phone-auth/validation-utils.js +174 -0
  128. package/dist/esm/core/types.d.ts +62 -0
  129. package/dist/esm/core/types.js +1 -0
  130. package/dist/esm/core/version.d.ts +1 -0
  131. package/dist/esm/core/version.js +2 -0
  132. package/dist/esm/index.d.ts +12 -0
  133. package/dist/esm/index.js +15 -0
  134. package/dist/index.d.ts +12 -0
  135. package/dist/index.js +52 -0
  136. package/package.json +92 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Desktop Strategy Handler
3
+ * Handles QR code-based authentication for desktop browsers
4
+ * Manages QR code display and polling for authentication status
5
+ */
6
+ import type { StrategyHandler } from './types';
7
+ import type { PrepareResponse } from '../types';
8
+ /**
9
+ * QR code data structure for dual-platform support
10
+ */
11
+ export interface QRCodeData {
12
+ iosQRCode: string;
13
+ androidQRCode?: string;
14
+ iosUrl?: string;
15
+ androidUrl?: string;
16
+ }
17
+ export interface DesktopAuthOptions {
18
+ /** Custom polling interval in milliseconds (overrides server-provided value) */
19
+ pollingInterval?: number;
20
+ /** Maximum polling attempts before timeout (default: 150 = 5 minutes with 2s interval) */
21
+ maxPollingAttempts?: number;
22
+ /** Custom polling endpoint (overrides backend-provided or uses configured endpoint) */
23
+ pollingEndpoint?: string;
24
+ /** Callback when QR code is ready to display */
25
+ onQRCodeReady?: (qrCodeData: string | QRCodeData) => void;
26
+ /** Callback for polling status updates */
27
+ onStatusUpdate?: (status: PollingStatus) => void;
28
+ /** Callback when authentication expires */
29
+ onExpired?: () => void;
30
+ /** Callback when authentication is cancelled by user */
31
+ onCancel?: () => void;
32
+ /** Callback when polling times out (max attempts reached) */
33
+ onTimeout?: () => void;
34
+ }
35
+ export interface PollingStatus {
36
+ /** Current status of the authentication */
37
+ status: 'pending' | 'authenticated' | 'expired' | 'cancelled' | 'error';
38
+ /** Optional message */
39
+ message?: string;
40
+ /** Authentication result data if status is 'authenticated' */
41
+ data?: any;
42
+ }
43
+ export interface DesktopAuthResult {
44
+ /** Whether authentication was successful */
45
+ authenticated: boolean;
46
+ /** Authentication credential if successful */
47
+ credential?: string;
48
+ /** Session info for subsequent requests */
49
+ session?: any;
50
+ /** Error message if authentication failed */
51
+ error?: string;
52
+ }
53
+ export declare class DesktopHandler implements StrategyHandler {
54
+ private pollingIntervalId?;
55
+ private pollingAttempts;
56
+ private isCancelled;
57
+ private onCancel?;
58
+ /**
59
+ * Maps backend HTTP status codes to client status
60
+ * @param httpStatus HTTP status code from backend
61
+ * @param bodyStatus Optional status from response body (for 200 OK responses)
62
+ * @returns Mapped status string for client use
63
+ */
64
+ private mapBackendStatus;
65
+ /**
66
+ * Invoke desktop authentication with QR code
67
+ * Returns QR code data for display and starts polling if endpoint is provided
68
+ */
69
+ invoke(data: PrepareResponse, options?: DesktopAuthOptions): Promise<DesktopAuthResult>;
70
+ /**
71
+ * Start polling for authentication status
72
+ */
73
+ private startPolling;
74
+ /**
75
+ * Stop polling
76
+ */
77
+ private stopPolling;
78
+ /**
79
+ * Format response for backend processing
80
+ * Desktop strategy typically returns the credential from mobile authentication
81
+ */
82
+ formatResponse(response: DesktopAuthResult): any;
83
+ /**
84
+ * Check if desktop authentication is supported
85
+ * Desktop auth with QR codes works in any modern browser
86
+ */
87
+ isSupported(): boolean;
88
+ /**
89
+ * Clean up resources (stop polling if active)
90
+ */
91
+ cleanup(): void;
92
+ /**
93
+ * Cancel the ongoing authentication
94
+ */
95
+ cancel(): void;
96
+ }
97
+ /**
98
+ * Helper function to display QR code in a modal or inline
99
+ */
100
+ export declare function createQRCodeDisplay(qrCodeData: string, options?: {
101
+ container?: HTMLElement;
102
+ size?: number;
103
+ title?: string;
104
+ description?: string;
105
+ }): HTMLElement;
106
+ /**
107
+ * Helper function to create a modal for QR code display
108
+ */
109
+ export declare function showQRCodeModal(qrCodeData: string, options?: {
110
+ title?: string;
111
+ description?: string;
112
+ onClose?: () => void;
113
+ }): void;
@@ -0,0 +1,502 @@
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
+ */
7
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
+ return new (P || (P = Promise))(function (resolve, reject) {
10
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
14
+ });
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.DesktopHandler = void 0;
18
+ exports.createQRCodeDisplay = createQRCodeDisplay;
19
+ exports.showQRCodeModal = showQRCodeModal;
20
+ class DesktopHandler {
21
+ constructor() {
22
+ this.pollingAttempts = 0;
23
+ this.isCancelled = false;
24
+ }
25
+ /**
26
+ * Maps backend HTTP status codes to client status
27
+ * @param httpStatus HTTP status code from backend
28
+ * @param bodyStatus Optional status from response body (for 200 OK responses)
29
+ * @returns Mapped status string for client use
30
+ */
31
+ mapBackendStatus(httpStatus, bodyStatus) {
32
+ switch (httpStatus) {
33
+ case 200:
34
+ // For 200 OK, check the body status
35
+ return bodyStatus === 'completed' ? 'authenticated' : 'pending';
36
+ case 410:
37
+ return 'expired';
38
+ case 422:
39
+ return 'error'; // Failed or cancelled
40
+ case 404:
41
+ return 'error'; // Session not found
42
+ case 400:
43
+ return 'error'; // Invalid session key
44
+ default:
45
+ return 'error';
46
+ }
47
+ }
48
+ /**
49
+ * Invoke desktop authentication with QR code
50
+ * Returns QR code data for display and starts polling if endpoint is provided
51
+ */
52
+ invoke(data, options) {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ const desktopData = data.data;
55
+ // Extract QR code from nested or flat structure, checking multiple field names
56
+ let qrCode;
57
+ let sessionId;
58
+ let pollingEndpoint;
59
+ let pollingInterval;
60
+ let expiresIn;
61
+ // Check nested structure first (data.data.qr_code_image or data.data.qr_code)
62
+ if (desktopData && desktopData.data && typeof desktopData.data === 'object') {
63
+ const innerData = desktopData.data;
64
+ // Try to extract from inner data
65
+ qrCode = innerData.qr_code_image || innerData.qr_code;
66
+ sessionId = innerData.session_id;
67
+ pollingEndpoint = innerData.status_url;
68
+ pollingInterval = innerData.polling_interval;
69
+ expiresIn = innerData.expires_in;
70
+ }
71
+ // Fall back to flat structure if no QR code found
72
+ if (!qrCode && desktopData) {
73
+ qrCode = desktopData.qr_code_image || desktopData.qr_code;
74
+ sessionId = sessionId || desktopData.session_id;
75
+ pollingEndpoint = pollingEndpoint || desktopData.status_url || desktopData.polling_endpoint;
76
+ pollingInterval = pollingInterval || desktopData.polling_interval;
77
+ expiresIn = expiresIn || desktopData.expires_in;
78
+ }
79
+ // Validate QR code exists
80
+ if (!qrCode) {
81
+ throw new Error('Invalid desktop authentication data: missing QR code');
82
+ }
83
+ // Validate session ID exists
84
+ if (!sessionId) {
85
+ throw new Error('Invalid desktop authentication data: missing session ID');
86
+ }
87
+ // Notify that QR code is ready
88
+ if (options === null || options === void 0 ? void 0 : options.onQRCodeReady) {
89
+ options.onQRCodeReady(qrCode);
90
+ }
91
+ // Use polling endpoint with this priority:
92
+ // 1. Developer-provided endpoint from options
93
+ // 2. Backend-provided endpoint
94
+ // 3. Error if none available
95
+ const finalPollingEndpoint = (options === null || options === void 0 ? void 0 : options.pollingEndpoint) || pollingEndpoint;
96
+ // If no polling endpoint available, return QR code data and let the app handle the rest
97
+ if (!finalPollingEndpoint) {
98
+ return {
99
+ authenticated: false,
100
+ session: data.session,
101
+ error: 'No polling endpoint provided - configure endpoints.polling or ensure backend provides status_url'
102
+ };
103
+ }
104
+ // Start polling for authentication status
105
+ const finalPollingInterval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || pollingInterval || 2000;
106
+ const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 150; // Default to 5 minutes
107
+ return this.startPolling(finalPollingEndpoint, sessionId, finalPollingInterval, maxAttempts, expiresIn || 300, // Default 5 minutes expiry
108
+ options);
109
+ });
110
+ }
111
+ /**
112
+ * Start polling for authentication status
113
+ */
114
+ startPolling(endpoint, sessionId, interval, maxAttempts, expiresIn, options) {
115
+ return __awaiter(this, void 0, void 0, function* () {
116
+ const startTime = Date.now();
117
+ const expiryTime = startTime + (expiresIn * 1000);
118
+ return new Promise((resolve, reject) => {
119
+ const poll = () => __awaiter(this, void 0, void 0, function* () {
120
+ try {
121
+ // Check if cancelled
122
+ if (this.isCancelled) {
123
+ this.stopPolling();
124
+ if (options === null || options === void 0 ? void 0 : options.onCancel) {
125
+ options.onCancel();
126
+ }
127
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
128
+ options.onStatusUpdate({
129
+ status: 'cancelled',
130
+ message: 'Authentication cancelled'
131
+ });
132
+ }
133
+ resolve({
134
+ authenticated: false,
135
+ error: 'Authentication cancelled'
136
+ });
137
+ return;
138
+ }
139
+ // Check if expired
140
+ if (Date.now() > expiryTime) {
141
+ this.stopPolling();
142
+ if (options === null || options === void 0 ? void 0 : options.onExpired) {
143
+ options.onExpired();
144
+ }
145
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
146
+ options.onStatusUpdate({
147
+ status: 'expired',
148
+ message: 'QR code has expired'
149
+ });
150
+ }
151
+ resolve({
152
+ authenticated: false,
153
+ error: 'Authentication expired'
154
+ });
155
+ return;
156
+ }
157
+ // Check max attempts
158
+ if (this.pollingAttempts >= maxAttempts) {
159
+ this.stopPolling();
160
+ if (options === null || options === void 0 ? void 0 : options.onTimeout) {
161
+ options.onTimeout();
162
+ }
163
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
164
+ options.onStatusUpdate({
165
+ status: 'error',
166
+ message: 'Polling timeout reached'
167
+ });
168
+ }
169
+ resolve({
170
+ authenticated: false,
171
+ error: 'Polling timeout'
172
+ });
173
+ return;
174
+ }
175
+ // Build public status endpoint URL - use relative path for proxied requests
176
+ let statusUrl;
177
+ // Extract base URL and construct public endpoint
178
+ if (endpoint && (endpoint.startsWith('http://') || endpoint.startsWith('https://'))) {
179
+ // Full URL provided - extract base and use public endpoint
180
+ const url = new URL(endpoint);
181
+ statusUrl = `${url.protocol}//${url.host}/public/public/status/${sessionId}`;
182
+ }
183
+ else {
184
+ // Use relative path that will be proxied through the app's server
185
+ // This ensures it goes through the same domain and uses the app's API configuration
186
+ statusUrl = `/api/phone-auth/status/${sessionId}`;
187
+ }
188
+ // Poll the public endpoint - no authentication required
189
+ const response = yield fetch(statusUrl, {
190
+ method: 'GET',
191
+ headers: {
192
+ 'Accept': 'application/json'
193
+ // No Authorization header needed for public endpoint
194
+ }
195
+ });
196
+ // Backend Status Code Mapping:
197
+ // - 200 OK: Session exists (body has 'pending' or 'completed' status)
198
+ // - 410 Gone: Session expired after timeout
199
+ // - 422 Unprocessable Entity: Authentication failed or cancelled
200
+ // - 404 Not Found: Session doesn't exist
201
+ // - 400 Bad Request: Invalid session key format
202
+ // Handle response based on HTTP status code
203
+ if (response.status === 200) {
204
+ const result = yield response.json();
205
+ if (result.status === 'completed') {
206
+ // Authentication completed successfully
207
+ this.stopPolling();
208
+ // Close the modal if it exists
209
+ const modal = document.querySelector('[style*="position: fixed"]');
210
+ if (modal && modal.querySelector('#desktop-auth-status')) {
211
+ setTimeout(() => {
212
+ modal.remove();
213
+ }, 500); // Brief delay to show success message
214
+ }
215
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
216
+ options.onStatusUpdate({
217
+ status: 'authenticated',
218
+ message: 'Authentication successful',
219
+ data: result
220
+ });
221
+ }
222
+ // Return the session data for next steps
223
+ resolve({
224
+ authenticated: true,
225
+ credential: result.credential || result.session_key || sessionId,
226
+ session: result.session || {
227
+ session_key: result.session_key || sessionId,
228
+ status: result.status,
229
+ protocol: result.protocol,
230
+ created_at: result.created_at,
231
+ last_updated: result.last_updated
232
+ }
233
+ });
234
+ }
235
+ else if (result.status === 'pending') {
236
+ // Continue polling
237
+ this.pollingAttempts++;
238
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
239
+ options.onStatusUpdate({
240
+ status: 'pending',
241
+ message: `Waiting for authentication (attempt ${this.pollingAttempts}/${maxAttempts})`
242
+ });
243
+ }
244
+ }
245
+ }
246
+ else if (response.status === 410) {
247
+ // Session expired
248
+ this.stopPolling();
249
+ const errorData = yield response.json().catch(() => ({ message: 'Session expired' }));
250
+ // Close the modal on error
251
+ const modal = document.querySelector('[style*="position: fixed"]');
252
+ if (modal && modal.querySelector('#desktop-auth-status')) {
253
+ setTimeout(() => {
254
+ modal.remove();
255
+ }, 500);
256
+ }
257
+ if (options === null || options === void 0 ? void 0 : options.onExpired) {
258
+ options.onExpired();
259
+ }
260
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
261
+ options.onStatusUpdate({
262
+ status: 'expired',
263
+ message: errorData.message || 'Session has expired'
264
+ });
265
+ }
266
+ resolve({
267
+ authenticated: false,
268
+ error: errorData.message || 'Session expired'
269
+ });
270
+ }
271
+ else if (response.status === 422) {
272
+ // Authentication failed
273
+ this.stopPolling();
274
+ const errorData = yield response.json().catch(() => ({ message: 'Authentication failed' }));
275
+ // Close the modal on error
276
+ const modal = document.querySelector('[style*="position: fixed"]');
277
+ if (modal && modal.querySelector('#desktop-auth-status')) {
278
+ setTimeout(() => {
279
+ modal.remove();
280
+ }, 500);
281
+ }
282
+ const isUserCancelled = errorData.code === 'USER_CANCELLED';
283
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
284
+ options.onStatusUpdate({
285
+ status: 'error',
286
+ message: errorData.message || 'Authentication failed'
287
+ });
288
+ }
289
+ resolve({
290
+ authenticated: false,
291
+ error: isUserCancelled
292
+ ? 'User cancelled authentication'
293
+ : (errorData.message || 'Authentication failed')
294
+ });
295
+ }
296
+ else if (response.status === 404) {
297
+ // Session not found
298
+ this.stopPolling();
299
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
300
+ options.onStatusUpdate({
301
+ status: 'error',
302
+ message: 'Session not found'
303
+ });
304
+ }
305
+ resolve({
306
+ authenticated: false,
307
+ error: 'Session not found'
308
+ });
309
+ }
310
+ else if (response.status === 400) {
311
+ // Invalid session key
312
+ this.stopPolling();
313
+ const errorData = yield response.json().catch(() => ({ message: 'Invalid session key' }));
314
+ resolve({
315
+ authenticated: false,
316
+ error: errorData.message || 'Invalid session key'
317
+ });
318
+ }
319
+ else {
320
+ // Unexpected status - continue polling
321
+ this.pollingAttempts++;
322
+ }
323
+ }
324
+ catch (error) {
325
+ // Network or other error - continue polling
326
+ this.pollingAttempts++;
327
+ if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
328
+ options.onStatusUpdate({
329
+ status: 'pending',
330
+ message: `Network error, retrying... (attempt ${this.pollingAttempts}/${maxAttempts})`
331
+ });
332
+ }
333
+ }
334
+ });
335
+ // Start initial poll
336
+ poll();
337
+ // Set up interval for subsequent polls
338
+ this.pollingIntervalId = setInterval(poll, interval);
339
+ });
340
+ });
341
+ }
342
+ /**
343
+ * Stop polling
344
+ */
345
+ stopPolling() {
346
+ if (this.pollingIntervalId) {
347
+ clearInterval(this.pollingIntervalId);
348
+ this.pollingIntervalId = undefined;
349
+ }
350
+ this.pollingAttempts = 0;
351
+ }
352
+ /**
353
+ * Format response for backend processing
354
+ * Desktop strategy typically returns the credential from mobile authentication
355
+ */
356
+ formatResponse(response) {
357
+ if (!response.authenticated || !response.credential) {
358
+ throw new Error('Authentication not completed');
359
+ }
360
+ return {
361
+ credential: response.credential,
362
+ session: response.session
363
+ };
364
+ }
365
+ /**
366
+ * Check if desktop authentication is supported
367
+ * Desktop auth with QR codes works in any modern browser
368
+ */
369
+ isSupported() {
370
+ // Check for required browser APIs
371
+ return typeof window !== 'undefined' &&
372
+ typeof fetch !== 'undefined' &&
373
+ typeof Promise !== 'undefined';
374
+ }
375
+ /**
376
+ * Clean up resources (stop polling if active)
377
+ */
378
+ cleanup() {
379
+ this.stopPolling();
380
+ this.isCancelled = false;
381
+ this.onCancel = undefined;
382
+ }
383
+ /**
384
+ * Cancel the ongoing authentication
385
+ */
386
+ cancel() {
387
+ var _a;
388
+ this.isCancelled = true;
389
+ this.stopPolling();
390
+ (_a = this.onCancel) === null || _a === void 0 ? void 0 : _a.call(this);
391
+ }
392
+ }
393
+ exports.DesktopHandler = DesktopHandler;
394
+ /**
395
+ * Helper function to display QR code in a modal or inline
396
+ */
397
+ function createQRCodeDisplay(qrCodeData, options) {
398
+ const container = (options === null || options === void 0 ? void 0 : options.container) || document.createElement('div');
399
+ container.className = 'phone-auth-qr-container';
400
+ // Create QR code image
401
+ const img = document.createElement('img');
402
+ img.src = qrCodeData;
403
+ img.alt = 'QR Code for authentication';
404
+ img.style.width = `${(options === null || options === void 0 ? void 0 : options.size) || 256}px`;
405
+ img.style.height = `${(options === null || options === void 0 ? void 0 : options.size) || 256}px`;
406
+ img.style.display = 'block';
407
+ img.style.margin = '0 auto';
408
+ // Add title if provided
409
+ if (options === null || options === void 0 ? void 0 : options.title) {
410
+ const title = document.createElement('h3');
411
+ title.textContent = options.title;
412
+ title.style.textAlign = 'center';
413
+ title.style.marginBottom = '1rem';
414
+ container.appendChild(title);
415
+ }
416
+ container.appendChild(img);
417
+ // Add description if provided
418
+ if (options === null || options === void 0 ? void 0 : options.description) {
419
+ const desc = document.createElement('p');
420
+ desc.textContent = options.description;
421
+ desc.style.textAlign = 'center';
422
+ desc.style.marginTop = '1rem';
423
+ desc.style.color = '#666';
424
+ container.appendChild(desc);
425
+ }
426
+ return container;
427
+ }
428
+ /**
429
+ * Helper function to create a modal for QR code display
430
+ */
431
+ function showQRCodeModal(qrCodeData, options) {
432
+ // Create modal overlay
433
+ const overlay = document.createElement('div');
434
+ overlay.style.cssText = `
435
+ position: fixed;
436
+ top: 0;
437
+ left: 0;
438
+ right: 0;
439
+ bottom: 0;
440
+ background-color: rgba(0, 0, 0, 0.5);
441
+ display: flex;
442
+ align-items: center;
443
+ justify-content: center;
444
+ z-index: 9999;
445
+ `;
446
+ // Create modal content
447
+ const modal = document.createElement('div');
448
+ modal.style.cssText = `
449
+ background: white;
450
+ padding: 2rem;
451
+ border-radius: 8px;
452
+ max-width: 400px;
453
+ position: relative;
454
+ `;
455
+ // Add close button
456
+ const closeBtn = document.createElement('button');
457
+ closeBtn.textContent = '×';
458
+ closeBtn.style.cssText = `
459
+ position: absolute;
460
+ top: 10px;
461
+ right: 10px;
462
+ background: none;
463
+ border: none;
464
+ font-size: 24px;
465
+ cursor: pointer;
466
+ color: #999;
467
+ `;
468
+ closeBtn.onclick = () => {
469
+ document.body.removeChild(overlay);
470
+ if (options === null || options === void 0 ? void 0 : options.onClose) {
471
+ options.onClose();
472
+ }
473
+ };
474
+ modal.appendChild(closeBtn);
475
+ // Add QR code display
476
+ const qrDisplay = createQRCodeDisplay(qrCodeData, {
477
+ title: (options === null || options === void 0 ? void 0 : options.title) || 'Scan QR Code to Authenticate',
478
+ description: (options === null || options === void 0 ? void 0 : options.description) || 'Use your mobile device to scan this QR code'
479
+ });
480
+ modal.appendChild(qrDisplay);
481
+ // Add loading spinner placeholder
482
+ const statusDiv = document.createElement('div');
483
+ statusDiv.id = 'desktop-auth-status';
484
+ statusDiv.style.cssText = `
485
+ text-align: center;
486
+ margin-top: 1rem;
487
+ color: #666;
488
+ font-size: 14px;
489
+ `;
490
+ modal.appendChild(statusDiv);
491
+ overlay.appendChild(modal);
492
+ document.body.appendChild(overlay);
493
+ // Close modal on overlay click
494
+ overlay.onclick = (e) => {
495
+ if (e.target === overlay) {
496
+ document.body.removeChild(overlay);
497
+ if (options === null || options === void 0 ? void 0 : options.onClose) {
498
+ options.onClose();
499
+ }
500
+ }
501
+ };
502
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Strategy Handlers Export
3
+ * Provides implementations for TS43, Link, and Desktop authentication strategies
4
+ */
5
+ export type { StrategyHandler } from './types';
6
+ export { TS43Handler } from './ts43';
7
+ export { LinkHandler } from './link';
8
+ export type { LinkAuthOptions, LinkAuthResult, PollingStatus as LinkPollingStatus } from './link';
9
+ export { DesktopHandler, createQRCodeDisplay, showQRCodeModal } from './desktop';
10
+ export type { DesktopAuthOptions, DesktopAuthResult, PollingStatus } from './desktop';
11
+ export type { TS43Data, LinkData } from '../types';
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * Strategy Handlers Export
4
+ * Provides implementations for TS43, Link, and Desktop authentication strategies
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.showQRCodeModal = exports.createQRCodeDisplay = exports.DesktopHandler = exports.LinkHandler = exports.TS43Handler = void 0;
8
+ var ts43_1 = require("./ts43");
9
+ Object.defineProperty(exports, "TS43Handler", { enumerable: true, get: function () { return ts43_1.TS43Handler; } });
10
+ var link_1 = require("./link");
11
+ Object.defineProperty(exports, "LinkHandler", { enumerable: true, get: function () { return link_1.LinkHandler; } });
12
+ var desktop_1 = require("./desktop");
13
+ Object.defineProperty(exports, "DesktopHandler", { enumerable: true, get: function () { return desktop_1.DesktopHandler; } });
14
+ Object.defineProperty(exports, "createQRCodeDisplay", { enumerable: true, get: function () { return desktop_1.createQRCodeDisplay; } });
15
+ Object.defineProperty(exports, "showQRCodeModal", { enumerable: true, get: function () { return desktop_1.showQRCodeModal; } });