@glideidentity/web-client-sdk 5.1.3 → 6.0.0-beta.2

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