@glideidentity/web-client-sdk 4.4.8-beta.1 → 4.4.8-beta.3

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 (36) hide show
  1. package/dist/adapters/react/usePhoneAuth.d.ts +1 -1
  2. package/dist/adapters/vue/useClient.d.ts +3 -3
  3. package/dist/adapters/vue/usePhoneAuth.d.ts +1 -1
  4. package/dist/browser/web-client-sdk.min.js +1 -1
  5. package/dist/core/phone-auth/api-types.d.ts +112 -27
  6. package/dist/core/phone-auth/client.d.ts +13 -11
  7. package/dist/core/phone-auth/client.js +263 -248
  8. package/dist/core/phone-auth/index.d.ts +1 -1
  9. package/dist/core/phone-auth/index.js +7 -2
  10. package/dist/core/phone-auth/strategies/desktop.d.ts +1 -0
  11. package/dist/core/phone-auth/strategies/desktop.js +64 -18
  12. package/dist/core/phone-auth/strategies/link.js +97 -5
  13. package/dist/core/phone-auth/type-guards.d.ts +61 -43
  14. package/dist/core/phone-auth/type-guards.js +82 -44
  15. package/dist/core/phone-auth/ui/modal.js +14 -1
  16. package/dist/core/version.js +1 -1
  17. package/dist/esm/adapters/react/usePhoneAuth.d.ts +1 -1
  18. package/dist/esm/adapters/vue/useClient.d.ts +3 -3
  19. package/dist/esm/adapters/vue/usePhoneAuth.d.ts +1 -1
  20. package/dist/esm/core/phone-auth/api-types.d.ts +112 -27
  21. package/dist/esm/core/phone-auth/client.d.ts +13 -11
  22. package/dist/esm/core/phone-auth/client.js +263 -248
  23. package/dist/esm/core/phone-auth/index.d.ts +1 -1
  24. package/dist/esm/core/phone-auth/index.js +3 -1
  25. package/dist/esm/core/phone-auth/strategies/desktop.d.ts +1 -0
  26. package/dist/esm/core/phone-auth/strategies/desktop.js +64 -18
  27. package/dist/esm/core/phone-auth/strategies/link.js +97 -5
  28. package/dist/esm/core/phone-auth/type-guards.d.ts +61 -43
  29. package/dist/esm/core/phone-auth/type-guards.js +76 -41
  30. package/dist/esm/core/phone-auth/ui/modal.js +14 -1
  31. package/dist/esm/core/version.js +1 -1
  32. package/dist/esm/index.d.ts +2 -2
  33. package/dist/esm/index.js +3 -1
  34. package/dist/index.d.ts +2 -2
  35. package/dist/index.js +7 -2
  36. package/package.json +1 -1
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.requiresUserAction = exports.requiresPolling = exports.getStrategy = exports.isDesktopStrategy = exports.isTS43Strategy = exports.isLinkStrategy = exports.isCredential = exports.isHeadlessResult = exports.MobileDebugConsole = exports.validateNonce = exports.validateConsentData = exports.validateUseCaseRequirements = exports.validatePlmn = exports.validatePhoneNumber = exports.createErrorBreadcrumb = exports.serializeError = exports.isRetryableError = exports.getRetryDelay = exports.isErrorCode = exports.getUserMessage = exports.isUserError = exports.isPhoneAuthError = exports.PhoneAuthErrorCode = exports.PhoneAuthClient = void 0;
17
+ exports.requiresUserAction = exports.requiresPolling = exports.isHeadlessResult = exports.hasTrigger = exports.hasPollingControls = exports.getStrategy = exports.isDesktopStrategy = exports.isTS43Strategy = exports.isLinkStrategy = exports.isAuthCredential = exports.isCredential = exports.isExtendedResponse = exports.MobileDebugConsole = exports.validateNonce = exports.validateConsentData = exports.validateUseCaseRequirements = exports.validatePlmn = exports.validatePhoneNumber = exports.createErrorBreadcrumb = exports.serializeError = exports.isRetryableError = exports.getRetryDelay = exports.isErrorCode = exports.getUserMessage = exports.isUserError = exports.isPhoneAuthError = exports.PhoneAuthErrorCode = exports.PhoneAuthClient = void 0;
18
18
  var client_1 = require("./client");
