@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
|
@@ -18,7 +18,7 @@ import { LinkHandler } from './strategies/link';
|
|
|
18
18
|
import { AuthModal } from './ui/modal';
|
|
19
19
|
export class PhoneAuthClient {
|
|
20
20
|
constructor(config = {}) {
|
|
21
|
-
var _a, _b, _c;
|
|
21
|
+
var _a, _b, _c, _d;
|
|
22
22
|
this.crossDeviceActive = false;
|
|
23
23
|
this.retryCount = 0;
|
|
24
24
|
this.sessionCache = new Map();
|
|
@@ -28,7 +28,8 @@ export class PhoneAuthClient {
|
|
|
28
28
|
this.config = {
|
|
29
29
|
endpoints: {
|
|
30
30
|
prepare: ((_a = config.endpoints) === null || _a === void 0 ? void 0 : _a.prepare) || '/api/magic-auth/prepare',
|
|
31
|
-
process: ((_b = config.endpoints) === null || _b === void 0 ? void 0 : _b.process) || '/api/magic-auth/process'
|
|
31
|
+
process: ((_b = config.endpoints) === null || _b === void 0 ? void 0 : _b.process) || '/api/magic-auth/process',
|
|
32
|
+
polling: (_c = config.endpoints) === null || _c === void 0 ? void 0 : _c.polling // Pass through the polling endpoint
|
|
32
33
|
},
|
|
33
34
|
timeout: config.timeout || 30000,
|
|
34
35
|
pollingInterval: config.pollingInterval || 2000, // Default 2 seconds
|
|
@@ -51,7 +52,7 @@ export class PhoneAuthClient {
|
|
|
51
52
|
custom: config.logger
|
|
52
53
|
});
|
|
53
54
|
// Initialize developer tools if configured
|
|
54
|
-
if (((
|
|
55
|
+
if (((_d = config.devtools) === null || _d === void 0 ? void 0 : _d.showMobileConsole) && typeof window !== 'undefined') {
|
|
55
56
|
import('./ui/mobile-debug-console').then(({ MobileDebugConsole }) => {
|
|
56
57
|
MobileDebugConsole.init();
|
|
57
58
|
console.log('[PhoneAuth] Mobile debug console enabled');
|
|
@@ -451,23 +452,25 @@ export class PhoneAuthClient {
|
|
|
451
452
|
* });
|
|
452
453
|
* ```
|
|
453
454
|
*
|
|
454
|
-
* @example
|
|
455
|
+
* @example Extended Mode (returns control methods)
|
|
455
456
|
* ```typescript
|
|
456
|
-
* // Get
|
|
457
|
+
* // Get control methods for custom implementation
|
|
457
458
|
* const result = await phoneAuth.invokeSecurePrompt(prepareResult, {
|
|
458
|
-
*
|
|
459
|
+
* executionMode: 'extended',
|
|
460
|
+
* preventDefaultUI: true // Desktop: no modal
|
|
459
461
|
* });
|
|
460
462
|
*
|
|
461
|
-
* if (result.strategy === '
|
|
462
|
-
* //
|
|
463
|
-
*
|
|
464
|
-
*
|
|
463
|
+
* if (result.strategy === 'desktop') {
|
|
464
|
+
* // Show custom QR UI
|
|
465
|
+
* showCustomQR(result.qr_code_data);
|
|
466
|
+
* // Start polling
|
|
467
|
+
* await result.start_polling();
|
|
465
468
|
* }
|
|
466
469
|
* ```
|
|
467
470
|
*
|
|
468
471
|
* @param prepareResponse - Response from prepare() with strategy and data
|
|
469
|
-
* @param options - Control UI behavior
|
|
470
|
-
* @returns Credential or
|
|
472
|
+
* @param options - Control UI behavior and response type
|
|
473
|
+
* @returns Credential or ExtendedResponse based on executionMode
|
|
471
474
|
*/
|
|
472
475
|
invokeSecurePrompt(prepareResponse, options) {
|
|
473
476
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -475,7 +478,7 @@ export class PhoneAuthClient {
|
|
|
475
478
|
// This ensures we work with plain objects for browser APIs
|
|
476
479
|
// Vue's reactivity system wraps objects in Proxies which can interfere
|
|
477
480
|
// with browser APIs like Digital Credentials API that expect plain objects
|
|
478
|
-
var _a, _b, _c;
|
|
481
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
479
482
|
// Try structuredClone first (modern browsers), but catch errors and fallback to JSON method
|
|
480
483
|
let plainResponse;
|
|
481
484
|
try {
|
|
@@ -495,16 +498,17 @@ export class PhoneAuthClient {
|
|
|
495
498
|
console.log('[PhoneAuth] Session cache size:', this.sessionCache.size);
|
|
496
499
|
console.log('[PhoneAuth] Retry count:', this.retryCount);
|
|
497
500
|
console.log('[PhoneAuth] PrepareResponse received:', JSON.stringify(plainResponse, null, 2));
|
|
498
|
-
// Check if we're
|
|
501
|
+
// Check if we're using new InvokeOptions format
|
|
499
502
|
// Properly detect InvokeOptions by checking for any of its properties
|
|
500
|
-
const invokeOptions = options && ('
|
|
503
|
+
const invokeOptions = options && ('preventDefaultUI' in options ||
|
|
504
|
+
'executionMode' in options ||
|
|
501
505
|
'theme' in options ||
|
|
502
506
|
'modalOptions' in options ||
|
|
503
507
|
'callbacks' in options) ? options : undefined;
|
|
504
|
-
//
|
|
508
|
+
// Get configuration from options
|
|
505
509
|
const strategy = plainResponse.authentication_strategy;
|
|
506
|
-
const
|
|
507
|
-
const
|
|
510
|
+
const preventDefaultUI = (_a = invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.preventDefaultUI) !== null && _a !== void 0 ? _a : false;
|
|
511
|
+
const executionMode = (_b = invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.executionMode) !== null && _b !== void 0 ? _b : 'standard';
|
|
508
512
|
// DesktopAuthOptions is only used if not InvokeOptions
|
|
509
513
|
const desktopOptions = options && !invokeOptions ? options : undefined;
|
|
510
514
|
// Handle based on authentication strategy
|
|
@@ -643,270 +647,281 @@ export class PhoneAuthClient {
|
|
|
643
647
|
throw error;
|
|
644
648
|
}
|
|
645
649
|
});
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
650
|
+
// TS43 always auto-triggers (no SDK UI ever)
|
|
651
|
+
// The Digital Credentials API provides its own OS-level UI
|
|
652
|
+
let credentialPromise;
|
|
653
|
+
try {
|
|
654
|
+
// Always try to trigger immediately
|
|
655
|
+
const vpToken = yield enhancedTriggerTS43();
|
|
656
|
+
// Convert to AuthCredential format
|
|
657
|
+
credentialPromise = Promise.resolve({
|
|
658
|
+
credential: typeof vpToken === 'string' ? vpToken : Object.values(vpToken)[0],
|
|
659
|
+
session: plainResponse.session,
|
|
660
|
+
authenticated: true
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
catch (error) {
|
|
664
|
+
// If auto-trigger fails, create a rejected promise
|
|
665
|
+
credentialPromise = Promise.reject(error);
|
|
666
|
+
}
|
|
667
|
+
// Handle based on execution mode
|
|
668
|
+
if (executionMode === 'extended') {
|
|
669
|
+
// Extended mode - return control methods
|
|
665
670
|
return {
|
|
666
|
-
strategy:
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
671
|
+
strategy: 'ts43',
|
|
672
|
+
session: plainResponse.session,
|
|
673
|
+
credential: credentialPromise,
|
|
674
|
+
// Re-trigger credential request
|
|
675
|
+
trigger: () => __awaiter(this, void 0, void 0, function* () {
|
|
676
|
+
const vpToken = yield enhancedTriggerTS43();
|
|
677
|
+
// Update the credential promise
|
|
678
|
+
credentialPromise = Promise.resolve({
|
|
679
|
+
credential: typeof vpToken === 'string' ? vpToken : Object.values(vpToken)[0],
|
|
680
|
+
session: plainResponse.session,
|
|
681
|
+
authenticated: true
|
|
682
|
+
});
|
|
683
|
+
}),
|
|
684
|
+
cancel: () => {
|
|
685
|
+
// TS43 doesn't have a way to cancel once triggered
|
|
686
|
+
// but we can reject the promise
|
|
687
|
+
credentialPromise = Promise.reject(this.createError(PhoneAuthErrorCode.USER_DENIED, 'Authentication cancelled'));
|
|
688
|
+
}
|
|
670
689
|
};
|
|
671
690
|
}
|
|
672
691
|
else {
|
|
673
|
-
//
|
|
674
|
-
//
|
|
675
|
-
|
|
692
|
+
// Standard mode - just return credential
|
|
693
|
+
// Wait for and return the credential
|
|
694
|
+
const credential = yield credentialPromise;
|
|
695
|
+
// Return in standard format
|
|
696
|
+
return {
|
|
697
|
+
[plainResponse.session.session_key]: credential.credential
|
|
698
|
+
};
|
|
676
699
|
}
|
|
677
700
|
}
|
|
678
701
|
else if (plainResponse.authentication_strategy === API.AUTHENTICATION_STRATEGY.DESKTOP) {
|
|
679
702
|
// Desktop strategy - QR code based authentication
|
|
680
703
|
const desktopData = plainResponse.data;
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
704
|
+
const handler = new DesktopHandler();
|
|
705
|
+
// Extract QR code data - convert to QRCodeData format for modal
|
|
706
|
+
const qrCodeData = {
|
|
707
|
+
iosQRCode: ((_c = desktopData.data) === null || _c === void 0 ? void 0 : _c.ios_qr_image) || desktopData.ios_qr_image ||
|
|
708
|
+
((_d = desktopData.data) === null || _d === void 0 ? void 0 : _d.qr_code_image) || desktopData.qr_code_image || desktopData.qr_code || '',
|
|
709
|
+
androidQRCode: ((_e = desktopData.data) === null || _e === void 0 ? void 0 : _e.android_qr_image) || desktopData.android_qr_image,
|
|
710
|
+
iosUrl: ((_f = desktopData.data) === null || _f === void 0 ? void 0 : _f.ios_url) || desktopData.ios_url,
|
|
711
|
+
androidUrl: ((_g = desktopData.data) === null || _g === void 0 ? void 0 : _g.android_url) || desktopData.android_url
|
|
712
|
+
};
|
|
713
|
+
// Also keep snake_case format for extended response
|
|
714
|
+
const qrCodeDataSnakeCase = {
|
|
715
|
+
ios_qr_image: ((_h = desktopData.data) === null || _h === void 0 ? void 0 : _h.ios_qr_image) || desktopData.ios_qr_image,
|
|
716
|
+
android_qr_image: ((_j = desktopData.data) === null || _j === void 0 ? void 0 : _j.android_qr_image) || desktopData.android_qr_image,
|
|
717
|
+
qr_code: ((_k = desktopData.data) === null || _k === void 0 ? void 0 : _k.qr_code_image) || desktopData.qr_code_image || desktopData.qr_code,
|
|
718
|
+
challenge: (_l = desktopData.data) === null || _l === void 0 ? void 0 : _l.challenge
|
|
719
|
+
};
|
|
720
|
+
// Polling options
|
|
721
|
+
const pollingEndpointToUse = (invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.pollingEndpoint) ||
|
|
722
|
+
(desktopOptions === null || desktopOptions === void 0 ? void 0 : desktopOptions.pollingEndpoint) ||
|
|
723
|
+
((_m = this.config.endpoints) === null || _m === void 0 ? void 0 : _m.polling);
|
|
724
|
+
const pollingOptions = Object.assign(Object.assign({}, desktopOptions), { pollingEndpoint: pollingEndpointToUse, pollingInterval: (invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.pollingInterval) || (desktopOptions === null || desktopOptions === void 0 ? void 0 : desktopOptions.pollingInterval) || this.config.pollingInterval || 2000, maxPollingAttempts: (invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.maxPollingAttempts) || (desktopOptions === null || desktopOptions === void 0 ? void 0 : desktopOptions.maxPollingAttempts) || this.config.maxPollingAttempts || 150, onQRCodeReady: undefined, onStatusUpdate: undefined });
|
|
725
|
+
// Decide whether to show modal based on preventDefaultUI
|
|
726
|
+
const showModal = !preventDefaultUI;
|
|
727
|
+
let modal;
|
|
728
|
+
let modalRef = undefined;
|
|
729
|
+
console.log('[Desktop] Modal decision:', {
|
|
730
|
+
preventDefaultUI,
|
|
731
|
+
showModal,
|
|
732
|
+
executionMode,
|
|
733
|
+
hasInvokeOptions: !!invokeOptions,
|
|
734
|
+
hasDesktopOptions: !!desktopOptions
|
|
735
|
+
});
|
|
736
|
+
if (showModal) {
|
|
737
|
+
console.log('[Desktop] Creating modal with QR data:', qrCodeData);
|
|
738
|
+
// Create and setup modal
|
|
739
|
+
modal = new AuthModal(invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.modalOptions, invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.callbacks);
|
|
740
|
+
modal.setCloseCallback(() => {
|
|
741
|
+
this.log('Desktop QR modal closed by user, cancelling polling');
|
|
742
|
+
handler.cancel();
|
|
743
|
+
});
|
|
744
|
+
// Add UI callbacks to polling options
|
|
745
|
+
pollingOptions.onQRCodeReady = (qrData) => {
|
|
746
|
+
console.log('[Desktop] onQRCodeReady callback triggered:', qrData);
|
|
747
|
+
modal.showQRCode(qrData, 'Scan with your mobile device');
|
|
748
|
+
};
|
|
749
|
+
pollingOptions.onStatusUpdate = (status) => {
|
|
750
|
+
if (status.status === 'pending') {
|
|
751
|
+
modal.updateStatus('Waiting for authentication...');
|
|
752
|
+
}
|
|
753
|
+
else if (status.status === 'authenticated') {
|
|
754
|
+
modal.updateStatus('Authentication successful!');
|
|
755
|
+
setTimeout(() => modal.close(), 1500);
|
|
709
756
|
}
|
|
710
|
-
else {
|
|
711
|
-
|
|
757
|
+
else if (status.status === 'expired') {
|
|
758
|
+
modal.updateStatus('QR code expired', true);
|
|
712
759
|
}
|
|
760
|
+
else if (status.status === 'error') {
|
|
761
|
+
modal.updateStatus('Authentication failed', true);
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
// Note: We don't show the QR code here. It will be shown by the onQRCodeReady callback
|
|
765
|
+
// that gets triggered immediately when handler.invoke() is called
|
|
766
|
+
modalRef = modal;
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
console.log('[Desktop] Modal not shown - preventDefaultUI is true');
|
|
770
|
+
}
|
|
771
|
+
// Create credential promise
|
|
772
|
+
const startPolling = () => handler.invoke(plainResponse, pollingOptions).then(result => {
|
|
773
|
+
if (result.authenticated && result.credential) {
|
|
774
|
+
return {
|
|
775
|
+
credential: result.credential,
|
|
776
|
+
session: plainResponse.session,
|
|
777
|
+
authenticated: true
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
throw this.createError(PhoneAuthErrorCode.USER_DENIED, result.error || 'Desktop authentication failed');
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
// Handle based on execution mode
|
|
785
|
+
if (executionMode === 'extended') {
|
|
786
|
+
// Extended mode - return control methods
|
|
787
|
+
const credentialPromise = showModal ? startPolling() : Promise.resolve({
|
|
788
|
+
credential: '',
|
|
789
|
+
session: plainResponse.session,
|
|
790
|
+
authenticated: false
|
|
713
791
|
});
|
|
714
792
|
return {
|
|
715
|
-
strategy:
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
793
|
+
strategy: 'desktop',
|
|
794
|
+
session: plainResponse.session,
|
|
795
|
+
credential: credentialPromise,
|
|
796
|
+
qr_code_data: qrCodeDataSnakeCase,
|
|
797
|
+
modal_ref: modalRef,
|
|
798
|
+
start_polling: startPolling,
|
|
799
|
+
stop_polling: () => {
|
|
800
|
+
handler.cleanup();
|
|
801
|
+
if (modal)
|
|
802
|
+
modal.close();
|
|
803
|
+
},
|
|
804
|
+
cancel: () => {
|
|
805
|
+
handler.cancel();
|
|
806
|
+
handler.cleanup();
|
|
807
|
+
if (modal)
|
|
808
|
+
modal.close();
|
|
809
|
+
},
|
|
810
|
+
is_polling: showModal // If modal shown, polling already started
|
|
719
811
|
};
|
|
720
812
|
}
|
|
721
813
|
else {
|
|
722
|
-
//
|
|
723
|
-
|
|
724
|
-
const modal = new AuthModal(invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.modalOptions, invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.callbacks);
|
|
725
|
-
// Default options with modal display
|
|
726
|
-
const options = Object.assign(Object.assign({}, desktopOptions), {
|
|
727
|
-
// Don't pass config.endpoints.polling - let backend-provided status_url take priority
|
|
728
|
-
// Only explicit desktopOptions.pollingEndpoint will override backend URL
|
|
729
|
-
pollingInterval: (desktopOptions === null || desktopOptions === void 0 ? void 0 : desktopOptions.pollingInterval) || this.config.pollingInterval || 2000, maxPollingAttempts: (desktopOptions === null || desktopOptions === void 0 ? void 0 : desktopOptions.maxPollingAttempts) || this.config.maxPollingAttempts || 150, onQRCodeReady: (qrCodeData) => {
|
|
730
|
-
// Show QR code in modal (supports both single and dual-platform)
|
|
731
|
-
modal.showQRCode(qrCodeData, 'Scan with your mobile device');
|
|
732
|
-
}, onStatusUpdate: (status) => {
|
|
733
|
-
// Update status in modal
|
|
734
|
-
if (status.status === 'pending') {
|
|
735
|
-
modal.updateStatus('Waiting for authentication...');
|
|
736
|
-
}
|
|
737
|
-
else if (status.status === 'authenticated') {
|
|
738
|
-
modal.updateStatus('Authentication successful!');
|
|
739
|
-
setTimeout(() => modal.close(), 1500);
|
|
740
|
-
}
|
|
741
|
-
else if (status.status === 'expired') {
|
|
742
|
-
modal.updateStatus('QR code expired', true);
|
|
743
|
-
}
|
|
744
|
-
else if (status.status === 'error') {
|
|
745
|
-
modal.updateStatus('Authentication failed', true);
|
|
746
|
-
}
|
|
747
|
-
} });
|
|
814
|
+
// Standard mode - return credential when complete
|
|
815
|
+
// Start polling and wait for result
|
|
748
816
|
try {
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
759
|
-
// Also check flat structure
|
|
760
|
-
if (!sessionId || sessionId === 'default') {
|
|
761
|
-
sessionId = desktopData.session_id || sessionId;
|
|
762
|
-
}
|
|
817
|
+
const credential = yield startPolling();
|
|
818
|
+
// Extract session ID for compatibility
|
|
819
|
+
let sessionId = 'default';
|
|
820
|
+
if (desktopData && typeof desktopData === 'object') {
|
|
821
|
+
if (desktopData.data && typeof desktopData.data === 'object') {
|
|
822
|
+
sessionId = desktopData.data.session_id || sessionId;
|
|
823
|
+
}
|
|
824
|
+
if (!sessionId || sessionId === 'default') {
|
|
825
|
+
sessionId = desktopData.session_id || sessionId;
|
|
763
826
|
}
|
|
764
|
-
// Return credential in expected format for subsequent API calls
|
|
765
|
-
return {
|
|
766
|
-
[sessionId]: result.credential
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
else {
|
|
770
|
-
throw this.createError(PhoneAuthErrorCode.USER_DENIED, result.error || 'Desktop authentication failed');
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
catch (error) {
|
|
774
|
-
if (error instanceof Error && error.name === 'PhoneAuthError') {
|
|
775
|
-
throw error;
|
|
776
827
|
}
|
|
777
|
-
|
|
828
|
+
return { [sessionId]: credential.credential };
|
|
778
829
|
}
|
|
779
830
|
finally {
|
|
780
|
-
// Ensure handler cleanup
|
|
781
831
|
handler.cleanup();
|
|
782
|
-
modal
|
|
832
|
+
if (modal)
|
|
833
|
+
modal.close();
|
|
783
834
|
}
|
|
784
835
|
}
|
|
785
836
|
}
|
|
786
837
|
else if (plainResponse.authentication_strategy === API.AUTHENTICATION_STRATEGY.LINK) {
|
|
787
838
|
// Link strategy - app-based authentication (iOS/Android)
|
|
788
839
|
const linkData = plainResponse.data;
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
strategy: API.AUTHENTICATION_STRATEGY.LINK,
|
|
801
|
-
url: linkData.url,
|
|
802
|
-
success: true
|
|
803
|
-
});
|
|
804
|
-
}
|
|
805
|
-
catch (error) {
|
|
806
|
-
(_b = invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.onTriggerAttempt) === null || _b === void 0 ? void 0 : _b.call(invokeOptions, {
|
|
807
|
-
strategy: API.AUTHENTICATION_STRATEGY.LINK,
|
|
808
|
-
url: linkData.url,
|
|
809
|
-
success: false,
|
|
810
|
-
error
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
};
|
|
814
|
-
// Auto-trigger by default for Link strategy
|
|
815
|
-
// This opens the App Clip immediately while preserving user gesture context
|
|
816
|
-
if ((invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.autoTrigger) !== false) {
|
|
817
|
-
triggerLink();
|
|
840
|
+
const handler = new LinkHandler();
|
|
841
|
+
// Create reusable trigger function that ONLY opens the App Clip
|
|
842
|
+
const triggerLink = () => {
|
|
843
|
+
var _a, _b;
|
|
844
|
+
try {
|
|
845
|
+
window.open(linkData.url, '_blank');
|
|
846
|
+
(_a = invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.onTriggerAttempt) === null || _a === void 0 ? void 0 : _a.call(invokeOptions, {
|
|
847
|
+
strategy: API.AUTHENTICATION_STRATEGY.LINK,
|
|
848
|
+
url: linkData.url,
|
|
849
|
+
success: true
|
|
850
|
+
});
|
|
818
851
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
852
|
+
catch (error) {
|
|
853
|
+
(_b = invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.onTriggerAttempt) === null || _b === void 0 ? void 0 : _b.call(invokeOptions, {
|
|
854
|
+
strategy: API.AUTHENTICATION_STRATEGY.LINK,
|
|
855
|
+
url: linkData.url,
|
|
856
|
+
success: false,
|
|
857
|
+
error
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
// Link always auto-opens the app (no SDK UI by default)
|
|
862
|
+
// Open immediately to preserve user gesture context
|
|
863
|
+
if ((invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.autoTrigger) !== false) {
|
|
864
|
+
triggerLink();
|
|
865
|
+
}
|
|
866
|
+
// Start polling in the background
|
|
867
|
+
console.log('[PhoneAuth Client] Link polling config:', {
|
|
868
|
+
fromInvokeOptions: invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.pollingEndpoint,
|
|
869
|
+
fromClientConfig: (_o = this.config.endpoints) === null || _o === void 0 ? void 0 : _o.polling,
|
|
870
|
+
finalPollingEndpoint: (invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.pollingEndpoint) || ((_p = this.config.endpoints) === null || _p === void 0 ? void 0 : _p.polling)
|
|
871
|
+
});
|
|
872
|
+
const pollingOptions = {
|
|
873
|
+
pollingEndpoint: (invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.pollingEndpoint) || ((_q = this.config.endpoints) === null || _q === void 0 ? void 0 : _q.polling),
|
|
874
|
+
pollingInterval: (invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.pollingInterval) || this.config.pollingInterval || 2000,
|
|
875
|
+
maxPollingAttempts: (invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.maxPollingAttempts) || this.config.maxPollingAttempts || 150,
|
|
876
|
+
onLinkOpened: undefined,
|
|
877
|
+
onStatusUpdate: undefined
|
|
878
|
+
};
|
|
879
|
+
console.log('[PhoneAuth Client] Final Link polling options:', pollingOptions);
|
|
880
|
+
// Create credential promise
|
|
881
|
+
const credentialPromise = handler.invoke(plainResponse, pollingOptions).then(result => {
|
|
882
|
+
if (result.authenticated && result.credential) {
|
|
883
|
+
return {
|
|
884
|
+
credential: result.credential,
|
|
885
|
+
session: plainResponse.session,
|
|
886
|
+
authenticated: true
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
else {
|
|
890
|
+
throw this.createError(PhoneAuthErrorCode.USER_DENIED, result.error || 'Link authentication failed');
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
// Handle based on execution mode
|
|
894
|
+
if (executionMode === 'extended') {
|
|
895
|
+
// Extended mode - return control methods
|
|
844
896
|
return {
|
|
845
|
-
strategy:
|
|
846
|
-
url: linkData.url,
|
|
847
|
-
pollingPromise,
|
|
897
|
+
strategy: 'link',
|
|
848
898
|
session: plainResponse.session,
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
};
|
|
853
|
-
}
|
|
854
|
-
else {
|
|
855
|
-
// UI mode - show button to open app link
|
|
856
|
-
const modal = new AuthModal(invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.modalOptions, invokeOptions === null || invokeOptions === void 0 ? void 0 : invokeOptions.callbacks);
|
|
857
|
-
const handler = new LinkHandler();
|
|
858
|
-
// Show link button in modal - user MUST click the button to open the app link
|
|
859
|
-
// This is critical for iOS to recognize the app link (requires user interaction)
|
|
860
|
-
yield modal.showLinkButton(linkData.url);
|
|
861
|
-
// Link options - the app link will be opened by user clicking the modal button
|
|
862
|
-
const options = {
|
|
863
|
-
// Use configured polling endpoint if available
|
|
864
|
-
pollingEndpoint: (_c = this.config.endpoints) === null || _c === void 0 ? void 0 : _c.polling,
|
|
865
|
-
pollingInterval: this.config.pollingInterval || 2000, // Default 2 second interval
|
|
866
|
-
maxPollingAttempts: this.config.maxPollingAttempts || 150, // Default 5 minutes total
|
|
867
|
-
onLinkOpened: () => {
|
|
868
|
-
this.log('Authentication app link opened');
|
|
869
|
-
modal.updateStatus('Waiting for app authentication...');
|
|
899
|
+
credential: credentialPromise,
|
|
900
|
+
data: {
|
|
901
|
+
app_url: linkData.url
|
|
870
902
|
},
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
903
|
+
// Re-open the app link
|
|
904
|
+
trigger: triggerLink,
|
|
905
|
+
// Polling control
|
|
906
|
+
start_polling: () => handler.invoke(plainResponse, pollingOptions).then(result => ({
|
|
907
|
+
credential: result.credential || '',
|
|
908
|
+
session: plainResponse.session,
|
|
909
|
+
authenticated: result.authenticated
|
|
910
|
+
})),
|
|
911
|
+
stop_polling: () => handler.cleanup(),
|
|
912
|
+
cancel: () => {
|
|
913
|
+
handler.cancel();
|
|
914
|
+
handler.cleanup();
|
|
880
915
|
},
|
|
881
|
-
|
|
882
|
-
this.log('Link authentication timed out');
|
|
883
|
-
modal.updateStatus('Authentication timed out', true);
|
|
884
|
-
}
|
|
916
|
+
is_polling: true
|
|
885
917
|
};
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
return { [aggregatorId]: result.credential };
|
|
894
|
-
}
|
|
895
|
-
else {
|
|
896
|
-
throw this.createError(PhoneAuthErrorCode.VERIFICATION_FAILED, result.error || 'Link authentication failed');
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
catch (error) {
|
|
900
|
-
modal.close();
|
|
901
|
-
if (error instanceof Error && error.name === 'PhoneAuthError') {
|
|
902
|
-
throw error;
|
|
903
|
-
}
|
|
904
|
-
throw this.createError(PhoneAuthErrorCode.INTERNAL_SERVER_ERROR, `Link authentication error: ${error instanceof Error ? error.message : 'Unknown error'}`, { originalError: error });
|
|
905
|
-
}
|
|
906
|
-
finally {
|
|
907
|
-
// Ensure handler cleanup
|
|
908
|
-
handler.cleanup();
|
|
909
|
-
}
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
// Standard mode - return credential when complete
|
|
921
|
+
// Wait for credential and return in standard format
|
|
922
|
+
const credential = yield credentialPromise;
|
|
923
|
+
const aggregatorId = this.config.aggregatorId || 'default';
|
|
924
|
+
return { [aggregatorId]: credential.credential };
|
|
910
925
|
}
|
|
911
926
|
}
|
|
912
927
|
else {
|
|
@@ -4,4 +4,4 @@ export { PhoneAuthErrorCode, isPhoneAuthError, isUserError, getUserMessage, isEr
|
|
|
4
4
|
export type { PhoneAuthErrorCode as PhoneAuthErrorCodeType } from './error-utils';
|
|
5
5
|
export { validatePhoneNumber, validatePlmn, validateUseCaseRequirements, validateConsentData, validateNonce } from './validation-utils';
|
|
6
6
|
export { MobileDebugConsole } from './ui/mobile-debug-console';
|
|
7
|
-
export {
|
|
7
|
+
export { isExtendedResponse, isCredential, isAuthCredential, isLinkStrategy, isTS43Strategy, isDesktopStrategy, getStrategy, hasPollingControls, hasTrigger, isHeadlessResult, requiresPolling, requiresUserAction } from './type-guards';
|