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