19
19
  Object.defineProperty(exports, "PhoneAuthClient", { enumerable: true, get: function () { return client_1.PhoneAuthClient; } });
20
20
  __exportStar(require("./types"), exports);
@@ -37,11 +37,16 @@ Object.defineProperty(exports, "validateNonce", { enumerable: true, get: functio
37
37
  var mobile_debug_console_1 = require("./ui/mobile-debug-console");
38
38
  Object.defineProperty(exports, "MobileDebugConsole", { enumerable: true, get: function () { return mobile_debug_console_1.MobileDebugConsole; } });
39
39
  var type_guards_1 = require("./type-guards");
40
- Object.defineProperty(exports, "isHeadlessResult", { enumerable: true, get: function () { return type_guards_1.isHeadlessResult; } });
40
+ Object.defineProperty(exports, "isExtendedResponse", { enumerable: true, get: function () { return type_guards_1.isExtendedResponse; } });
41
41
  Object.defineProperty(exports, "isCredential", { enumerable: true, get: function () { return type_guards_1.isCredential; } });
42
+ Object.defineProperty(exports, "isAuthCredential", { enumerable: true, get: function () { return type_guards_1.isAuthCredential; } });
42
43
  Object.defineProperty(exports, "isLinkStrategy", { enumerable: true, get: function () { return type_guards_1.isLinkStrategy; } });
43
44
  Object.defineProperty(exports, "isTS43Strategy", { enumerable: true, get: function () { return type_guards_1.isTS43Strategy; } });
44
45
  Object.defineProperty(exports, "isDesktopStrategy", { enumerable: true, get: function () { return type_guards_1.isDesktopStrategy; } });
45
46
  Object.defineProperty(exports, "getStrategy", { enumerable: true, get: function () { return type_guards_1.getStrategy; } });
47
+ Object.defineProperty(exports, "hasPollingControls", { enumerable: true, get: function () { return type_guards_1.hasPollingControls; } });
48
+ Object.defineProperty(exports, "hasTrigger", { enumerable: true, get: function () { return type_guards_1.hasTrigger; } });
49
+ // Deprecated aliases
50
+ Object.defineProperty(exports, "isHeadlessResult", { enumerable: true, get: function () { return type_guards_1.isHeadlessResult; } });
46
51
  Object.defineProperty(exports, "requiresPolling", { enumerable: true, get: function () { return type_guards_1.requiresPolling; } });
47
52
  Object.defineProperty(exports, "requiresUserAction", { enumerable: true, get: function () { return type_guards_1.requiresUserAction; } });
@@ -55,6 +55,7 @@ export declare class DesktopHandler implements StrategyHandler {
55
55
  private pollingAttempts;
56
56
  private isCancelled;
57
57
  private onCancel?;
58
+ private pollingReject?;
58
59
  /**
59
60
  * Maps backend HTTP status codes to client status
60
61
  * @param httpStatus HTTP status code from backend
@@ -62,7 +62,20 @@ class DesktopHandler {
62
62
  if (desktopData && desktopData.data && typeof desktopData.data === 'object') {
63
63
  const innerData = desktopData.data;
64
64
  // Try to extract from inner data
65
- qrCode = innerData.qr_code_image || innerData.qr_code;
65
+ // Support both single QR (qr_code_image) and dual-platform QR (ios/android)
66
+ if (innerData.ios_qr_image || innerData.android_qr_image) {
67
+ // Dual-platform QR format
68
+ qrCode = {
69
+ iosQRCode: innerData.ios_qr_image,
70
+ androidQRCode: innerData.android_qr_image,
71
+ iosUrl: innerData.ios_url,
72
+ androidUrl: innerData.android_url
73
+ };
74
+ }
75
+ else {
76
+ // Single QR format (legacy)
77
+ qrCode = innerData.qr_code_image || innerData.qr_code;
78
+ }
66
79
  sessionId = innerData.session_id;
67
80
  pollingEndpoint = innerData.status_url;
68
81
  pollingInterval = innerData.polling_interval;
@@ -89,33 +102,44 @@ class DesktopHandler {
89
102
  options.onQRCodeReady(qrCode);
90
103
  }
91
104
  // Use polling endpoint with this priority:
92
- // 1. Developer-provided endpoint from options
105
+ // 1. Developer-provided endpoint from options (highest priority)
93
106
  // 2. Backend-provided endpoint
94
- // 3. Error if none available
95
- const finalPollingEndpoint = (options === null || options === void 0 ? void 0 : options.pollingEndpoint) || pollingEndpoint;
96
- // If no polling endpoint available, return QR code data and let the app handle the rest
107
+ // 3. Hardcoded fallback
108
+ console.log('[Desktop QR] Polling endpoint selection:');
109
+ console.log(' - options?.pollingEndpoint:', options === null || options === void 0 ? void 0 : options.pollingEndpoint);
110
+ console.log(' - backend pollingEndpoint:', pollingEndpoint);
111
+ let finalPollingEndpoint = options === null || options === void 0 ? void 0 : options.pollingEndpoint;
112
+ let endpointSource = 'options';
97
113
  if (!finalPollingEndpoint) {
98
- return {
99
- authenticated: false,
100
- session: data.session,
101
- error: 'No polling endpoint provided - configure endpoints.polling or ensure backend provides status_url'
102
- };
114
+ finalPollingEndpoint = pollingEndpoint; // Backend-provided status_url
115
+ endpointSource = 'backend';
103
116
  }
117
+ if (!finalPollingEndpoint) {
118
+ // Use hardcoded fallback - this will be constructed in the polling function
119
+ console.log('[Desktop QR] No polling endpoint provided, will use hardcoded fallback');
120
+ endpointSource = 'fallback';
121
+ }
122
+ console.log('[Desktop QR] Selected endpoint:', finalPollingEndpoint, 'from source:', endpointSource);
104
123
  // Start polling for authentication status
105
124
  const finalPollingInterval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || pollingInterval || 2000;
106
125
  const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 150; // Default to 5 minutes
107
- return this.startPolling(finalPollingEndpoint, sessionId, finalPollingInterval, maxAttempts, expiresIn || 300, // Default 5 minutes expiry
108
- options);
126
+ console.log(`[Desktop QR] Starting polling - endpoint source: ${endpointSource}, interval: ${finalPollingInterval}ms, max attempts: ${maxAttempts}`);
127
+ return this.startPolling(finalPollingEndpoint || '', // Pass empty string if undefined, will use fallback
128
+ sessionId, finalPollingInterval, maxAttempts, expiresIn || 300, // Default 5 minutes expiry
129
+ options, endpointSource // Pass the endpoint source for logging
130
+ );
109
131
  });
110
132
  }
111
133
  /**
112
134
  * Start polling for authentication status
113
135
  */
114
- startPolling(endpoint, sessionId, interval, maxAttempts, expiresIn, options) {
115
- return __awaiter(this, void 0, void 0, function* () {
136
+ startPolling(endpoint_1, sessionId_1, interval_1, maxAttempts_1, expiresIn_1, options_1) {
137
+ return __awaiter(this, arguments, void 0, function* (endpoint, sessionId, interval, maxAttempts, expiresIn, options, endpointSource = 'unknown') {
116
138
  const startTime = Date.now();
117
139
  const expiryTime = startTime + (expiresIn * 1000);
118
140
  return new Promise((resolve, reject) => {
141
+ // Store the reject function so we can call it from cancel()
142
+ this.pollingReject = reject;
119
143
  const poll = () => __awaiter(this, void 0, void 0, function* () {
120
144
  try {
121
145
  // Check if cancelled
@@ -130,9 +154,10 @@ class DesktopHandler {
130
154
  message: 'Authentication cancelled'
131
155
  });
132
156
  }
133
- resolve({
134
- authenticated: false,
135
- error: 'Authentication cancelled'
157
+ // Reject the promise with a cancellation error
158
+ reject({
159
+ code: 'USER_DENIED',
160
+ message: 'Authentication cancelled by user'
136
161
  });
137
162
  return;
138
163
  }
@@ -180,12 +205,19 @@ class DesktopHandler {
180
205
  const url = new URL(endpoint);
181
206
  statusUrl = `${url.protocol}//${url.host}/public/public/status/${sessionId}`;
182
207
  }
208
+ else if (endpoint && endpoint !== '') {
209
+ // Relative path provided (e.g. '/api/phone-auth/status')
210
+ // Append session ID to the provided endpoint
211
+ statusUrl = `${endpoint}/${sessionId}`;
212
+ }
183
213
  else {
184
- // Use relative path that will be proxied through the app's server
214
+ // No endpoint provided - use hardcoded fallback
185
215
  // This ensures it goes through the same domain and uses the app's API configuration
186
216
  statusUrl = `/api/phone-auth/status/${sessionId}`;
187
217
  }
188
218
  // Poll the public endpoint - no authentication required
219
+ console.log(`[Desktop QR] Polling status (attempt ${this.pollingAttempts}/${maxAttempts})`);
220
+ console.log(`[Desktop QR] Using ${endpointSource} endpoint: ${statusUrl}`);
189
221
  const response = yield fetch(statusUrl, {
190
222
  method: 'GET',
191
223
  headers: {
@@ -193,6 +225,7 @@ class DesktopHandler {
193
225
  // No Authorization header needed for public endpoint
194
226
  }
195
227
  });
228
+ console.log(`[Desktop QR] Status response: ${response.status} ${response.statusText}`);
196
229
  // Backend Status Code Mapping:
197
230
  // - 200 OK: Session exists (body has 'pending' or 'completed' status)
198
231
  // - 410 Gone: Session expired after timeout
@@ -220,6 +253,7 @@ class DesktopHandler {
220
253
  });
221
254
  }
222
255
  // Return the session data for next steps
256
+ this.pollingReject = undefined; // Clear the reject function on success
223
257
  resolve({
224
258
  authenticated: true,
225
259
  credential: result.credential || result.session_key || sessionId,
@@ -344,10 +378,12 @@ class DesktopHandler {
344
378
  */
345
379
  stopPolling() {
346
380
  if (this.pollingIntervalId) {
381
+ console.log('[Desktop QR] Stopping polling');
347
382
  clearInterval(this.pollingIntervalId);
348
383
  this.pollingIntervalId = undefined;
349
384
  }
350
385
  this.pollingAttempts = 0;
386
+ // Don't clear pollingReject here - it's needed by cancel()
351
387
  }
352
388
  /**
353
389
  * Format response for backend processing
@@ -379,15 +415,25 @@ class DesktopHandler {
379
415
  this.stopPolling();
380
416
  this.isCancelled = false;
381
417
  this.onCancel = undefined;
418
+ this.pollingReject = undefined;
382
419
  }
383
420
  /**
384
421
  * Cancel the ongoing authentication
385
422
  */
386
423
  cancel() {
387
424
  var _a;
425
+ console.log('[Desktop QR] Cancelling authentication');
388
426
  this.isCancelled = true;
389
427
  this.stopPolling();
390
428
  (_a = this.onCancel) === null || _a === void 0 ? void 0 : _a.call(this);
429
+ // Immediately reject the polling promise
430
+ if (this.pollingReject) {
431
+ this.pollingReject({
432
+ code: 'USER_DENIED',
433
+ message: 'Authentication cancelled by user'
434
+ });
435
+ this.pollingReject = undefined;
436
+ }
391
437
  }
392
438
  }
393
439
  exports.DesktopHandler = DesktopHandler;
@@ -26,12 +26,21 @@ class LinkHandler {
26
26
  */
27
27
  invoke(data, options) {
28
28
  return __awaiter(this, void 0, void 0, function* () {
29
+ console.log('[Link Auth] 🔗 SDK Version: 4.4.8-beta.2 (with enhanced error logging)');
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');
29
36
  // Extract link data from prepare response
30
37
  const linkData = data.data;
31
38
  if (!linkData || !linkData.url) {
32
39
  throw new Error('Invalid link data: missing URL');
33
40
  }
34
41
  const sessionKey = data.session.session_key;
42
+ console.log('[Link Auth] Session key:', sessionKey);
43
+ console.log('[Link Auth] Link URL:', linkData.url);
35
44
  // Open authentication app without navigating away from current page
36
45
  this.openAuthenticationLink(linkData.url);
37
46
  // Notify that link was opened
@@ -63,12 +72,19 @@ class LinkHandler {
63
72
  const interval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || 2000; // Fixed 2 second interval
64
73
  const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 150; // 5 minutes with 2s interval
65
74
  let attempts = 0;
75
+ console.log('[Link Auth] 🚀 Starting polling:', {
76
+ sessionKey,
77
+ interval: `${interval}ms`,
78
+ maxAttempts,
79
+ linkDataAvailable: !!linkData
80
+ });
66
81
  return new Promise((resolve, reject) => {
67
82
  this.isPolling = true;
68
83
  const poll = () => __awaiter(this, void 0, void 0, function* () {
69
84
  if (!this.isPolling) {
70
85
  return; // Polling was stopped
71
86
  }
87
+ let statusUrl = ''; // Declare at function scope for catch block access
72
88
  try {
73
89
  attempts++;
74
90
  // Check max attempts
@@ -87,16 +103,54 @@ class LinkHandler {
87
103
  return;
88
104
  }
89
105
  // Build public status endpoint URL
90
- let statusUrl;
91
- // First priority: use status_url from link data if provided
92
- if (linkData.status_url) {
93
- statusUrl = linkData.status_url;
94
- console.log('[Link Auth] Using status URL from link data:', statusUrl);
106
+ // Use the same priority logic as Desktop strategy:
107
+ // 1. options?.pollingEndpoint (already contains invoke options OR client config from client.ts)
108
+ // 2. Backend-provided status_url from linkData
109
+ // 3. Hardcoded fallback to API server
110
+ let endpoint = options === null || options === void 0 ? void 0 : options.pollingEndpoint;
111
+ let endpointSource = 'options';
112
+ if (!endpoint && linkData.status_url) {
113
+ endpoint = linkData.status_url;
114
+ endpointSource = 'backend';
115
+ }
116
+ console.log('[Link Auth] Polling endpoint selection:');
117
+ console.log(' - options?.pollingEndpoint:', options === null || options === void 0 ? void 0 : options.pollingEndpoint);
118
+ console.log(' - linkData.status_url:', linkData.status_url);
119
+ console.log(' - selected endpoint:', endpoint, 'from source:', endpointSource);
120
+ // Build the status URL based on endpoint format (same as Desktop)
121
+ if (endpoint && (endpoint.startsWith('http://') || endpoint.startsWith('https://'))) {
122
+ // Full URL provided
123
+ if (endpoint.includes('{{session_id}}')) {
124
+ statusUrl = endpoint.replace('{{session_id}}', sessionKey);
125
+ }
126
+ else if (!endpoint.includes(sessionKey)) {
127
+ // If it doesn't already contain the session ID, check if it's a base URL
128
+ const url = new URL(endpoint);
129
+ statusUrl = `${url.protocol}//${url.host}/public/public/status/${sessionKey}`;
130
+ }
131
+ else {
132
+ statusUrl = endpoint;
133
+ }
134
+ }
135
+ else if (endpoint && endpoint !== '') {
136
+ // Relative path provided (e.g. '/api/phone-auth/status')
137
+ const origin = typeof window !== 'undefined' ? window.location.origin : '';
138
+ if (endpoint.includes('{{session_id}}')) {
139
+ statusUrl = origin + endpoint.replace('{{session_id}}', sessionKey);
140
+ }
141
+ else {
142
+ // Append session ID to the provided endpoint
143
+ statusUrl = origin + endpoint + '/' + sessionKey;
144
+ }
95
145
  }
96
146
  else {
147
+ // No endpoint provided - use hardcoded fallback
97
148
  statusUrl = `https://api.glideidentity.app/public/public/status/${sessionKey}`;
149
+ endpointSource = 'fallback';
98
150
  }
151
+ console.log(`[Link Auth] Using ${endpointSource} endpoint: ${statusUrl}`);
99
152
  // Poll public status endpoint - no authentication required
153
+ console.log(`[Link Auth] Polling status (attempt ${attempts}/${maxAttempts}): ${statusUrl}`);
100
154
  const response = yield fetch(statusUrl, {
101
155
  method: 'GET',
102
156
  headers: {
@@ -104,12 +158,16 @@ class LinkHandler {
104
158
  // No Authorization header needed for public endpoint
105
159
  }
106
160
  });
161
+ console.log(`[Link Auth] Poll response - Status: ${response.status}, OK: ${response.ok}`);
107
162
  // Handle based on HTTP status code
108
163
  if (response.status === 200) {
109
164
  // Session is active (pending or completed)
110
165
  const result = yield response.json();
166
+ console.log('[Link Auth] Poll response data:', JSON.stringify(result, null, 2));
111
167
  if (result.status === 'completed') {
112
168
  // Authentication completed successfully
169
+ console.log('[Link Auth] ✅ Authentication COMPLETED! Session:', sessionKey);
170
+ console.log('[Link Auth] Full completion result:', JSON.stringify(result, null, 2));
113
171
  this.stopPolling();
114
172
  // Authentication completed successfully
115
173
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
@@ -134,6 +192,7 @@ class LinkHandler {
134
192
  }
135
193
  else if (result.status === 'pending') {
136
194
  // Continue polling
195
+ console.log('[Link Auth] Status still pending, continuing to poll...');
137
196
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
138
197
  options.onStatusUpdate({
139
198
  status: 'pending',
@@ -141,9 +200,14 @@ class LinkHandler {
141
200
  });
142
201
  }
143
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
+ }
144
207
  }
145
208
  else if (response.status === 410) {
146
209
  // Session expired
210
+ console.log('[Link Auth] ❌ Session expired (410)');
147
211
  this.stopPolling();
148
212
  const errorData = yield response.json().catch(() => ({ message: 'Session expired' }));
149
213
  if (options === null || options === void 0 ? void 0 : options.onTimeout) {
@@ -159,8 +223,10 @@ class LinkHandler {
159
223
  }
160
224
  else if (response.status === 422) {
161
225
  // Authentication failed
226
+ console.log('[Link Auth] ❌ Authentication failed (422)');
162
227
  this.stopPolling();
163
228
  const errorData = yield response.json().catch(() => ({ message: 'Authentication failed' }));
229
+ console.log('[Link Auth] Error data:', JSON.stringify(errorData, null, 2));
164
230
  const isUserCancelled = errorData.code === 'USER_CANCELLED';
165
231
  const errorMsg = isUserCancelled
166
232
  ? 'User cancelled authentication'
@@ -176,6 +242,7 @@ class LinkHandler {
176
242
  }
177
243
  else if (response.status === 404) {
178
244
  // Session not found
245
+ console.log('[Link Auth] ❌ Session not found (404)');
179
246
  this.stopPolling();
180
247
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
181
248
  options.onStatusUpdate({
@@ -187,16 +254,40 @@ class LinkHandler {
187
254
  }
188
255
  else if (response.status === 400) {
189
256
  // Invalid session key
257
+ console.log('[Link Auth] ❌ Invalid session key (400)');
190
258
  this.stopPolling();
191
259
  const errorData = yield response.json().catch(() => ({ message: 'Invalid session key' }));
260
+ console.log('[Link Auth] Error data:', JSON.stringify(errorData, null, 2));
192
261
  reject(new Error(errorData.message || 'Invalid session key'));
193
262
  }
194
263
  else {
195
264
  // Unexpected status - continue polling
265
+ console.log('[Link Auth] ⚠️ Unexpected HTTP status:', response.status, 'continuing to poll...');
266
+ try {
267
+ const body = yield response.text();
268
+ console.log('[Link Auth] Response body:', body);
269
+ }
270
+ catch (e) {
271
+ console.log('[Link Auth] Could not read response body');
272
+ }
196
273
  }
197
274
  }
198
275
  catch (error) {
199
276
  // Network or other error - continue polling
277
+ console.error('[Link Auth] 🔴 Polling error:', error.message || error);
278
+ console.error('[Link Auth] Error details:', {
279
+ name: error.name,
280
+ message: error.message,
281
+ stack: error.stack,
282
+ statusUrl: statusUrl,
283
+ attempt: attempts,
284
+ error: error
285
+ });
286
+ // Check if it's a CORS error (common on mobile)
287
+ if (error.message && error.message.toLowerCase().includes('failed')) {
288
+ console.error('[Link Auth] ⚠️ Possible CORS issue. Status URL:', statusUrl);
289
+ console.error('[Link Auth] Make sure the API endpoint allows CORS from your ngrok domain');
290
+ }
200
291
  if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
201
292
  options.onStatusUpdate({
202
293
  status: 'pending',
@@ -216,6 +307,7 @@ class LinkHandler {
216
307
  * Stop polling
217
308
  */
218
309
  stopPolling() {
310
+ console.log('[Link Auth] 🏁 Stopping polling');
219
311
  this.isPolling = false;
220
312
  if (this.pollingInterval) {
221
313
  clearInterval(this.pollingInterval);
@@ -4,29 +4,29 @@
4
4
  * These utilities help developers work with the SDK responses in a type-safe way
5
5
  * without having to write their own type checking logic.
6
6
  */
7
- import type { HeadlessResult } from './api-types';
7
+ import type { AnyExtendedResponse, DesktopExtendedResponse, LinkExtendedResponse, TS43ExtendedResponse, AuthCredential } from './api-types';
8
8
  /**
9
- * Type guard to check if the result is a HeadlessResult (headless mode)
10
- * or a Credential (UI mode).
9
+ * Type guard to check if the result is an ExtendedResponse (extended mode)
10
+ * or a Credential (standard mode).
11
11
  *
12
12
  * @example
13
13
  * ```typescript
14
- * const result = await invokeSecurePrompt(sdkRequest);
14
+ * const result = await invokeSecurePrompt(sdkRequest, { executionMode: 'extended' });
15
15
  *
16
- * if (isHeadlessResult(result)) {
17
- * // TypeScript knows this is HeadlessResult
16
+ * if (isExtendedResponse(result)) {
17
+ * // TypeScript knows this is ExtendedResponse
18
18
  * console.log(result.strategy);
19
- * await result.trigger();
19
+ * await result.cancel();
20
20
  * } else {
21
21
  * // TypeScript knows this is a Credential
22
22
  * const processedResult = await verifyPhoneNumberCredential(result, session);
23
23
  * }
24
24
  * ```
25
25
  */
26
- export declare function isHeadlessResult(result: any): result is HeadlessResult;
26
+ export declare function isExtendedResponse(result: any): result is AnyExtendedResponse;
27
27
  /**
28
- * Type guard to check if the result is a Credential (UI mode response).
29
- * A credential is either a string token or an object without HeadlessResult properties.
28
+ * Type guard to check if the result is a Credential (standard mode response).
29
+ * A credential is either a string token or an object without ExtendedResponse properties.
30
30
  *
31
31
  * @example
32
32
  * ```typescript
@@ -40,55 +40,61 @@ export declare function isCredential(result: any): result is string | {
40
40
  [aggregator_id: string]: string | string[];
41
41
  };
42
42
  /**
43
- * Type guard to check if a HeadlessResult is using the Link strategy.
43
+ * Type guard to check if the result is an AuthCredential object.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * if (isAuthCredential(result)) {
48
+ * console.log(result.credential);
49
+ * console.log(result.authenticated);
50
+ * }
51
+ * ```
52
+ */
53
+ export declare function isAuthCredential(result: any): result is AuthCredential;
54
+ /**
55
+ * Type guard to check if an ExtendedResponse is using the Link strategy.
44
56
  * Link strategy involves opening an app link (App Clip on iOS, app on Android).
45
57
  *
46
58
  * @example
47
59
  * ```typescript
48
- * if (isHeadlessResult(result) && isLinkStrategy(result)) {
49
- * // Show custom button for opening app
50
- * myButton.onclick = () => result.trigger();
51
- * await result.pollingPromise;
60
+ * if (isExtendedResponse(result) && isLinkStrategy(result)) {
61
+ * // Re-trigger app opening if needed
62
+ * result.trigger();
63
+ * await result.credential;
52
64
  * }
53
65
  * ```
54
66
  */
55
- export declare function isLinkStrategy(result: HeadlessResult): result is HeadlessResult & {
56
- strategy: 'link';
57
- };
67
+ export declare function isLinkStrategy(result: AnyExtendedResponse): result is LinkExtendedResponse;
58
68
  /**
59
- * Type guard to check if a HeadlessResult is using the TS43 strategy.
69
+ * Type guard to check if an ExtendedResponse is using the TS43 strategy.
60
70
  * TS43 strategy uses the browser's Digital Credentials API.
61
71
  *
62
72
  * @example
63
73
  * ```typescript
64
- * if (isHeadlessResult(result) && isTS43Strategy(result)) {
65
- * // Invoke credential API immediately or on button click
66
- * const credential = await result.trigger();
74
+ * if (isExtendedResponse(result) && isTS43Strategy(result)) {
75
+ * // Re-trigger credential request if needed
76
+ * await result.trigger();
67
77
  * }
68
78
  * ```
69
79
  */
70
- export declare function isTS43Strategy(result: HeadlessResult): result is HeadlessResult & {
71
- strategy: 'ts43';
72
- };
80
+ export declare function isTS43Strategy(result: AnyExtendedResponse): result is TS43ExtendedResponse;
73
81
  /**
74
- * Type guard to check if a HeadlessResult is using the Desktop strategy.
82
+ * Type guard to check if an ExtendedResponse is using the Desktop strategy.
75
83
  * Desktop strategy involves QR codes for cross-device authentication.
76
84
  *
77
85
  * @example
78
86
  * ```typescript
79
- * if (isHeadlessResult(result) && isDesktopStrategy(result)) {
87
+ * if (isExtendedResponse(result) && isDesktopStrategy(result)) {
80
88
  * // Show custom QR code UI
81
- * displayQRCode(result.qrCodeUrl);
82
- * await result.pollingPromise;
89
+ * displayQRCode(result.qr_code_data);
90
+ * await result.start_polling();
83
91
  * }
84
92
  * ```
85
93
  */
86
- export declare function isDesktopStrategy(result: HeadlessResult): result is HeadlessResult & {
87
- strategy: 'desktop';
88
- };
94
+ export declare function isDesktopStrategy(result: AnyExtendedResponse): result is DesktopExtendedResponse;
89
95
  /**
90
96
  * Helper function to safely get the authentication strategy from any result.
91
- * Returns undefined if the result is not a HeadlessResult.
97
+ * Returns undefined if the result is not an ExtendedResponse.
92
98
  *
93
99
  * @example
94
100
  * ```typescript
@@ -100,26 +106,38 @@ export declare function isDesktopStrategy(result: HeadlessResult): result is Hea
100
106
  */
101
107
  export declare function getStrategy(result: any): 'link' | 'ts43' | 'desktop' | undefined;
102
108
  /**
103
- * Helper function to determine if a result requires polling.
104
- * Link and Desktop strategies require polling, TS43 does not.
109
+ * Helper function to determine if a result has polling controls.
110
+ * Link and Desktop strategies have polling controls in extended mode.
105
111
  *
106
112
  * @example
107
113
  * ```typescript
108
- * if (requiresPolling(result)) {
109
- * await result.pollingPromise;
114
+ * if (hasPollingControls(result)) {
115
+ * await result.start_polling();
110
116
  * }
111
117
  * ```
112
118
  */
113
- export declare function requiresPolling(result: any): boolean;
119
+ export declare function hasPollingControls(result: any): boolean;
114
120
  /**
115
- * Helper function to determine if a result requires user interaction.
116
- * All headless strategies require some form of user interaction.
121
+ * Helper function to determine if a result has a trigger method.
122
+ * Link and TS43 strategies have trigger methods in extended mode.
117
123
  *
118
124
  * @example
119
125
  * ```typescript
120
- * if (requiresUserAction(result)) {
121
- * showActionButton();
126
+ * if (hasTrigger(result)) {
127
+ * result.trigger();
122
128
  * }
123
129
  * ```
124
130
  */
125
- export declare function requiresUserAction(result: any): boolean;
131
+ export declare function hasTrigger(result: any): boolean;
132
+ /**
133
+ * @deprecated Use isExtendedResponse instead
134
+ */
135
+ export declare const isHeadlessResult: typeof isExtendedResponse;
136
+ /**
137
+ * @deprecated Use hasPollingControls instead
138
+ */
139
+ export declare const requiresPolling: typeof hasPollingControls;
140
+ /**
141
+ * @deprecated This function is no longer needed as extended mode handles user actions differently
142
+ */
143
+ export declare const requiresUserAction: (result: any) => boolean;