@glideidentity/web-client-sdk 5.1.3 → 6.0.0-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 (203) hide show
  1. package/README.md +337 -526
  2. package/dist/browser/web-client-sdk.min.js +1 -1
  3. package/dist/cjs/adapters/index.js +15 -0
  4. package/dist/cjs/adapters/react.js +192 -0
  5. package/dist/cjs/adapters/vanilla.js +38 -0
  6. package/dist/cjs/adapters/vue.js +187 -0
  7. package/dist/cjs/browser.js +58 -0
  8. package/dist/cjs/client/http.js +159 -0
  9. package/dist/cjs/client/index.js +19 -0
  10. package/dist/cjs/client/logger.js +135 -0
  11. package/dist/cjs/client/phone-auth-client.js +439 -0
  12. package/dist/cjs/client/strategies/polling.js +177 -0
  13. package/dist/cjs/core/errors.js +204 -0
  14. package/dist/cjs/core/index.js +83 -0
  15. package/dist/cjs/core/type-guards.js +196 -0
  16. package/dist/cjs/core/types.js +25 -0
  17. package/dist/{core/phone-auth/validation-utils.js → cjs/core/validators.js} +70 -23
  18. package/dist/cjs/index.js +81 -0
  19. package/dist/cjs/ui/index.js +11 -0
  20. package/dist/{core/phone-auth → cjs}/ui/mobile-debug-console.js +149 -78
  21. package/dist/cjs/ui/modal.js +1122 -0
  22. package/dist/esm/adapters/index.js +11 -0
  23. package/dist/esm/adapters/react.js +182 -0
  24. package/dist/esm/adapters/vanilla.js +29 -0
  25. package/dist/esm/adapters/vue.js +177 -0
  26. package/dist/esm/browser.js +30 -11
  27. package/dist/esm/client/http.js +156 -0
  28. package/dist/esm/client/index.js +11 -0
  29. package/dist/esm/client/logger.js +131 -0
  30. package/dist/esm/client/phone-auth-client.js +435 -0
  31. package/dist/esm/client/strategies/polling.js +174 -0
  32. package/dist/esm/core/errors.js +193 -0
  33. package/dist/esm/core/index.js +60 -0
  34. package/dist/esm/core/type-guards.js +181 -0
  35. package/dist/esm/core/types.js +22 -1
  36. package/dist/esm/core/{phone-auth/validation-utils.js → validators.js} +66 -21
  37. package/dist/esm/index.js +45 -17
  38. package/dist/esm/ui/index.js +5 -0
  39. package/dist/esm/{core/phone-auth/ui → ui}/mobile-debug-console.js +149 -78
  40. package/dist/esm/ui/modal.js +1117 -0
  41. package/dist/types/adapters/index.d.ts +10 -0
  42. package/dist/types/adapters/index.d.ts.map +1 -0
  43. package/dist/types/adapters/react.d.ts +70 -0
  44. package/dist/types/adapters/react.d.ts.map +1 -0
  45. package/dist/types/adapters/vanilla.d.ts +29 -0
  46. package/dist/types/adapters/vanilla.d.ts.map +1 -0
  47. package/dist/types/adapters/vue.d.ts +71 -0
  48. package/dist/types/adapters/vue.d.ts.map +1 -0
  49. package/dist/types/browser.d.ts +27 -0
  50. package/dist/types/browser.d.ts.map +1 -0
  51. package/dist/types/client/http.d.ts +41 -0
  52. package/dist/types/client/http.d.ts.map +1 -0
  53. package/dist/types/client/index.d.ts +10 -0
  54. package/dist/types/client/index.d.ts.map +1 -0
  55. package/dist/types/client/logger.d.ts +36 -0
  56. package/dist/types/client/logger.d.ts.map +1 -0
  57. package/dist/types/client/phone-auth-client.d.ts +91 -0
  58. package/dist/types/client/phone-auth-client.d.ts.map +1 -0
  59. package/dist/types/client/strategies/polling.d.ts +36 -0
  60. package/dist/types/client/strategies/polling.d.ts.map +1 -0
  61. package/dist/types/core/errors.d.ts +71 -0
  62. package/dist/types/core/errors.d.ts.map +1 -0
  63. package/dist/types/core/index.d.ts +38 -0
  64. package/dist/types/core/index.d.ts.map +1 -0
  65. package/dist/types/core/type-guards.d.ts +118 -0
  66. package/dist/types/core/type-guards.d.ts.map +1 -0
  67. package/dist/types/core/types.d.ts +534 -0
  68. package/dist/types/core/types.d.ts.map +1 -0
  69. package/dist/types/core/validators.d.ts +63 -0
  70. package/dist/types/core/validators.d.ts.map +1 -0
  71. package/dist/types/index.d.ts +40 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/ui/index.d.ts +6 -0
  74. package/dist/types/ui/index.d.ts.map +1 -0
  75. package/dist/{esm/core/phone-auth → types}/ui/mobile-debug-console.d.ts +1 -0
  76. package/dist/types/ui/mobile-debug-console.d.ts.map +1 -0
  77. package/dist/types/ui/modal.d.ts +87 -0
  78. package/dist/types/ui/modal.d.ts.map +1 -0
  79. package/package.json +48 -34
  80. package/dist/adapters/angular/client.service.d.ts +0 -7
  81. package/dist/adapters/angular/client.service.js +0 -30
  82. package/dist/adapters/angular/index.d.ts +0 -3
  83. package/dist/adapters/angular/index.js +0 -18
  84. package/dist/adapters/angular/phone-auth.service.d.ts +0 -38
  85. package/dist/adapters/angular/phone-auth.service.js +0 -130
  86. package/dist/adapters/react/index.d.ts +0 -9
  87. package/dist/adapters/react/index.js +0 -28
  88. package/dist/adapters/react/useClient.d.ts +0 -26
  89. package/dist/adapters/react/useClient.js +0 -121
  90. package/dist/adapters/react/usePhoneAuth.d.ts +0 -23
  91. package/dist/adapters/react/usePhoneAuth.js +0 -95
  92. package/dist/adapters/vanilla/client.d.ts +0 -8
  93. package/dist/adapters/vanilla/client.js +0 -33
  94. package/dist/adapters/vanilla/index.d.ts +0 -3
  95. package/dist/adapters/vanilla/index.js +0 -18
  96. package/dist/adapters/vanilla/phone-auth.d.ts +0 -46
  97. package/dist/adapters/vanilla/phone-auth.js +0 -138
  98. package/dist/adapters/vue/index.d.ts +0 -10
  99. package/dist/adapters/vue/index.js +0 -36
  100. package/dist/adapters/vue/useClient.d.ts +0 -115
  101. package/dist/adapters/vue/useClient.js +0 -131
  102. package/dist/adapters/vue/usePhoneAuth.d.ts +0 -94
  103. package/dist/adapters/vue/usePhoneAuth.js +0 -103
  104. package/dist/browser.d.ts +0 -7
  105. package/dist/browser.js +0 -31
  106. package/dist/core/client.d.ts +0 -22
  107. package/dist/core/client.js +0 -77
  108. package/dist/core/logger.d.ts +0 -130
  109. package/dist/core/logger.js +0 -370
  110. package/dist/core/phone-auth/api-types.d.ts +0 -593
  111. package/dist/core/phone-auth/api-types.js +0 -215
  112. package/dist/core/phone-auth/client.d.ts +0 -189
  113. package/dist/core/phone-auth/client.js +0 -1441
  114. package/dist/core/phone-auth/error-utils.d.ts +0 -110
  115. package/dist/core/phone-auth/error-utils.js +0 -350
  116. package/dist/core/phone-auth/index.d.ts +0 -7
  117. package/dist/core/phone-auth/index.js +0 -50
  118. package/dist/core/phone-auth/status-types.d.ts +0 -107
  119. package/dist/core/phone-auth/status-types.js +0 -31
  120. package/dist/core/phone-auth/strategies/desktop.d.ts +0 -122
  121. package/dist/core/phone-auth/strategies/desktop.js +0 -596
  122. package/dist/core/phone-auth/strategies/index.d.ts +0 -11
  123. package/dist/core/phone-auth/strategies/index.js +0 -15
  124. package/dist/core/phone-auth/strategies/link.d.ts +0 -89
  125. package/dist/core/phone-auth/strategies/link.js +0 -384
  126. package/dist/core/phone-auth/strategies/ts43.d.ts +0 -32
  127. package/dist/core/phone-auth/strategies/ts43.js +0 -161
  128. package/dist/core/phone-auth/strategies/types.d.ts +0 -18
  129. package/dist/core/phone-auth/strategies/types.js +0 -6
  130. package/dist/core/phone-auth/type-guards.d.ts +0 -143
  131. package/dist/core/phone-auth/type-guards.js +0 -198
  132. package/dist/core/phone-auth/types.d.ts +0 -237
  133. package/dist/core/phone-auth/types.js +0 -93
  134. package/dist/core/phone-auth/ui/mobile-debug-console.d.ts +0 -25
  135. package/dist/core/phone-auth/ui/modal.d.ts +0 -88
  136. package/dist/core/phone-auth/ui/modal.js +0 -598
  137. package/dist/core/phone-auth/validation-utils.d.ts +0 -44
  138. package/dist/core/types.d.ts +0 -62
  139. package/dist/core/types.js +0 -2
  140. package/dist/core/version.d.ts +0 -1
  141. package/dist/core/version.js +0 -5
  142. package/dist/esm/adapters/angular/client.service.d.ts +0 -7
  143. package/dist/esm/adapters/angular/client.service.js +0 -27
  144. package/dist/esm/adapters/angular/index.d.ts +0 -3
  145. package/dist/esm/adapters/angular/index.js +0 -4
  146. package/dist/esm/adapters/angular/phone-auth.service.d.ts +0 -38
  147. package/dist/esm/adapters/angular/phone-auth.service.js +0 -127
  148. package/dist/esm/adapters/react/index.d.ts +0 -9
  149. package/dist/esm/adapters/react/index.js +0 -8
  150. package/dist/esm/adapters/react/useClient.d.ts +0 -26
  151. package/dist/esm/adapters/react/useClient.js +0 -116
  152. package/dist/esm/adapters/react/usePhoneAuth.d.ts +0 -23
  153. package/dist/esm/adapters/react/usePhoneAuth.js +0 -92
  154. package/dist/esm/adapters/vanilla/client.d.ts +0 -8
  155. package/dist/esm/adapters/vanilla/client.js +0 -29
  156. package/dist/esm/adapters/vanilla/index.d.ts +0 -3
  157. package/dist/esm/adapters/vanilla/index.js +0 -4
  158. package/dist/esm/adapters/vanilla/phone-auth.d.ts +0 -46
  159. package/dist/esm/adapters/vanilla/phone-auth.js +0 -134
  160. package/dist/esm/adapters/vue/index.d.ts +0 -10
  161. package/dist/esm/adapters/vue/index.js +0 -11
  162. package/dist/esm/adapters/vue/useClient.d.ts +0 -115
  163. package/dist/esm/adapters/vue/useClient.js +0 -127
  164. package/dist/esm/adapters/vue/usePhoneAuth.d.ts +0 -94
  165. package/dist/esm/adapters/vue/usePhoneAuth.js +0 -100
  166. package/dist/esm/browser.d.ts +0 -7
  167. package/dist/esm/core/client.d.ts +0 -22
  168. package/dist/esm/core/client.js +0 -70
  169. package/dist/esm/core/logger.d.ts +0 -130
  170. package/dist/esm/core/logger.js +0 -359
  171. package/dist/esm/core/phone-auth/api-types.d.ts +0 -593
  172. package/dist/esm/core/phone-auth/api-types.js +0 -203
  173. package/dist/esm/core/phone-auth/client.d.ts +0 -189
  174. package/dist/esm/core/phone-auth/client.js +0 -1404
  175. package/dist/esm/core/phone-auth/error-utils.d.ts +0 -110
  176. package/dist/esm/core/phone-auth/error-utils.js +0 -338
  177. package/dist/esm/core/phone-auth/index.d.ts +0 -7
  178. package/dist/esm/core/phone-auth/index.js +0 -8
  179. package/dist/esm/core/phone-auth/status-types.d.ts +0 -107
  180. package/dist/esm/core/phone-auth/status-types.js +0 -26
  181. package/dist/esm/core/phone-auth/strategies/desktop.d.ts +0 -122
  182. package/dist/esm/core/phone-auth/strategies/desktop.js +0 -590
  183. package/dist/esm/core/phone-auth/strategies/index.d.ts +0 -11
  184. package/dist/esm/core/phone-auth/strategies/index.js +0 -7
  185. package/dist/esm/core/phone-auth/strategies/link.d.ts +0 -89
  186. package/dist/esm/core/phone-auth/strategies/link.js +0 -380
  187. package/dist/esm/core/phone-auth/strategies/ts43.d.ts +0 -32
  188. package/dist/esm/core/phone-auth/strategies/ts43.js +0 -157
  189. package/dist/esm/core/phone-auth/strategies/types.d.ts +0 -18
  190. package/dist/esm/core/phone-auth/strategies/types.js +0 -5
  191. package/dist/esm/core/phone-auth/type-guards.d.ts +0 -143
  192. package/dist/esm/core/phone-auth/type-guards.js +0 -185
  193. package/dist/esm/core/phone-auth/types.d.ts +0 -237
  194. package/dist/esm/core/phone-auth/types.js +0 -76
  195. package/dist/esm/core/phone-auth/ui/modal.d.ts +0 -88
  196. package/dist/esm/core/phone-auth/ui/modal.js +0 -594
  197. package/dist/esm/core/phone-auth/validation-utils.d.ts +0 -44
  198. package/dist/esm/core/types.d.ts +0 -62
  199. package/dist/esm/core/version.d.ts +0 -1
  200. package/dist/esm/core/version.js +0 -2
  201. package/dist/esm/index.d.ts +0 -12
  202. package/dist/index.d.ts +0 -12
  203. package/dist/index.js +0 -55
