@glideidentity/web-client-sdk 5.0.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -8
- package/dist/adapters/angular/index.js +0 -1
- package/dist/adapters/angular/phone-auth.service.d.ts +0 -18
- package/dist/adapters/angular/phone-auth.service.js +0 -26
- package/dist/adapters/react/index.js +0 -3
- package/dist/adapters/react/useClient.js +0 -1
- package/dist/adapters/react/usePhoneAuth.js +1 -16
- package/dist/adapters/vanilla/client.js +0 -1
- package/dist/adapters/vanilla/index.js +0 -1
- package/dist/adapters/vanilla/phone-auth.js +0 -31
- package/dist/adapters/vue/index.js +0 -4
- package/dist/adapters/vue/useClient.js +0 -5
- package/dist/adapters/vue/usePhoneAuth.js +1 -20
- package/dist/browser/web-client-sdk.min.js +1 -1
- package/dist/browser.js +0 -6
- package/dist/core/client.js +0 -12
- package/dist/core/logger.js +1 -81
- package/dist/core/phone-auth/api-types.js +0 -83
- package/dist/core/phone-auth/client.js +27 -366
- package/dist/core/phone-auth/error-utils.js +1 -83
- package/dist/core/phone-auth/index.js +0 -1
- package/dist/core/phone-auth/status-types.d.ts +0 -78
- package/dist/core/phone-auth/status-types.js +0 -17
- package/dist/core/phone-auth/strategies/desktop.js +8 -126
- package/dist/core/phone-auth/strategies/index.d.ts +0 -4
- package/dist/core/phone-auth/strategies/index.js +0 -4
- package/dist/core/phone-auth/strategies/link.js +10 -88
- package/dist/core/phone-auth/strategies/ts43.d.ts +0 -19
- package/dist/core/phone-auth/strategies/ts43.js +2 -33
- package/dist/core/phone-auth/strategies/types.js +0 -4
- package/dist/core/phone-auth/type-guards.js +0 -131
- package/dist/core/phone-auth/types.js +0 -32
- package/dist/core/phone-auth/ui/mobile-debug-console.js +2 -28
- package/dist/core/phone-auth/ui/modal.d.ts +33 -55
- package/dist/core/phone-auth/ui/modal.js +889 -422
- package/dist/core/phone-auth/validation-utils.js +2 -40
- package/dist/core/version.js +1 -2
- package/dist/esm/adapters/angular/index.js +0 -1
- package/dist/esm/adapters/angular/phone-auth.service.d.ts +0 -18
- package/dist/esm/adapters/angular/phone-auth.service.js +0 -26
- package/dist/esm/adapters/react/index.js +0 -3
- package/dist/esm/adapters/react/useClient.js +0 -1
- package/dist/esm/adapters/react/usePhoneAuth.js +1 -16
- package/dist/esm/adapters/vanilla/client.js +0 -1
- package/dist/esm/adapters/vanilla/index.js +0 -1
- package/dist/esm/adapters/vanilla/phone-auth.d.ts +0 -24
- package/dist/esm/adapters/vanilla/phone-auth.js +0 -31
- package/dist/esm/adapters/vue/index.js +0 -4
- package/dist/esm/adapters/vue/useClient.js +0 -5
- package/dist/esm/adapters/vue/usePhoneAuth.js +1 -20
- package/dist/esm/browser.js +0 -6
- package/dist/esm/core/client.d.ts +0 -10
- package/dist/esm/core/client.js +0 -12
- package/dist/esm/core/logger.d.ts +0 -53
- package/dist/esm/core/logger.js +1 -81
- package/dist/esm/core/phone-auth/api-types.d.ts +0 -315
- package/dist/esm/core/phone-auth/api-types.js +0 -83
- package/dist/esm/core/phone-auth/client.d.ts +0 -144
- package/dist/esm/core/phone-auth/client.js +27 -366
- package/dist/esm/core/phone-auth/error-utils.d.ts +0 -29
- package/dist/esm/core/phone-auth/error-utils.js +1 -83
- package/dist/esm/core/phone-auth/index.js +1 -3
- package/dist/esm/core/phone-auth/status-types.d.ts +0 -78
- package/dist/esm/core/phone-auth/status-types.js +0 -17
- package/dist/esm/core/phone-auth/strategies/desktop.d.ts +0 -63
- package/dist/esm/core/phone-auth/strategies/desktop.js +8 -126
- package/dist/esm/core/phone-auth/strategies/index.d.ts +0 -4
- package/dist/esm/core/phone-auth/strategies/index.js +0 -4
- package/dist/esm/core/phone-auth/strategies/link.d.ts +0 -48
- package/dist/esm/core/phone-auth/strategies/link.js +10 -88
- package/dist/esm/core/phone-auth/strategies/ts43.d.ts +0 -19
- package/dist/esm/core/phone-auth/strategies/ts43.js +2 -33
- package/dist/esm/core/phone-auth/strategies/types.d.ts +0 -13
- package/dist/esm/core/phone-auth/strategies/types.js +0 -4
- package/dist/esm/core/phone-auth/type-guards.d.ts +0 -128
- package/dist/esm/core/phone-auth/type-guards.js +0 -131
- package/dist/esm/core/phone-auth/types.d.ts +0 -108
- package/dist/esm/core/phone-auth/types.js +0 -32
- package/dist/esm/core/phone-auth/ui/mobile-debug-console.d.ts +0 -4
- package/dist/esm/core/phone-auth/ui/mobile-debug-console.js +2 -28
- package/dist/esm/core/phone-auth/ui/modal.d.ts +27 -68
- package/dist/esm/core/phone-auth/ui/modal.js +889 -422
- package/dist/esm/core/phone-auth/validation-utils.d.ts +0 -31
- package/dist/esm/core/phone-auth/validation-utils.js +2 -40
- package/dist/esm/core/types.d.ts +0 -35
- package/dist/esm/core/version.js +1 -2
- package/dist/esm/index.js +1 -9
- package/dist/index.js +0 -7
- package/package.json +1 -1
|
@@ -1,9 +1,4 @@
|
|
|
1
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
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -21,10 +16,6 @@ class LinkHandler {
|
|
|
21
16
|
this.isCancelled = false;
|
|
22
17
|
this.isPollingInProgress = false;
|
|
23
18
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Invoke link-based authentication
|
|
26
|
-
* Opens authentication app while keeping user on current page
|
|
27
|
-
*/
|
|
28
19
|
invoke(data, options) {
|
|
29
20
|
return __awaiter(this, void 0, void 0, function* () {
|
|
30
21
|
console.log('[Link Auth] 🔗 invoke() called with data:', JSON.stringify(data, null, 2));
|
|
@@ -33,7 +24,6 @@ class LinkHandler {
|
|
|
33
24
|
maxPollingAttempts: options.maxPollingAttempts,
|
|
34
25
|
pollingEndpoint: options.pollingEndpoint
|
|
35
26
|
}) : 'none');
|
|
36
|
-
// Extract link data from prepare response
|
|
37
27
|
const linkData = data.data;
|
|
38
28
|
if (!linkData || !linkData.url) {
|
|
39
29
|
throw new Error('Invalid link data: missing URL');
|
|
@@ -41,36 +31,23 @@ class LinkHandler {
|
|
|
41
31
|
const sessionKey = data.session.session_key;
|
|
42
32
|
console.log('[Link Auth] Session key:', sessionKey);
|
|
43
33
|
console.log('[Link Auth] Link URL:', linkData.url);
|
|
44
|
-
// Open authentication app without navigating away from current page
|
|
45
34
|
this.openAuthenticationLink(linkData.url);
|
|
46
|
-
// Notify that link was opened
|
|
47
35
|
if (options === null || options === void 0 ? void 0 : options.onLinkOpened) {
|
|
48
36
|
options.onLinkOpened();
|
|
49
37
|
}
|
|
50
|
-
// Start polling for authentication status
|
|
51
|
-
// Use constant interval (no exponential backoff)
|
|
52
38
|
return this.startPolling(sessionKey, linkData, options);
|
|
53
39
|
});
|
|
54
40
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Open authentication link without navigating away
|
|
57
|
-
*/
|
|
58
41
|
openAuthenticationLink(url) {
|
|
59
|
-
// Always use window.open - Works best for App Clips and Android deep links
|
|
60
|
-
// Must be called in direct response to user action to avoid popup blocker
|
|
61
42
|
const newWindow = window.open(url, '_blank');
|
|
62
43
|
if (!newWindow || newWindow.closed || typeof newWindow.closed === 'undefined') {
|
|
63
|
-
// Popup was blocked - this can happen if not called from user gesture
|
|
64
44
|
console.warn('[LinkHandler] Failed to open app link - popup may have been blocked');
|
|
65
45
|
}
|
|
66
46
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Start polling for authentication status with constant interval
|
|
69
|
-
*/
|
|
70
47
|
startPolling(sessionKey, linkData, options) {
|
|
71
48
|
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
-
const interval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || 2000;
|
|
73
|
-
const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 30;
|
|
49
|
+
const interval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || 2000;
|
|
50
|
+
const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 30;
|
|
74
51
|
let attempts = 0;
|
|
75
52
|
console.log('[Link Auth] 🚀 Starting polling:', {
|
|
76
53
|
sessionKey,
|
|
@@ -80,25 +57,22 @@ class LinkHandler {
|
|
|
80
57
|
});
|
|
81
58
|
return new Promise((resolve, reject) => {
|
|
82
59
|
this.isPollingActive = true;
|
|
83
|
-
this.pollingReject = reject;
|
|
60
|
+
this.pollingReject = reject;
|
|
84
61
|
const poll = () => __awaiter(this, void 0, void 0, function* () {
|
|
85
62
|
if (!this.isPollingActive) {
|
|
86
|
-
return;
|
|
63
|
+
return;
|
|
87
64
|
}
|
|
88
|
-
// Skip if another poll is already in progress
|
|
89
65
|
if (this.isPollingInProgress) {
|
|
90
66
|
return;
|
|
91
67
|
}
|
|
92
|
-
let statusUrl = '';
|
|
68
|
+
let statusUrl = '';
|
|
93
69
|
try {
|
|
94
70
|
this.isPollingInProgress = true;
|
|
95
|
-
// Check max attempts before making the request
|
|
96
71
|
if (attempts >= maxAttempts) {
|
|
97
72
|
this.stopPolling();
|
|
98
73
|
if (options === null || options === void 0 ? void 0 : options.onTimeout) {
|
|
99
74
|
options.onTimeout();
|
|
100
75
|
}
|
|
101
|
-
// Calculate actual timeout duration
|
|
102
76
|
const timeoutSeconds = Math.round((maxAttempts * interval) / 1000);
|
|
103
77
|
const timeoutMessage = timeoutSeconds >= 60
|
|
104
78
|
? `${Math.floor(timeoutSeconds / 60)} minute${Math.floor(timeoutSeconds / 60) > 1 ? 's' : ''}`
|
|
@@ -112,11 +86,6 @@ class LinkHandler {
|
|
|
112
86
|
reject(new Error(`Authentication timeout after ${timeoutMessage}`));
|
|
113
87
|
return;
|
|
114
88
|
}
|
|
115
|
-
// Build public status endpoint URL
|
|
116
|
-
// Use the same priority logic as Desktop strategy:
|
|
117
|
-
// 1. options?.pollingEndpoint (already contains invoke options OR client config from client.ts)
|
|
118
|
-
// 2. Backend-provided status_url from linkData
|
|
119
|
-
// 3. Hardcoded fallback to API server
|
|
120
89
|
let endpoint = options === null || options === void 0 ? void 0 : options.pollingEndpoint;
|
|
121
90
|
let endpointSource = 'options';
|
|
122
91
|
if (!endpoint && linkData.status_url) {
|
|
@@ -127,14 +96,11 @@ class LinkHandler {
|
|
|
127
96
|
console.log(' - options?.pollingEndpoint:', options === null || options === void 0 ? void 0 : options.pollingEndpoint);
|
|
128
97
|
console.log(' - linkData.status_url:', linkData.status_url);
|
|
129
98
|
console.log(' - selected endpoint:', endpoint, 'from source:', endpointSource);
|
|
130
|
-
// Build the status URL based on endpoint format (same as Desktop)
|
|
131
99
|
if (endpoint && (endpoint.startsWith('http://') || endpoint.startsWith('https://'))) {
|
|
132
|
-
// Full URL provided
|
|
133
100
|
if (endpoint.includes('{{session_id}}')) {
|
|
134
101
|
statusUrl = endpoint.replace('{{session_id}}', sessionKey);
|
|
135
102
|
}
|
|
136
103
|
else if (!endpoint.includes(sessionKey)) {
|
|
137
|
-
// If it doesn't already contain the session ID, check if it's a base URL
|
|
138
104
|
const url = new URL(endpoint);
|
|
139
105
|
statusUrl = `${url.protocol}//${url.host}/public/public/status/${sessionKey}`;
|
|
140
106
|
}
|
|
@@ -143,43 +109,34 @@ class LinkHandler {
|
|
|
143
109
|
}
|
|
144
110
|
}
|
|
145
111
|
else if (endpoint && endpoint !== '') {
|
|
146
|
-
// Relative path provided (e.g. '/api/phone-auth/status')
|
|
147
112
|
const origin = typeof window !== 'undefined' ? window.location.origin : '';
|
|
148
113
|
if (endpoint.includes('{{session_id}}')) {
|
|
149
114
|
statusUrl = origin + endpoint.replace('{{session_id}}', sessionKey);
|
|
150
115
|
}
|
|
151
116
|
else {
|
|
152
|
-
// Append session ID to the provided endpoint
|
|
153
117
|
statusUrl = origin + endpoint + '/' + sessionKey;
|
|
154
118
|
}
|
|
155
119
|
}
|
|
156
120
|
else {
|
|
157
|
-
// No endpoint provided - use hardcoded fallback
|
|
158
121
|
statusUrl = `https://api.glideidentity.app/public/public/status/${sessionKey}`;
|
|
159
122
|
endpointSource = 'fallback';
|
|
160
123
|
}
|
|
161
124
|
console.log(`[Link Auth] Using ${endpointSource} endpoint: ${statusUrl}`);
|
|
162
|
-
// Poll public status endpoint - no authentication required
|
|
163
125
|
console.log(`[Link Auth] Polling status (attempt ${attempts}/${maxAttempts}): ${statusUrl}`);
|
|
164
126
|
const response = yield fetch(statusUrl, {
|
|
165
127
|
method: 'GET',
|
|
166
128
|
headers: {
|
|
167
129
|
'Accept': 'application/json'
|
|
168
|
-
// No Authorization header needed for public endpoint
|
|
169
130
|
}
|
|
170
131
|
});
|
|
171
132
|
console.log(`[Link Auth] Poll response - Status: ${response.status}, OK: ${response.ok}`);
|
|
172
|
-
// Handle based on HTTP status code
|
|
173
133
|
if (response.status === 200) {
|
|
174
|
-
// Session is active (pending or completed)
|
|
175
134
|
const result = yield response.json();
|
|
176
135
|
console.log('[Link Auth] Poll response data:', JSON.stringify(result, null, 2));
|
|
177
136
|
if (result.status === 'completed') {
|
|
178
|
-
// Authentication completed successfully
|
|
179
137
|
console.log('[Link Auth] ✅ Authentication COMPLETED! Session:', sessionKey);
|
|
180
138
|
console.log('[Link Auth] Full completion result:', JSON.stringify(result, null, 2));
|
|
181
139
|
this.stopPolling();
|
|
182
|
-
// Authentication completed successfully
|
|
183
140
|
if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
|
|
184
141
|
options.onStatusUpdate({
|
|
185
142
|
status: 'authenticated',
|
|
@@ -187,8 +144,7 @@ class LinkHandler {
|
|
|
187
144
|
data: result
|
|
188
145
|
});
|
|
189
146
|
}
|
|
190
|
-
|
|
191
|
-
this.pollingReject = undefined; // Clear reject function on success
|
|
147
|
+
this.pollingReject = undefined;
|
|
192
148
|
resolve({
|
|
193
149
|
authenticated: true,
|
|
194
150
|
credential: result.credential || sessionKey,
|
|
@@ -202,9 +158,8 @@ class LinkHandler {
|
|
|
202
158
|
});
|
|
203
159
|
}
|
|
204
160
|
else if (result.status === 'pending') {
|
|
205
|
-
// Continue polling
|
|
206
161
|
console.log('[Link Auth] Status still pending, continuing to poll...');
|
|
207
|
-
attempts++;
|
|
162
|
+
attempts++;
|
|
208
163
|
if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
|
|
209
164
|
options.onStatusUpdate({
|
|
210
165
|
status: 'pending',
|
|
@@ -213,13 +168,11 @@ class LinkHandler {
|
|
|
213
168
|
}
|
|
214
169
|
}
|
|
215
170
|
else {
|
|
216
|
-
// Unexpected status value
|
|
217
171
|
console.log('[Link Auth] ⚠️ Unexpected status value:', result.status, 'Full result:', JSON.stringify(result, null, 2));
|
|
218
|
-
attempts++;
|
|
172
|
+
attempts++;
|
|
219
173
|
}
|
|
220
174
|
}
|
|
221
175
|
else if (response.status === 410) {
|
|
222
|
-
// Session expired
|
|
223
176
|
console.log('[Link Auth] ❌ Session expired (410)');
|
|
224
177
|
this.stopPolling();
|
|
225
178
|
const errorData = yield response.json().catch(() => ({ message: 'Session expired' }));
|
|
@@ -235,7 +188,6 @@ class LinkHandler {
|
|
|
235
188
|
reject(new Error(errorData.message || 'Session expired'));
|
|
236
189
|
}
|
|
237
190
|
else if (response.status === 422) {
|
|
238
|
-
// Authentication failed
|
|
239
191
|
console.log('[Link Auth] ❌ Authentication failed (422)');
|
|
240
192
|
this.stopPolling();
|
|
241
193
|
const errorData = yield response.json().catch(() => ({ message: 'Authentication failed' }));
|
|
@@ -244,7 +196,6 @@ class LinkHandler {
|
|
|
244
196
|
const errorMsg = isUserCancelled
|
|
245
197
|
? 'User cancelled authentication'
|
|
246
198
|
: (errorData.message || 'Verification failed');
|
|
247
|
-
// Authentication failed
|
|
248
199
|
if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
|
|
249
200
|
options.onStatusUpdate({
|
|
250
201
|
status: 'error',
|
|
@@ -254,7 +205,6 @@ class LinkHandler {
|
|
|
254
205
|
reject(new Error(errorMsg));
|
|
255
206
|
}
|
|
256
207
|
else if (response.status === 404) {
|
|
257
|
-
// Session not found
|
|
258
208
|
console.log('[Link Auth] ❌ Session not found (404)');
|
|
259
209
|
this.stopPolling();
|
|
260
210
|
if (options === null || options === void 0 ? void 0 : options.onStatusUpdate) {
|
|
@@ -266,7 +216,6 @@ class LinkHandler {
|
|
|
266
216
|
reject(new Error('Session not found'));
|
|
267
217
|
}
|
|
268
218
|
else if (response.status === 400) {
|
|
269
|
-
// Invalid session key
|
|
270
219
|
console.log('[Link Auth] ❌ Invalid session key (400)');
|
|
271
220
|
this.stopPolling();
|
|
272
221
|
const errorData = yield response.json().catch(() => ({ message: 'Invalid session key' }));
|
|
@@ -274,9 +223,8 @@ class LinkHandler {
|
|
|
274
223
|
reject(new Error(errorData.message || 'Invalid session key'));
|
|
275
224
|
}
|
|
276
225
|
else {
|
|
277
|
-
// Unexpected status - continue polling
|
|
278
226
|
console.log('[Link Auth] ⚠️ Unexpected HTTP status:', response.status, 'continuing to poll...');
|
|
279
|
-
attempts++;
|
|
227
|
+
attempts++;
|
|
280
228
|
try {
|
|
281
229
|
const body = yield response.text();
|
|
282
230
|
console.log('[Link Auth] Response body:', body);
|
|
@@ -287,9 +235,8 @@ class LinkHandler {
|
|
|
287
235
|
}
|
|
288
236
|
}
|
|
289
237
|
catch (error) {
|
|
290
|
-
// Network or other error - continue polling
|
|
291
238
|
console.error('[Link Auth] 🔴 Polling error:', error.message || error);
|
|
292
|
-
attempts++;
|
|
239
|
+
attempts++;
|
|
293
240
|
console.error('[Link Auth] Error details:', {
|
|
294
241
|
name: error.name,
|
|
295
242
|
message: error.message,
|
|
@@ -298,7 +245,6 @@ class LinkHandler {
|
|
|
298
245
|
attempt: attempts,
|
|
299
246
|
error: error
|
|
300
247
|
});
|
|
301
|
-
// Check if it's a CORS error (common on mobile)
|
|
302
248
|
if (error.message && error.message.toLowerCase().includes('failed')) {
|
|
303
249
|
console.error('[Link Auth] ⚠️ Possible CORS issue. Status URL:', statusUrl);
|
|
304
250
|
console.error('[Link Auth] Make sure the API endpoint allows CORS from your ngrok domain');
|
|
@@ -311,20 +257,14 @@ class LinkHandler {
|
|
|
311
257
|
}
|
|
312
258
|
}
|
|
313
259
|
finally {
|
|
314
|
-
// Always clear the polling flag when done
|
|
315
260
|
this.isPollingInProgress = false;
|
|
316
261
|
}
|
|
317
262
|
});
|
|
318
|
-
// Start initial poll immediately
|
|
319
263
|
poll();
|
|
320
|
-
// Set up constant interval polling (no backoff)
|
|
321
264
|
this.pollingInterval = setInterval(poll, interval);
|
|
322
265
|
});
|
|
323
266
|
});
|
|
324
267
|
}
|
|
325
|
-
/**
|
|
326
|
-
* Stop polling
|
|
327
|
-
*/
|
|
328
268
|
stopPolling() {
|
|
329
269
|
console.log('[Link Auth] 🏁 Stopping polling');
|
|
330
270
|
this.isPollingActive = false;
|
|
@@ -334,9 +274,6 @@ class LinkHandler {
|
|
|
334
274
|
this.pollingInterval = undefined;
|
|
335
275
|
}
|
|
336
276
|
}
|
|
337
|
-
/**
|
|
338
|
-
* Format response for backend processing
|
|
339
|
-
*/
|
|
340
277
|
formatResponse(response) {
|
|
341
278
|
if (!response.authenticated || !response.credential) {
|
|
342
279
|
throw new Error('Authentication not completed');
|
|
@@ -347,40 +284,25 @@ class LinkHandler {
|
|
|
347
284
|
type: 'link'
|
|
348
285
|
};
|
|
349
286
|
}
|
|
350
|
-
/**
|
|
351
|
-
* Check if link strategy is supported
|
|
352
|
-
* Returns true for mobile devices (iOS and Android)
|
|
353
|
-
*/
|
|
354
287
|
isSupported() {
|
|
355
|
-
// Link strategy is supported on mobile devices
|
|
356
288
|
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
|
357
289
|
return isMobile;
|
|
358
290
|
}
|
|
359
|
-
/**
|
|
360
|
-
* Clean up resources (stop polling if active)
|
|
361
|
-
*/
|
|
362
291
|
cleanup() {
|
|
363
292
|
this.stopPolling();
|
|
364
293
|
this.isCancelled = false;
|
|
365
294
|
this.onCancel = undefined;
|
|
366
295
|
this.pollingReject = undefined;
|
|
367
296
|
}
|
|
368
|
-
/**
|
|
369
|
-
* Check if polling is currently active
|
|
370
|
-
*/
|
|
371
297
|
isPolling() {
|
|
372
298
|
return this.pollingInterval !== undefined;
|
|
373
299
|
}
|
|
374
|
-
/**
|
|
375
|
-
* Cancel the ongoing authentication
|
|
376
|
-
*/
|
|
377
300
|
cancel() {
|
|
378
301
|
var _a;
|
|
379
302
|
console.log('[Link Auth] Cancelling authentication');
|
|
380
303
|
this.isCancelled = true;
|
|
381
304
|
this.stopPolling();
|
|
382
305
|
(_a = this.onCancel) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
383
|
-
// Immediately reject the polling promise
|
|
384
306
|
if (this.pollingReject) {
|
|
385
307
|
this.pollingReject({
|
|
386
308
|
code: 'USER_DENIED',
|
|
@@ -1,28 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TS-43 Strategy Handler
|
|
3
|
-
* Handles Digital Credentials API authentication for Android/Chromium
|
|
4
|
-
* Properly manages session objects with session_key, nonce, and enc_key
|
|
5
|
-
*/
|
|
6
1
|
import type { StrategyHandler } from './types';
|
|
7
2
|
import type { PrepareResponse } from '../types';
|
|
8
3
|
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
4
|
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
5
|
formatResponse(response: any): any;
|
|
19
|
-
/**
|
|
20
|
-
* Check if Digital Credentials API is supported
|
|
21
|
-
*/
|
|
22
6
|
isSupported(): boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Get browser support information
|
|
25
|
-
*/
|
|
26
7
|
getBrowserSupportInfo(): {
|
|
27
8
|
supported: boolean;
|
|
28
9
|
browser: string;
|
|
@@ -1,9 +1,4 @@
|
|
|
1
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, nonce, and enc_key
|
|
6
|
-
*/
|
|
7
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -16,43 +11,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
16
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
12
|
exports.TS43Handler = void 0;
|
|
18
13
|
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
14
|
invoke(data) {
|
|
24
15
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
// Validate session structure - only session_key is actually required
|
|
26
16
|
if (!data.session || !data.session.session_key) {
|
|
27
17
|
throw new Error('Invalid TS43 session: missing required session_key');
|
|
28
18
|
}
|
|
29
|
-
// Check if Digital Credentials API is available
|
|
30
19
|
if (!this.isSupported()) {
|
|
31
20
|
throw new Error('Digital Credentials API not supported in this browser');
|
|
32
21
|
}
|
|
33
|
-
// Extract TS43 data from the prepare response
|
|
34
22
|
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
23
|
const credentialRequest = {
|
|
38
24
|
digital: {
|
|
39
25
|
requests: [{
|
|
40
|
-
protocol: ts43Data.protocol,
|
|
41
|
-
data: ts43Data.data
|
|
26
|
+
protocol: ts43Data.protocol,
|
|
27
|
+
data: ts43Data.data
|
|
42
28
|
}]
|
|
43
29
|
}
|
|
44
30
|
};
|
|
45
31
|
try {
|
|
46
|
-
// @ts-ignore - Digital Credentials API types not yet in TypeScript
|
|
47
32
|
const credential = yield navigator.credentials.get(credentialRequest);
|
|
48
33
|
if (!credential) {
|
|
49
34
|
throw new Error('No credential received from Digital Credentials API');
|
|
50
35
|
}
|
|
51
|
-
// @ts-ignore - credential.data is not typed yet
|
|
52
36
|
return credential;
|
|
53
37
|
}
|
|
54
38
|
catch (error) {
|
|
55
|
-
// Handle browser-specific errors
|
|
56
39
|
if (error instanceof Error) {
|
|
57
40
|
if (error.name === 'NotAllowedError') {
|
|
58
41
|
throw new Error('User denied the authentication request');
|
|
@@ -68,13 +51,8 @@ class TS43Handler {
|
|
|
68
51
|
}
|
|
69
52
|
});
|
|
70
53
|
}
|
|
71
|
-
/**
|
|
72
|
-
* Format the credential response for backend processing
|
|
73
|
-
* Include the session key so backend can retrieve the full session
|
|
74
|
-
*/
|
|
75
54
|
formatResponse(response) {
|
|
76
55
|
var _a;
|
|
77
|
-
// Extract vp_token from the response
|
|
78
56
|
const vpToken = (_a = response.data) === null || _a === void 0 ? void 0 : _a.vp_token;
|
|
79
57
|
if (!vpToken) {
|
|
80
58
|
throw new Error('Invalid TS43 response: missing vp_token');
|
|
@@ -84,20 +62,12 @@ class TS43Handler {
|
|
|
84
62
|
type: 'ts43'
|
|
85
63
|
};
|
|
86
64
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Check if Digital Credentials API is supported
|
|
89
|
-
*/
|
|
90
65
|
isSupported() {
|
|
91
66
|
if (typeof window === 'undefined') {
|
|
92
67
|
return false;
|
|
93
68
|
}
|
|
94
|
-
// Check for DigitalCredential constructor
|
|
95
|
-
// @ts-ignore - DigitalCredential not yet in TypeScript
|
|
96
69
|
return 'DigitalCredential' in window;
|
|
97
70
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Get browser support information
|
|
100
|
-
*/
|
|
101
71
|
getBrowserSupportInfo() {
|
|
102
72
|
if (typeof window === 'undefined') {
|
|
103
73
|
return {
|
|
@@ -117,7 +87,6 @@ class TS43Handler {
|
|
|
117
87
|
browser: isChrome ? 'Chrome' : isEdge ? 'Edge' : 'Chromium'
|
|
118
88
|
};
|
|
119
89
|
}
|
|
120
|
-
// Provide specific guidance based on browser
|
|
121
90
|
if ((isChrome || isEdge) && isAndroid) {
|
|
122
91
|
return {
|
|
123
92
|
supported: false,
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Type Guards and Helper Functions for Phone Authentication
|
|
4
|
-
*
|
|
5
|
-
* These utilities help developers work with the SDK responses in a type-safe way
|
|
6
|
-
* without having to write their own type checking logic.
|
|
7
|
-
*/
|
|
8
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
3
|
exports.requiresUserAction = exports.requiresPolling = exports.isHeadlessResult = void 0;
|
|
10
4
|
exports.isExtendedResponse = isExtendedResponse;
|
|
@@ -16,24 +10,6 @@ exports.isDesktopStrategy = isDesktopStrategy;
|
|
|
16
10
|
exports.getStrategy = getStrategy;
|
|
17
11
|
exports.hasPollingControls = hasPollingControls;
|
|
18
12
|
exports.hasTrigger = hasTrigger;
|
|
19
|
-
/**
|
|
20
|
-
* Type guard to check if the result is an ExtendedResponse (extended mode)
|
|
21
|
-
* or a Credential (standard mode).
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* const result = await invokeSecurePrompt(sdkRequest, { executionMode: 'extended' });
|
|
26
|
-
*
|
|
27
|
-
* if (isExtendedResponse(result)) {
|
|
28
|
-
* // TypeScript knows this is ExtendedResponse
|
|
29
|
-
* console.log(result.strategy);
|
|
30
|
-
* await result.cancel();
|
|
31
|
-
* } else {
|
|
32
|
-
* // TypeScript knows this is a Credential
|
|
33
|
-
* const processedResult = await verifyPhoneNumberCredential(result, session);
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
13
|
function isExtendedResponse(result) {
|
|
38
14
|
return result &&
|
|
39
15
|
typeof result === 'object' &&
|
|
@@ -42,41 +18,16 @@ function isExtendedResponse(result) {
|
|
|
42
18
|
'cancel' in result &&
|
|
43
19
|
typeof result.cancel === 'function';
|
|
44
20
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Type guard to check if the result is a Credential (standard mode response).
|
|
47
|
-
* A credential is either a string token or an object without ExtendedResponse properties.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```typescript
|
|
51
|
-
* if (isCredential(result)) {
|
|
52
|
-
* // Process the credential directly
|
|
53
|
-
* const verified = await verifyPhoneNumberCredential(result, session);
|
|
54
|
-
* }
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
21
|
function isCredential(result) {
|
|
58
22
|
if (!result)
|
|
59
23
|
return false;
|
|
60
|
-
// String credentials are valid
|
|
61
24
|
if (typeof result === 'string')
|
|
62
25
|
return true;
|
|
63
|
-
// Object credentials should NOT have ExtendedResponse properties
|
|
64
26
|
if (typeof result === 'object') {
|
|
65
27
|
return !('strategy' in result) && !('credential' in result) && !('cancel' in result);
|
|
66
28
|
}
|
|
67
29
|
return false;
|
|
68
30
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Type guard to check if the result is an AuthCredential object.
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ```typescript
|
|
74
|
-
* if (isAuthCredential(result)) {
|
|
75
|
-
* console.log(result.credential);
|
|
76
|
-
* console.log(result.authenticated);
|
|
77
|
-
* }
|
|
78
|
-
* ```
|
|
79
|
-
*/
|
|
80
31
|
function isAuthCredential(result) {
|
|
81
32
|
return result &&
|
|
82
33
|
typeof result === 'object' &&
|
|
@@ -84,115 +35,33 @@ function isAuthCredential(result) {
|
|
|
84
35
|
'authenticated' in result &&
|
|
85
36
|
'session' in result;
|
|
86
37
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Type guard to check if an ExtendedResponse is using the Link strategy.
|
|
89
|
-
* Link strategy involves opening an app link (App Clip on iOS, app on Android).
|
|
90
|
-
*
|
|
91
|
-
* @example
|
|
92
|
-
* ```typescript
|
|
93
|
-
* if (isExtendedResponse(result) && isLinkStrategy(result)) {
|
|
94
|
-
* // Re-trigger app opening if needed
|
|
95
|
-
* result.trigger();
|
|
96
|
-
* await result.credential;
|
|
97
|
-
* }
|
|
98
|
-
* ```
|
|
99
|
-
*/
|
|
100
38
|
function isLinkStrategy(result) {
|
|
101
39
|
return result.strategy === 'link';
|
|
102
40
|
}
|
|
103
|
-
/**
|
|
104
|
-
* Type guard to check if an ExtendedResponse is using the TS43 strategy.
|
|
105
|
-
* TS43 strategy uses the browser's Digital Credentials API.
|
|
106
|
-
*
|
|
107
|
-
* @example
|
|
108
|
-
* ```typescript
|
|
109
|
-
* if (isExtendedResponse(result) && isTS43Strategy(result)) {
|
|
110
|
-
* // Re-trigger credential request if needed
|
|
111
|
-
* await result.trigger();
|
|
112
|
-
* }
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
41
|
function isTS43Strategy(result) {
|
|
116
42
|
return result.strategy === 'ts43';
|
|
117
43
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Type guard to check if an ExtendedResponse is using the Desktop strategy.
|
|
120
|
-
* Desktop strategy involves QR codes for cross-device authentication.
|
|
121
|
-
*
|
|
122
|
-
* @example
|
|
123
|
-
* ```typescript
|
|
124
|
-
* if (isExtendedResponse(result) && isDesktopStrategy(result)) {
|
|
125
|
-
* // Show custom QR code UI
|
|
126
|
-
* displayQRCode(result.qr_code_data);
|
|
127
|
-
* await result.start_polling();
|
|
128
|
-
* }
|
|
129
|
-
* ```
|
|
130
|
-
*/
|
|
131
44
|
function isDesktopStrategy(result) {
|
|
132
45
|
return result.strategy === 'desktop';
|
|
133
46
|
}
|
|
134
|
-
/**
|
|
135
|
-
* Helper function to safely get the authentication strategy from any result.
|
|
136
|
-
* Returns undefined if the result is not an ExtendedResponse.
|
|
137
|
-
*
|
|
138
|
-
* @example
|
|
139
|
-
* ```typescript
|
|
140
|
-
* const strategy = getStrategy(result);
|
|
141
|
-
* if (strategy === 'link') {
|
|
142
|
-
* // Handle link strategy
|
|
143
|
-
* }
|
|
144
|
-
* ```
|
|
145
|
-
*/
|
|
146
47
|
function getStrategy(result) {
|
|
147
48
|
if (isExtendedResponse(result)) {
|
|
148
49
|
return result.strategy;
|
|
149
50
|
}
|
|
150
51
|
return undefined;
|
|
151
52
|
}
|
|
152
|
-
/**
|
|
153
|
-
* Helper function to determine if a result has polling controls.
|
|
154
|
-
* Link and Desktop strategies have polling controls in extended mode.
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* ```typescript
|
|
158
|
-
* if (hasPollingControls(result)) {
|
|
159
|
-
* await result.start_polling();
|
|
160
|
-
* }
|
|
161
|
-
* ```
|
|
162
|
-
*/
|
|
163
53
|
function hasPollingControls(result) {
|
|
164
54
|
if (!isExtendedResponse(result))
|
|
165
55
|
return false;
|
|
166
56
|
return (result.strategy === 'link' && 'start_polling' in result) ||
|
|
167
57
|
(result.strategy === 'desktop' && 'start_polling' in result);
|
|
168
58
|
}
|
|
169
|
-
/**
|
|
170
|
-
* Helper function to determine if a result has a trigger method.
|
|
171
|
-
* Link and TS43 strategies have trigger methods in extended mode.
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* ```typescript
|
|
175
|
-
* if (hasTrigger(result)) {
|
|
176
|
-
* result.trigger();
|
|
177
|
-
* }
|
|
178
|
-
* ```
|
|
179
|
-
*/
|
|
180
59
|
function hasTrigger(result) {
|
|
181
60
|
if (!isExtendedResponse(result))
|
|
182
61
|
return false;
|
|
183
62
|
return 'trigger' in result && typeof result.trigger === 'function';
|
|
184
63
|
}
|
|
185
|
-
// Export legacy function names as deprecated aliases for backward compatibility
|
|
186
|
-
/**
|
|
187
|
-
* @deprecated Use isExtendedResponse instead
|
|
188
|
-
*/
|
|
189
64
|
exports.isHeadlessResult = isExtendedResponse;
|
|
190
|
-
/**
|
|
191
|
-
* @deprecated Use hasPollingControls instead
|
|
192
|
-
*/
|
|
193
65
|
exports.requiresPolling = hasPollingControls;
|
|
194
|
-
/**
|
|
195
|
-
* @deprecated This function is no longer needed as extended mode handles user actions differently
|
|
196
|
-
*/
|
|
197
66
|
const requiresUserAction = (result) => false;
|
|
198
67
|
exports.requiresUserAction = requiresUserAction;
|