@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.
- package/dist/adapters/react/usePhoneAuth.d.ts +1 -1
- package/dist/adapters/vue/useClient.d.ts +3 -3
- package/dist/adapters/vue/usePhoneAuth.d.ts +1 -1
- package/dist/browser/web-client-sdk.min.js +1 -1
- package/dist/core/phone-auth/api-types.d.ts +112 -27
- package/dist/core/phone-auth/client.d.ts +13 -11
- package/dist/core/phone-auth/client.js +263 -248
- package/dist/core/phone-auth/index.d.ts +1 -1
- package/dist/core/phone-auth/index.js +7 -2
- package/dist/core/phone-auth/strategies/desktop.d.ts +1 -0
- package/dist/core/phone-auth/strategies/desktop.js +64 -18
- package/dist/core/phone-auth/strategies/link.js +97 -5
- package/dist/core/phone-auth/type-guards.d.ts +61 -43
- package/dist/core/phone-auth/type-guards.js +82 -44
- package/dist/core/phone-auth/ui/modal.js +14 -1
- package/dist/core/version.js +1 -1
- package/dist/esm/adapters/react/usePhoneAuth.d.ts +1 -1
- package/dist/esm/adapters/vue/useClient.d.ts +3 -3
- package/dist/esm/adapters/vue/usePhoneAuth.d.ts +1 -1
- package/dist/esm/core/phone-auth/api-types.d.ts +112 -27
- package/dist/esm/core/phone-auth/client.d.ts +13 -11
- package/dist/esm/core/phone-auth/client.js +263 -248
- package/dist/esm/core/phone-auth/index.d.ts +1 -1
- package/dist/esm/core/phone-auth/index.js +3 -1
- package/dist/esm/core/phone-auth/strategies/desktop.d.ts +1 -0
- package/dist/esm/core/phone-auth/strategies/desktop.js +64 -18
- package/dist/esm/core/phone-auth/strategies/link.js +97 -5
- package/dist/esm/core/phone-auth/type-guards.d.ts +61 -43
- package/dist/esm/core/phone-auth/type-guards.js +76 -41
- package/dist/esm/core/phone-auth/ui/modal.js +14 -1
- package/dist/esm/core/version.js +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +3 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -2
- 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.
|
|
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, "
|
|
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
|
-
|
|
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.
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
99
|
-
|
|
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
|
-
|
|
108
|
-
|
|
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(
|
|
115
|
-
return __awaiter(this,
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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 {
|
|
7
|
+
import type { AnyExtendedResponse, DesktopExtendedResponse, LinkExtendedResponse, TS43ExtendedResponse, AuthCredential } from './api-types';
|
|
8
8
|
/**
|
|
9
|
-
* Type guard to check if the result is
|
|
10
|
-
* or a Credential (
|
|
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 (
|
|
17
|
-
* // TypeScript knows this is
|
|
16
|
+
* if (isExtendedResponse(result)) {
|
|
17
|
+
* // TypeScript knows this is ExtendedResponse
|
|
18
18
|
* console.log(result.strategy);
|
|
19
|
-
* await result.
|
|
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
|
|
26
|
+
export declare function isExtendedResponse(result: any): result is AnyExtendedResponse;
|
|
27
27
|
/**
|
|
28
|
-
* Type guard to check if the result is a Credential (
|
|
29
|
-
* A credential is either a string token or an object without
|
|
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
|
|
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 (
|
|
49
|
-
* //
|
|
50
|
-
*
|
|
51
|
-
* await result.
|
|
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:
|
|
56
|
-
strategy: 'link';
|
|
57
|
-
};
|
|
67
|
+
export declare function isLinkStrategy(result: AnyExtendedResponse): result is LinkExtendedResponse;
|
|
58
68
|
/**
|
|
59
|
-
* Type guard to check if
|
|
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 (
|
|
65
|
-
* //
|
|
66
|
-
*
|
|
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:
|
|
71
|
-
strategy: 'ts43';
|
|
72
|
-
};
|
|
80
|
+
export declare function isTS43Strategy(result: AnyExtendedResponse): result is TS43ExtendedResponse;
|
|
73
81
|
/**
|
|
74
|
-
* Type guard to check if
|
|
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 (
|
|
87
|
+
* if (isExtendedResponse(result) && isDesktopStrategy(result)) {
|
|
80
88
|
* // Show custom QR code UI
|
|
81
|
-
* displayQRCode(result.
|
|
82
|
-
* await result.
|
|
89
|
+
* displayQRCode(result.qr_code_data);
|
|
90
|
+
* await result.start_polling();
|
|
83
91
|
* }
|
|
84
92
|
* ```
|
|
85
93
|
*/
|
|
86
|
-
export declare function isDesktopStrategy(result:
|
|
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
|
|
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
|
|
104
|
-
* Link and Desktop strategies
|
|
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 (
|
|
109
|
-
* await result.
|
|
114
|
+
* if (hasPollingControls(result)) {
|
|
115
|
+
* await result.start_polling();
|
|
110
116
|
* }
|
|
111
117
|
* ```
|
|
112
118
|
*/
|
|
113
|
-
export declare function
|
|
119
|
+
export declare function hasPollingControls(result: any): boolean;
|
|
114
120
|
/**
|
|
115
|
-
* Helper function to determine if a result
|
|
116
|
-
*
|
|
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 (
|
|
121
|
-
*
|
|
126
|
+
* if (hasTrigger(result)) {
|
|
127
|
+
* result.trigger();
|
|
122
128
|
* }
|
|
123
129
|
* ```
|
|
124
130
|
*/
|
|
125
|
-
export declare function
|
|
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;
|