@@ -1,89 +0,0 @@
1
- /**
2
- * Link Strategy Handler
3
- * Handles authentication via app links (iOS and Android)
4
- * Opens authentication app while keeping user on current page
5
- */
6
- import type { StrategyHandler } from './types';
7
- import type { PrepareResponse } from '../types';
8
- export interface LinkAuthOptions {
9
- /** Fixed polling interval in milliseconds (default: 2000) */
10
- pollingInterval?: number;
11
- /** Maximum polling attempts before timeout (default: 30 = 1 minute with 2s interval) */
12
- maxPollingAttempts?: number;
13
- /** Custom polling endpoint (overrides backend-provided or configured endpoint) */
14
- pollingEndpoint?: string;
15
- /** Developer environment (adds 'developer' header to requests) */
16
- devEnv?: string;
17
- /** Callback when link is opened */
18
- onLinkOpened?: () => void;
19
- /** Callback for polling status updates */
20
- onStatusUpdate?: (status: PollingStatus) => void;
21
- /** Callback when authentication times out */
22
- onTimeout?: () => void;
23
- /** Callback when authentication is cancelled by user */
24
- onCancel?: () => void;
25
- }
26
- export interface PollingStatus {
27
- /** Current status of the authentication */
28
- status: 'pending' | 'authenticated' | 'expired' | 'cancelled' | 'error';
29
- /** Optional message */
30
- message?: string;
31
- /** Authentication result data if status is 'authenticated' */
32
- data?: any;
33
- }
34
- export interface LinkAuthResult {
35
- /** Whether authentication was successful */
36
- authenticated: boolean;
37
- /** Authentication credential if successful */
38
- credential?: string;
39
- /** Session info for subsequent requests */
40
- session?: any;
41
- /** Error message if authentication failed */
42
- error?: string;
43
- }
44
- export declare class LinkHandler implements StrategyHandler {
45
- private pollingInterval?;
46
- private isPollingActive;
47
- private isCancelled;
48
- private onCancel?;
49
- private pollingReject?;
50
- private isPollingInProgress;
51
- /**
52
- * Invoke link-based authentication
53
- * Opens authentication app while keeping user on current page
54
- */
55
- invoke(data: PrepareResponse, options?: LinkAuthOptions): Promise<LinkAuthResult>;
56
- /**
57
- * Open authentication link by navigating to the URL
58
- */
59
- private openAuthenticationLink;
60
- /**
61
- * Start polling for authentication status with constant interval
62
- */
63
- private startPolling;
64
- /**
65
- * Stop polling
66
- */
67
- private stopPolling;
68
- /**
69
- * Format response for backend processing
70
- */
71
- formatResponse(response: LinkAuthResult): any;
72
- /**
73
- * Check if link strategy is supported
74
- * Returns true for mobile devices (iOS and Android)
75
- */
76
- isSupported(): boolean;
77
- /**
78
- * Clean up resources (stop polling if active)
79
- */
80
- cleanup(): void;
81
- /**
82
- * Check if polling is currently active
83
- */
84
- isPolling(): boolean;
85
- /**
86
- * Cancel the ongoing authentication
87
- */
88
- cancel(): void;
89
- }
@@ -1,380 +0,0 @@
1
- /**
2
- * Link Strategy Handler
3
- * Handles authentication via app links (iOS and Android)
4
- * Opens authentication app while keeping user on current page
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 LinkHandler {
16
- constructor() {
17
- this.isPollingActive = false;
18
- this.isCancelled = false;
19
- this.isPollingInProgress = false;
20
- }
21
- /**
22
- * Invoke link-based authentication
23
- * Opens authentication app while keeping user on current page
24
- */
25
- invoke(data, options) {
26
- return __awaiter(this, void 0, void 0, function* () {
27
- console.log('[Link Auth] 🔗 invoke() called with data:', JSON.stringify(data, null, 2));
28
- console.log('[Link Auth] Options:', options ? JSON.stringify({
29
- pollingInterval: options.pollingInterval,
30
- maxPollingAttempts: options.maxPollingAttempts,
31
- pollingEndpoint: options.pollingEndpoint
32
- }) : 'none');
33
- // Extract link data from prepare response
34
- const linkData = data.data;
35
- if (!linkData || !linkData.url) {
36
- throw new Error('Invalid link data: missing URL');
37
- }
38
- const sessionKey = data.session.session_key;
39
- console.log('[Link Auth] Session key:', sessionKey);
40
- console.log('[Link Auth] Link URL:', linkData.url);
41
- // Open authentication app without navigating away from current page
42
- this.openAuthenticationLink(linkData.url);
43
- // Notify that link was opened
44
- if (options === null || options === void 0 ? void 0 : options.onLinkOpened) {
45
- options.onLinkOpened();
46
- }
47
- // Start polling for authentication status
48
- // Use constant interval (no exponential backoff)
49
- return this.startPolling(sessionKey, linkData, options);
50
- });
51
- }
52
- /**
53
- * Open authentication link by navigating to the URL
54
- */
55
- openAuthenticationLink(url) {
56
- // Use location.href to navigate directly - required for App Clips to open properly
57
- window.location.href = url;
58
- }
59
- /**
60
- * Start polling for authentication status with constant interval
61
- */
62
- startPolling(sessionKey, linkData, options) {
63
- return __awaiter(this, void 0, void 0, function* () {
64
- const interval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || 2000; // Fixed 2 second interval
65
- const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 30; // 1 minute with 2s interval
66
- let attempts = 0;
67
- console.log('[Link Auth] 🚀 Starting polling:', {
68
- sessionKey,
69
- interval: `${interval}ms`,
70
- maxAttempts,
71
- linkDataAvailable: !!linkData
72
- });
73
- return new Promise((resolve, reject) => {
74
- this.isPollingActive = true;
75
- this.pollingReject = reject; // Store reject function for cancel()
76
- const poll = () => __awaiter(this, void 0, void 0, function* () {
77
- if (!this.isPollingActive) {
78
- return; // Polling was stopped
79
- }
80
- // Skip if another poll is already in progress
81
- if (this.isPollingInProgress) {
82
- return;
83
- }
84
- let statusUrl = ''; // Declare at function scope for catch block access
85
- try {
86
- this.isPollingInProgress = true;
87
- // Check max attempts before making the request
88
- if (attempts >= maxAttempts) {
89
- this.stopPolling();
90
- if (options === null || options === void 0 ? void 0 : options.onTimeout) {
91
- options.onTimeout();
92
- }
93
- // Calculate actual timeout duration
94
- const timeoutSeconds = Math.round((maxAttempts * interval) / 1000);
95
- const timeoutMessage = timeoutSeconds >= 60
96
- ? `${Math.floor(timeoutSeconds / 60)} minute${Math.floor(timeoutSeconds / 60) > 1 ? 's' : ''}`
97
- : `${timeoutSeconds} seconds`;
98
- if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
99
- options.onStatusUpdate({
100
- status: 'expired',
101
- message: `Authentication timeout after ${timeoutMessage}`
102
- });
103
- }
104
- reject(new Error(`Authentication timeout after ${timeoutMessage}`));
105
- return;
106
- }
107
- // Build public status endpoint URL
108
- // Use the same priority logic as Desktop strategy:
109
- // 1. options?.pollingEndpoint (already contains invoke options OR client config from client.ts)
110
- // 2. Backend-provided status_url from linkData
111
- // 3. Hardcoded fallback to API server
112
- let endpoint = options === null || options === void 0 ? void 0 : options.pollingEndpoint;
113
- let endpointSource = 'options';
114
- if (!endpoint && linkData.status_url) {
115
- endpoint = linkData.status_url;
116
- endpointSource = 'backend';
117
- }
118
- console.log('[Link Auth] Polling endpoint selection:');
119
- console.log(' - options?.pollingEndpoint:', options === null || options === void 0 ? void 0 : options.pollingEndpoint);
120
- console.log(' - linkData.status_url:', linkData.status_url);
121
- console.log(' - selected endpoint:', endpoint, 'from source:', endpointSource);
122
- // Build the status URL based on endpoint format (same as Desktop)
123
- if (endpoint && (endpoint.startsWith('http://') || endpoint.startsWith('https://'))) {
124
- // Full URL provided
125
- statusUrl = endpoint;
126
- }
127
- else if (endpoint && endpoint !== '') {
128
- // Relative path provided (e.g. '/api/phone-auth/status')
129
- const origin = typeof window !== 'undefined' ? window.location.origin : '';
130
- if (endpoint.includes('{{session_id}}')) {
131
- statusUrl = origin + endpoint.replace('{{session_id}}', sessionKey);
132
- }
133
- else {
134
- // Append session ID to the provided endpoint
135
- statusUrl = origin + endpoint + '/' + sessionKey;
136
- }
137
- }
138
- else {
139
- // No endpoint provided - use hardcoded fallback
140
- statusUrl = `https://api.glideidentity.app/public/status/${sessionKey}`;
141
- endpointSource = 'fallback';
142
- }
143
- console.log(`[Link Auth] Using ${endpointSource} endpoint: ${statusUrl}`);
144
- // Poll public status endpoint - no authentication required
145
- console.log(`[Link Auth] Polling status (attempt ${attempts}/${maxAttempts}): ${statusUrl}`);
146
- // Build headers
147
- const headers = {
148
- 'Accept': 'application/json'
149
- };
150
- // Add developer header if devEnv is set
151
- if (options === null || options === void 0 ? void 0 : options.devEnv) {
152
- headers['developer'] = options.devEnv;
153
- console.log(`[Link Auth] Adding developer header: ${options.devEnv}`);
154
- }
155
- const response = yield fetch(statusUrl, {
156
- method: 'GET',
157
- headers
158
- });
159
- console.log(`[Link Auth] Poll response - Status: ${response.status}, OK: ${response.ok}`);
160
- // Handle based on HTTP status code
161
- if (response.status === 200) {
162
- // Session is active (pending or completed)
163
- const result = yield response.json();
164
- console.log('[Link Auth] Poll response data:', JSON.stringify(result, null, 2));
165
- if (result.status === 'completed') {
166
- // Authentication completed successfully
167
- console.log('[Link Auth] ✅ Authentication COMPLETED! Session:', sessionKey);
168
- console.log('[Link Auth] Full completion result:', JSON.stringify(result, null, 2));
169
- this.stopPolling();
170
- // Authentication completed successfully
171
- if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
172
- options.onStatusUpdate({
173
- status: 'authenticated',
174
- message: 'Authentication successful',
175
- data: result
176
- });
177
- }
178
- // Return the authentication result
179
- this.pollingReject = undefined; // Clear reject function on success
180
- resolve({
181
- authenticated: true,
182
- credential: result.credential || sessionKey,
183
- session: result.session || {
184
- session_key: sessionKey,
185
- status: result.status,
186
- protocol: result.protocol || 'link',
187
- created_at: result.created_at,
188
- last_updated: result.last_updated
189
- }
190
- });
191
- }
192
- else if (result.status === 'pending') {
193
- // Continue polling
194
- console.log('[Link Auth] Status still pending, continuing to poll...');
195
- attempts++; // Increment attempts after successful poll
196
- if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
197
- options.onStatusUpdate({
198
- status: 'pending',
199
- message: 'Waiting for app authentication...'
200
- });
201
- }
202
- }
203
- else {
204
- // Unexpected status value
205
- console.log('[Link Auth] ⚠️ Unexpected status value:', result.status, 'Full result:', JSON.stringify(result, null, 2));
206
- attempts++; // Increment for unexpected status too
207
- }
208
- }
209
- else if (response.status === 410) {
210
- // Session expired
211
- console.log('[Link Auth] ❌ Session expired (410)');
212
- this.stopPolling();
213
- const errorData = yield response.json().catch(() => ({ message: 'Session expired' }));
214
- if (options === null || options === void 0 ? void 0 : options.onTimeout) {
215
- options.onTimeout();
216
- }
217
- if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
218
- options.onStatusUpdate({
219
- status: 'expired',
220
- message: errorData.message || 'Session expired'
221
- });
222
- }
223
- reject(new Error(errorData.message || 'Session expired'));
224
- }
225
- else if (response.status === 422) {
226
- // Authentication failed
227
- console.log('[Link Auth] ❌ Authentication failed (422)');
228
- this.stopPolling();
229
- const errorData = yield response.json().catch(() => ({ message: 'Authentication failed' }));
230
- console.log('[Link Auth] Error data:', JSON.stringify(errorData, null, 2));
231
- const isUserCancelled = errorData.code === 'USER_CANCELLED';
232
- const errorMsg = isUserCancelled
233
- ? 'User cancelled authentication'
234
- : (errorData.message || 'Verification failed');
235
- // Authentication failed
236
- if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
237
- options.onStatusUpdate({
238
- status: 'error',
239
- message: errorMsg
240
- });
241
- }
242
- reject(new Error(errorMsg));
243
- }
244
- else if (response.status === 404) {
245
- // Session not found
246
- console.log('[Link Auth] ❌ Session not found (404)');
247
- this.stopPolling();
248
- if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
249
- options.onStatusUpdate({
250
- status: 'error',
251
- message: 'Session not found'
252
- });
253
- }
254
- reject(new Error('Session not found'));
255
- }
256
- else if (response.status === 400) {
257
- // Invalid session key
258
- console.log('[Link Auth] ❌ Invalid session key (400)');
259
- this.stopPolling();
260
- const errorData = yield response.json().catch(() => ({ message: 'Invalid session key' }));
261
- console.log('[Link Auth] Error data:', JSON.stringify(errorData, null, 2));
262
- reject(new Error(errorData.message || 'Invalid session key'));
263
- }
264
- else {
265
- // Unexpected status - continue polling
266
- console.log('[Link Auth] ⚠️ Unexpected HTTP status:', response.status, 'continuing to poll...');
267
- attempts++; // Increment for unexpected HTTP status
268
- try {
269
- const body = yield response.text();
270
- console.log('[Link Auth] Response body:', body);
271
- }
272
- catch (e) {
273
- console.log('[Link Auth] Could not read response body');
274
- }
275
- }
276
- }
277
- catch (error) {
278
- // Network or other error - continue polling
279
- console.error('[Link Auth] 🔴 Polling error:', error.message || error);
280
- attempts++; // Increment for error case
281
- console.error('[Link Auth] Error details:', {
282
- name: error.name,
283
- message: error.message,
284
- stack: error.stack,
285
- statusUrl: statusUrl,
286
- attempt: attempts,
287
- error: error
288
- });
289
- // Check if it's a CORS error (common on mobile)
290
- if (error.message && error.message.toLowerCase().includes('failed')) {
291
- console.error('[Link Auth] ⚠️ Possible CORS issue. Status URL:', statusUrl);
292
- console.error('[Link Auth] Make sure the API endpoint allows CORS from your ngrok domain');
293
- }
294
- if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
295
- options.onStatusUpdate({
296
- status: 'pending',
297
- message: `Connection issue, retrying... (${attempts}/${maxAttempts})`
298
- });
299
- }
300
- }
301
- finally {
302
- // Always clear the polling flag when done
303
- this.isPollingInProgress = false;
304
- }
305
- });
306
- // Start initial poll immediately
307
- poll();
308
- // Set up constant interval polling (no backoff)
309
- this.pollingInterval = setInterval(poll, interval);
310
- });
311
- });
312
- }
313
- /**
314
- * Stop polling
315
- */
316
- stopPolling() {
317
- console.log('[Link Auth] 🏁 Stopping polling');
318
- this.isPollingActive = false;
319
- this.isPollingInProgress = false;
320
- if (this.pollingInterval) {
321
- clearInterval(this.pollingInterval);
322
- this.pollingInterval = undefined;
323
- }
324
- }
325
- /**
326
- * Format response for backend processing
327
- */
328
- formatResponse(response) {
329
- if (!response.authenticated || !response.credential) {
330
- throw new Error('Authentication not completed');
331
- }
332
- return {
333
- credential: response.credential,
334
- session: response.session,
335
- type: 'link'
336
- };
337
- }
338
- /**
339
- * Check if link strategy is supported
340
- * Returns true for mobile devices (iOS and Android)
341
- */
342
- isSupported() {
343
- // Link strategy is supported on mobile devices
344
- const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
345
- return isMobile;
346
- }
347
- /**
348
- * Clean up resources (stop polling if active)
349
- */
350
- cleanup() {
351
- this.stopPolling();
352
- this.isCancelled = false;
353
- this.onCancel = undefined;
354
- this.pollingReject = undefined;
355
- }
356
- /**
357
- * Check if polling is currently active
358
- */
359
- isPolling() {
360
- return this.pollingInterval !== undefined;
361
- }
362
- /**
363
- * Cancel the ongoing authentication
364
- */
365
- cancel() {
366
- var _a;
367
- console.log('[Link Auth] Cancelling authentication');
368
- this.isCancelled = true;
369
- this.stopPolling();
370
- (_a = this.onCancel) === null || _a === void 0 ? void 0 : _a.call(this);
371
- // Immediately reject the polling promise
372
- if (this.pollingReject) {
373
- this.pollingReject({
374
- code: 'USER_DENIED',
375
- message: 'Authentication cancelled by user'
376
- });
377
- this.pollingReject = undefined;
378
- }
379
- }
380
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * TS-43 Strategy Handler
3
- * Handles Digital Credentials API authentication for Android/Chromium
4
- * Properly manages session objects with session_key and nonce
5
- */
6
- import type { StrategyHandler } from './types';
7
- import type { PrepareResponse } from '../types';
8
- export declare class TS43Handler implements StrategyHandler {
9
- /**
10
- * Invoke TS-43 authentication using Digital Credentials API
11
- * The data structure from backend is already in the correct format for navigator.credentials.get
12
- */
13
- invoke(data: PrepareResponse): Promise<any>;
14
- /**
15
- * Format the credential response for backend processing
16
- * Include the session key so backend can retrieve the full session
17
- */
18
- formatResponse(response: any): any;
19
- /**
20
- * Check if Digital Credentials API is supported
21
- */
22
- isSupported(): boolean;
23
- /**
24
- * Get browser support information
25
- */
26
- getBrowserSupportInfo(): {
27
- supported: boolean;
28
- browser: string;
29
- message?: string;
30
- helpUrl?: string;
31
- };
32
- }
@@ -1,157 +0,0 @@
1
- /**
2
- * TS-43 Strategy Handler
3
- * Handles Digital Credentials API authentication for Android/Chromium
4
- * Properly manages session objects with session_key and nonce
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 TS43Handler {
16
- /**
17
- * Invoke TS-43 authentication using Digital Credentials API
18
- * The data structure from backend is already in the correct format for navigator.credentials.get
19
- */
20
- invoke(data) {
21
- return __awaiter(this, void 0, void 0, function* () {
22
- // Validate session structure - only session_key is actually required
23
- if (!data.session || !data.session.session_key) {
24
- throw new Error('Invalid TS43 session: missing required session_key');
25
- }
26
- // Check if Digital Credentials API is available
27
- if (!this.isSupported()) {
28
- throw new Error('Digital Credentials API not supported in this browser');
29
- }
30
- // Extract TS43 data from the prepare response
31
- const ts43Data = data.data;
32
- // The data is already in the correct format from backend
33
- // Just pass it through to navigator.credentials.get
34
- const credentialRequest = {
35
- digital: {
36
- requests: [{
37
- protocol: ts43Data.protocol, // e.g., "openid4vp-v1-unsigned"
38
- data: ts43Data.data // Pass the entire data object as-is
39
- }]
40
- }
41
- };
42
- try {
43
- // @ts-ignore - Digital Credentials API types not yet in TypeScript
44
- const credential = yield navigator.credentials.get(credentialRequest);
45
- if (!credential) {
46
- throw new Error('No credential received from Digital Credentials API');
47
- }
48
- // Success vibration (haptic feedback)
49
- if (typeof navigator !== 'undefined' && navigator.vibrate) {
50
- // Add a small delay to ensure the browser has regained focus/visibility
51
- // after the native bottom sheet closes
52
- setTimeout(() => {
53
- try {
54
- // Double tap pattern: vibrate 80ms, pause 50ms, vibrate 80ms
55
- // Slightly longer duration (80ms vs 50ms) ensures it registers on more devices
56
- navigator.vibrate([80, 50, 80]);
57
- }
58
- catch (e) {
59
- // Ignore vibration errors
60
- }
61
- }, 200);
62
- }
63
- // @ts-ignore - credential.data is not typed yet
64
- return credential;
65
- }
66
- catch (error) {
67
- // Handle browser-specific errors
68
- if (error instanceof Error) {
69
- if (error.name === 'NotAllowedError') {
70
- throw new Error('User denied the authentication request');
71
- }
72
- if (error.name === 'NotSupportedError') {
73
- throw new Error('Digital Credentials API not supported');
74
- }
75
- if (error.name === 'AbortError') {
76
- throw new Error('Authentication was aborted');
77
- }
78
- }
79
- throw error;
80
- }
81
- });
82
- }
83
- /**
84
- * Format the credential response for backend processing
85
- * Include the session key so backend can retrieve the full session
86
- */
87
- formatResponse(response) {
88
- var _a;
89
- // Extract vp_token from the response
90
- const vpToken = (_a = response.data) === null || _a === void 0 ? void 0 : _a.vp_token;
91
- if (!vpToken) {
92
- throw new Error('Invalid TS43 response: missing vp_token');
93
- }
94
- return {
95
- vp_token: vpToken,
96
- type: 'ts43'
97
- };
98
- }
99
- /**
100
- * Check if Digital Credentials API is supported
101
- */
102
- isSupported() {
103
- if (typeof window === 'undefined') {
104
- return false;
105
- }
106
- // Check for DigitalCredential constructor
107
- // @ts-ignore - DigitalCredential not yet in TypeScript
108
- return 'DigitalCredential' in window;
109
- }
110
- /**
111
- * Get browser support information
112
- */
113
- getBrowserSupportInfo() {
114
- if (typeof window === 'undefined') {
115
- return {
116
- supported: false,
117
- browser: 'unknown',
118
- message: 'Not running in a browser environment'
119
- };
120
- }
121
- const userAgent = navigator.userAgent;
122
- const isChrome = /Chrome/.test(userAgent) && /Google Inc/.test(navigator.vendor);
123
- const isEdge = /Edg\//.test(userAgent);
124
- const isAndroid = /Android/.test(userAgent);
125
- const isSupported = this.isSupported();
126
- if (isSupported) {
127
- return {
128
- supported: true,
129
- browser: isChrome ? 'Chrome' : isEdge ? 'Edge' : 'Chromium'
130
- };
131
- }
132
- // Provide specific guidance based on browser
133
- if ((isChrome || isEdge) && isAndroid) {
134
- return {
135
- supported: false,
136
- browser: isChrome ? 'Chrome' : 'Edge',
137
- message: 'Digital Credentials API requires Chrome 128+ on Android. Please update your browser.',
138
- helpUrl: 'https://play.google.com/store/apps/details?id=com.android.chrome'
139
- };
140
- }
141
- if (isChrome || isEdge) {
142
- return {
143
- supported: false,
144
- browser: isChrome ? 'Chrome' : 'Edge',
145
- message: 'Digital Credentials API is not enabled. Please enable the #web-identity-digital-credentials flag.',
146
- helpUrl: isChrome
147
- ? 'chrome://flags/#web-identity-digital-credentials'
148
- : 'edge://flags/#web-identity-digital-credentials'
149
- };
150
- }
151
- return {
152
- supported: false,
153
- browser: 'unsupported',
154
- message: 'Your browser does not support Digital Credentials API'
155
- };
156
- }
157
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * Strategy Handler Interface
3
- * Defines the contract for authentication strategy implementations
4
- */
5
- export interface StrategyHandler {
6
- /**
7
- * Invoke authentication using strategy-specific data
8
- */
9
- invoke(data: any): Promise<any>;
10
- /**
11
- * Format response for backend processing
12
- */
13
- formatResponse(response: any): any;
14
- /**
15
- * Check if this strategy is supported in the current environment
16
- */
17
- isSupported(): boolean;
18
- }