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