verant_id_cloud_scan 1.4.5-beta.7 → 1.4.5-beta.9
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/Api.js +66 -0
- package/CHANGELOG.md +37 -0
- package/CloudScan.js +152 -1
- package/WebSocketClient.js +209 -0
- package/index.d.ts +65 -0
- package/package.json +8 -2
package/Api.js
CHANGED
|
@@ -94,6 +94,17 @@ export function getFaceComparisonServerAddress() {
|
|
|
94
94
|
: "https://faceid.verantid.com/compare_id_and_face";
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Get Mobile Verification server address based on current environment
|
|
99
|
+
* @returns {string}
|
|
100
|
+
*/
|
|
101
|
+
function getMobileVerificationServerAddress() {
|
|
102
|
+
const env = getEnvironment();
|
|
103
|
+
return env === 'staging'
|
|
104
|
+
? "https://staging.mdl.verantid.bluerocket.us"
|
|
105
|
+
: "https://mdl.verantid.bluerocket.us";
|
|
106
|
+
}
|
|
107
|
+
|
|
97
108
|
export const dmvCheck = async (clientId, scannerType, licenseData) => {
|
|
98
109
|
const url = getDmvServerAddress();
|
|
99
110
|
|
|
@@ -440,3 +451,58 @@ export const checkScannerPresent = async (scannerAddress) => {
|
|
|
440
451
|
return false;
|
|
441
452
|
}
|
|
442
453
|
};
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Create a verification session for mobile ID verification
|
|
457
|
+
*
|
|
458
|
+
* POST /sessions
|
|
459
|
+
* Returns: session_id, session_url (for QR code), websocket_url (for real-time updates)
|
|
460
|
+
*
|
|
461
|
+
* @param {string} userId - User ID for the verification session
|
|
462
|
+
* @param {string} clientId - Client ID for licensing and tracking
|
|
463
|
+
* @returns {Promise<Object>} Session data with session_id, session_url, and websocket_url
|
|
464
|
+
*/
|
|
465
|
+
export const createVerificationSession = async (userId, clientId) => {
|
|
466
|
+
const url = getMobileVerificationServerAddress() + "/sessions";
|
|
467
|
+
const data = { user_id: userId, client_id: clientId };
|
|
468
|
+
|
|
469
|
+
try {
|
|
470
|
+
const response = await fetch(url, {
|
|
471
|
+
method: "POST",
|
|
472
|
+
headers: {
|
|
473
|
+
"Content-Type": "application/json",
|
|
474
|
+
},
|
|
475
|
+
body: JSON.stringify(data),
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
if (response.ok) {
|
|
479
|
+
const responseData = await response.json();
|
|
480
|
+
return responseData;
|
|
481
|
+
} else {
|
|
482
|
+
// Try to parse error response
|
|
483
|
+
try {
|
|
484
|
+
const errorData = await response.json();
|
|
485
|
+
console.error("Verification session creation failed:", errorData);
|
|
486
|
+
return {
|
|
487
|
+
status: 'error',
|
|
488
|
+
message: errorData.message || 'Failed to create verification session',
|
|
489
|
+
error: errorData
|
|
490
|
+
};
|
|
491
|
+
} catch (parseError) {
|
|
492
|
+
const errorText = await response.text();
|
|
493
|
+
console.error("Verification session creation failed:", errorText);
|
|
494
|
+
return {
|
|
495
|
+
status: 'error',
|
|
496
|
+
message: 'Failed to create verification session',
|
|
497
|
+
raw_error: errorText
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
} catch (error) {
|
|
502
|
+
console.error("There was a problem with the verification session request:", error);
|
|
503
|
+
return {
|
|
504
|
+
status: 'error',
|
|
505
|
+
message: error.message || 'Unable to connect to verification service.'
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
};
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.4.5-beta.9] - 2026-04-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Mobile ID verification support (VNT-1409, VNT-1419, VNT-1429, VNT-1455)
|
|
12
|
+
- Added `startMobileVerification()` function to initiate mobile verification sessions
|
|
13
|
+
- Added `createVerificationSession()` API function to create verification sessions with user ID and client ID
|
|
14
|
+
- Added WebSocket client (`WebSocketClient.js`) for real-time verification updates from AWS API Gateway
|
|
15
|
+
- Added mobile verification server address configuration with environment detection
|
|
16
|
+
- QR code generation for mobile verification sessions with customizable base URLs
|
|
17
|
+
- Real-time verification callbacks: `onVerificationStarted`, `onVerificationResult`, `onStatusChange`, `onError`
|
|
18
|
+
- Session management with session ID, session URL, WebSocket URL, and QR code SVG
|
|
19
|
+
- Connection state management (CONNECTING, OPEN, CLOSED, ERROR) for WebSocket connections
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Updated environment detection to support mobile verification endpoints
|
|
23
|
+
- Mobile verification uses `staging.mdl.verantid.bluerocket.us` for staging
|
|
24
|
+
- Mobile verification uses `mdl.verantid.bluerocket.us` for production
|
|
25
|
+
- Updated scanner type detection to use `scannerProfile` from scanner response in auto-DMV verification
|
|
26
|
+
- Enhanced TypeScript definitions (`index.d.ts`) to include mobile verification types and callbacks
|
|
27
|
+
|
|
28
|
+
## [1.4.5-beta.8] - 2026-04-15
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- Moved UV/IR image type definitions to scanner profile configuration
|
|
32
|
+
- Added `frontUvImageType`, `backUvImageType`, `frontIrImageType`, and `backIrImageType` to IDXpressPlus profile
|
|
33
|
+
- Updated image extraction logic to use profile-defined UV/IR types instead of hardcoded strings
|
|
34
|
+
- Updated TypeScript definitions (`index.d.ts`) to include UV/IR base64 fields in `scanId` return type
|
|
35
|
+
- Removed UV/IR fields from local scanner functions (`localScanId`, `localContinueScanId`) as local scanners do not support UV/IR imaging
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- Eliminated redundant variable declarations in `ScannerApi.js` by declaring UV/IR variables at function scope
|
|
39
|
+
|
|
40
|
+
## [1.4.5-beta.7] - 2026-04-15
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- Internal refactoring and code review fixes
|
|
44
|
+
|
|
8
45
|
## [1.4.5-beta.6] - 2026-04-15
|
|
9
46
|
|
|
10
47
|
### Added
|
package/CloudScan.js
CHANGED
|
@@ -15,8 +15,14 @@ import {
|
|
|
15
15
|
scannerPresent,
|
|
16
16
|
} from "./ScannerApi.js";
|
|
17
17
|
import { VerificationModal } from "./VerificationModal.js";
|
|
18
|
-
import { checkAutoDmvEnabled, setEnvironment } from "./Api.js";
|
|
18
|
+
import { checkAutoDmvEnabled, setEnvironment, createVerificationSession } from "./Api.js";
|
|
19
19
|
import { formatSexCodeForDisplay, formatHeightForDisplay } from "./FormatUtils.js";
|
|
20
|
+
import { WebSocketClient, ConnectionState } from "./WebSocketClient.js";
|
|
21
|
+
|
|
22
|
+
// Re-export WebSocket primitives so host apps can import them from the
|
|
23
|
+
// library entry point (e.g. for typing connection state in their own UI).
|
|
24
|
+
export { WebSocketClient, ConnectionState };
|
|
25
|
+
import QRCode from "qrcode";
|
|
20
26
|
|
|
21
27
|
let cachedLicenseFrontBase64 = "";
|
|
22
28
|
|
|
@@ -496,3 +502,148 @@ export const localContinueScanId = async (scannerAddress, includeData, clientId
|
|
|
496
502
|
}
|
|
497
503
|
return returnObj;
|
|
498
504
|
};
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Connect to a verification session's WebSocket
|
|
508
|
+
*
|
|
509
|
+
* Low-level primitive: opens a WebSocket connection to the given API Gateway
|
|
510
|
+
* URL and wires up the event callbacks. Use this when the caller already has
|
|
511
|
+
* a session (URL obtained out-of-band). For the full flow that also creates
|
|
512
|
+
* the session and generates a QR code, use `startMobileVerification`.
|
|
513
|
+
*
|
|
514
|
+
* AWS message frames are parsed and dispatched as high-level events:
|
|
515
|
+
* - verification_started → callbacks.onVerificationStarted(payload)
|
|
516
|
+
* - verification_result → callbacks.onResult(payload)
|
|
517
|
+
* Connection lifecycle is surfaced via callbacks.onStatusChange and
|
|
518
|
+
* callbacks.onError with clean `{ message, code, error }` shapes.
|
|
519
|
+
*
|
|
520
|
+
* @param {Object} options
|
|
521
|
+
* @param {string} options.websocketUrl - API Gateway WebSocket URL (must include session_id)
|
|
522
|
+
* @param {Object} [options.callbacks] - Event callbacks
|
|
523
|
+
* @param {Function} [options.callbacks.onVerificationStarted]
|
|
524
|
+
* @param {Function} [options.callbacks.onResult]
|
|
525
|
+
* @param {Function} [options.callbacks.onStatusChange]
|
|
526
|
+
* @param {Function} [options.callbacks.onError]
|
|
527
|
+
* @returns {Promise<Object>} Handle with live `status` getter and `close()` method
|
|
528
|
+
*/
|
|
529
|
+
export const connectToVerificationSession = async ({ websocketUrl, callbacks = {} } = {}) => {
|
|
530
|
+
if (!websocketUrl) {
|
|
531
|
+
throw new Error('connectToVerificationSession: websocketUrl is required');
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const wsClient = new WebSocketClient(callbacks);
|
|
535
|
+
|
|
536
|
+
// WebSocketClient.connect() already invokes callbacks.onError on failure;
|
|
537
|
+
// we just let the error propagate so the caller can react too.
|
|
538
|
+
await wsClient.connect(websocketUrl);
|
|
539
|
+
|
|
540
|
+
return {
|
|
541
|
+
get status() { return wsClient.getState(); },
|
|
542
|
+
close: () => wsClient.disconnect()
|
|
543
|
+
};
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Start mobile verification session
|
|
548
|
+
*
|
|
549
|
+
* Creates a verification session, generates a QR code, and establishes WebSocket connection
|
|
550
|
+
* for real-time verification updates.
|
|
551
|
+
*
|
|
552
|
+
* @param {string} userId - User ID for the verification session
|
|
553
|
+
* @param {string} clientId - Client ID for licensing and tracking
|
|
554
|
+
* @param {Object} callbacks - Event callbacks for verification lifecycle
|
|
555
|
+
* @param {Function} callbacks.onVerificationStarted - Called when customer starts verification
|
|
556
|
+
* @param {Function} callbacks.onResult - Called when verification completes with verified fields
|
|
557
|
+
* @param {Function} callbacks.onStatusChange - Called when WebSocket connection state changes
|
|
558
|
+
* @param {Function} callbacks.onError - Called on errors
|
|
559
|
+
* @returns {Promise<Object>} Session handle with QR code and control methods
|
|
560
|
+
*/
|
|
561
|
+
export const startMobileVerification = async (userId, clientId, callbacks = {}, mobileVerifyBaseUrl) => {
|
|
562
|
+
try {
|
|
563
|
+
const sessionData = await createVerificationSession(userId, clientId);
|
|
564
|
+
|
|
565
|
+
if (sessionData.status === 'error') {
|
|
566
|
+
throw new Error(sessionData.message || 'Failed to create verification session');
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const { session_id, session_url, websocket_url } = sessionData;
|
|
570
|
+
|
|
571
|
+
if (!session_id || !session_url || !websocket_url) {
|
|
572
|
+
throw new Error('Invalid session response: missing required fields');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Generate QR code SVG
|
|
576
|
+
// If mobileVerifyBaseUrl is provided, construct the mobile verify URL by
|
|
577
|
+
// appending the session_id as a path segment (matches host-app routes like
|
|
578
|
+
// route("mobile-verify/:sessionId", ...)
|
|
579
|
+
// in VerantID-Web). Falls back to the backend session_url if no base is
|
|
580
|
+
// provided, but note that the backend URL typically requires auth headers
|
|
581
|
+
// that a phone browser can't send from a QR-code open, so host apps should
|
|
582
|
+
// always pass mobileVerifyBaseUrl in production.
|
|
583
|
+
let qrCodeUrl = session_url;
|
|
584
|
+
if (mobileVerifyBaseUrl) {
|
|
585
|
+
// Remove trailing slash if present so we don't end up with "//{session_id}"
|
|
586
|
+
const baseUrl = mobileVerifyBaseUrl.endsWith('/') ? mobileVerifyBaseUrl.slice(0, -1) : mobileVerifyBaseUrl;
|
|
587
|
+
qrCodeUrl = `${baseUrl}/${session_id}`;
|
|
588
|
+
console.log('[startMobileVerification] Using custom mobile verify URL:', qrCodeUrl);
|
|
589
|
+
} else {
|
|
590
|
+
console.log('[startMobileVerification] Using backend session URL for QR code:', qrCodeUrl);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
let qrCodeSvg = '';
|
|
594
|
+
try {
|
|
595
|
+
qrCodeSvg = await QRCode.toString(qrCodeUrl, {
|
|
596
|
+
type: 'svg',
|
|
597
|
+
width: 256,
|
|
598
|
+
margin: 2,
|
|
599
|
+
errorCorrectionLevel: 'M'
|
|
600
|
+
});
|
|
601
|
+
console.log('[startMobileVerification] QR code generated');
|
|
602
|
+
} catch (qrError) {
|
|
603
|
+
console.error('[startMobileVerification] QR code generation failed:', qrError);
|
|
604
|
+
throw new Error('Failed to generate QR code: ' + qrError.message);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Step 3: Connect to WebSocket via the shared primitive
|
|
608
|
+
let wsSession;
|
|
609
|
+
try {
|
|
610
|
+
wsSession = await connectToVerificationSession({
|
|
611
|
+
websocketUrl: websocket_url,
|
|
612
|
+
callbacks
|
|
613
|
+
});
|
|
614
|
+
console.log('[startMobileVerification] WebSocket connected');
|
|
615
|
+
} catch (wsError) {
|
|
616
|
+
console.error('[startMobileVerification] WebSocket connection failed:', wsError);
|
|
617
|
+
throw new Error('Failed to establish WebSocket connection: ' + wsError.message);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Step 4: Return session handle — `status` is a live getter that
|
|
621
|
+
// delegates to the underlying WebSocket client, so host apps always
|
|
622
|
+
// observe the current connection state (not a snapshot).
|
|
623
|
+
return {
|
|
624
|
+
sessionId: session_id,
|
|
625
|
+
sessionUrl: session_url, // Backend API URL for session
|
|
626
|
+
qrCodeUrl: qrCodeUrl, // The URL that was encoded in the QR code (mobile verify page or session URL)
|
|
627
|
+
qrCodeSvg: qrCodeSvg,
|
|
628
|
+
get status() { return wsSession.status; },
|
|
629
|
+
close: () => {
|
|
630
|
+
console.log('[startMobileVerification] Closing session:', session_id);
|
|
631
|
+
wsSession.close();
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
} catch (error) {
|
|
636
|
+
console.error('[startMobileVerification] Error:', error);
|
|
637
|
+
|
|
638
|
+
// Notify error callback if provided
|
|
639
|
+
if (typeof callbacks.onError === 'function') {
|
|
640
|
+
callbacks.onError({
|
|
641
|
+
message: error.message || 'Failed to start mobile verification',
|
|
642
|
+
code: 'SESSION_CREATION_FAILED',
|
|
643
|
+
error
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
throw error;
|
|
648
|
+
}
|
|
649
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocketClient.js
|
|
3
|
+
*
|
|
4
|
+
* Manages WebSocket connections to AWS API Gateway for real-time verification updates.
|
|
5
|
+
* Handles connection lifecycle, message parsing, and event callbacks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Connection states
|
|
10
|
+
*/
|
|
11
|
+
export const ConnectionState = {
|
|
12
|
+
CONNECTING: 'connecting',
|
|
13
|
+
OPEN: 'open',
|
|
14
|
+
CLOSED: 'closed',
|
|
15
|
+
ERROR: 'error'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* WebSocket message route keys from AWS API Gateway
|
|
20
|
+
*/
|
|
21
|
+
const RouteKeys = {
|
|
22
|
+
VERIFICATION_STARTED: 'verification_started',
|
|
23
|
+
VERIFICATION_RESULT: 'verification_result'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* WebSocketClient
|
|
28
|
+
*
|
|
29
|
+
* Encapsulates WebSocket connection management and event handling for verification sessions.
|
|
30
|
+
*/
|
|
31
|
+
export class WebSocketClient {
|
|
32
|
+
constructor(callbacks = {}) {
|
|
33
|
+
this.ws = null;
|
|
34
|
+
this.state = ConnectionState.CLOSED;
|
|
35
|
+
this.callbacks = {
|
|
36
|
+
onVerificationStarted: callbacks.onVerificationStarted || null,
|
|
37
|
+
onResult: callbacks.onResult || null,
|
|
38
|
+
onStatusChange: callbacks.onStatusChange || null,
|
|
39
|
+
onError: callbacks.onError || null
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Connect to WebSocket API Gateway
|
|
45
|
+
* @param {string} wsUrl - The WebSocket URL (already includes session_id query param)
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
async connect(wsUrl) {
|
|
49
|
+
if (this.ws) {
|
|
50
|
+
throw new Error('WebSocket connection already exists');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Resolve WebSocket implementation: native global (browser or modern Node)
|
|
54
|
+
// or the 'ws' package (older Node runtimes). Dynamic import is used because
|
|
55
|
+
// this file is an ES module — top-level `require` is not available.
|
|
56
|
+
let WebSocketImpl;
|
|
57
|
+
if (typeof WebSocket !== 'undefined') {
|
|
58
|
+
WebSocketImpl = WebSocket;
|
|
59
|
+
} else {
|
|
60
|
+
try {
|
|
61
|
+
const wsModule = await import('ws');
|
|
62
|
+
WebSocketImpl = wsModule.default || wsModule.WebSocket;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this._updateState(ConnectionState.ERROR);
|
|
65
|
+
this._invokeCallback('onError', {
|
|
66
|
+
message: 'No WebSocket implementation available (install "ws" for Node.js)',
|
|
67
|
+
code: 'NO_WEBSOCKET_IMPL',
|
|
68
|
+
error: error.message
|
|
69
|
+
});
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
try {
|
|
76
|
+
this._updateState(ConnectionState.CONNECTING);
|
|
77
|
+
this.ws = new WebSocketImpl(wsUrl);
|
|
78
|
+
|
|
79
|
+
this.ws.onopen = () => {
|
|
80
|
+
console.log('[WebSocketClient] Connection established');
|
|
81
|
+
this._updateState(ConnectionState.OPEN);
|
|
82
|
+
resolve();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
this.ws.onmessage = (event) => {
|
|
86
|
+
this._handleMessage(event.data);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
this.ws.onerror = (error) => {
|
|
90
|
+
console.error('[WebSocketClient] Connection error:', error);
|
|
91
|
+
this._updateState(ConnectionState.ERROR);
|
|
92
|
+
this._invokeCallback('onError', {
|
|
93
|
+
message: 'WebSocket connection error',
|
|
94
|
+
code: 'CONNECTION_ERROR',
|
|
95
|
+
error
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
this.ws.onclose = (event) => {
|
|
100
|
+
console.log('[WebSocketClient] Connection closed', event.code, event.reason);
|
|
101
|
+
this._updateState(ConnectionState.CLOSED);
|
|
102
|
+
this.ws = null;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
this._updateState(ConnectionState.ERROR);
|
|
107
|
+
this._invokeCallback('onError', {
|
|
108
|
+
message: 'Failed to create WebSocket connection',
|
|
109
|
+
code: 'CONNECTION_FAILED',
|
|
110
|
+
error: error.message
|
|
111
|
+
});
|
|
112
|
+
reject(error);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Disconnect and cleanup WebSocket connection
|
|
119
|
+
*/
|
|
120
|
+
disconnect() {
|
|
121
|
+
if (this.ws) {
|
|
122
|
+
console.log('[WebSocketClient] Disconnecting...');
|
|
123
|
+
this.ws.close();
|
|
124
|
+
this.ws = null;
|
|
125
|
+
this._updateState(ConnectionState.CLOSED);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get current connection state
|
|
131
|
+
* @returns {string}
|
|
132
|
+
*/
|
|
133
|
+
getState() {
|
|
134
|
+
return this.state;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Handle incoming WebSocket messages
|
|
139
|
+
* @private
|
|
140
|
+
* @param {string} data - Raw message data
|
|
141
|
+
*/
|
|
142
|
+
_handleMessage(data) {
|
|
143
|
+
try {
|
|
144
|
+
console.log('[WebSocketClient] Received message:', data);
|
|
145
|
+
|
|
146
|
+
// Parse the message (AWS API Gateway may send JSON-wrapped messages)
|
|
147
|
+
const message = typeof data === 'string' ? JSON.parse(data) : data;
|
|
148
|
+
|
|
149
|
+
// Extract route key and payload
|
|
150
|
+
// AWS API Gateway format may vary, handle both direct and wrapped formats
|
|
151
|
+
const routeKey = message.routeKey || message.action || message.type;
|
|
152
|
+
const payload = message.data || message.payload || message;
|
|
153
|
+
|
|
154
|
+
// Route to appropriate handler
|
|
155
|
+
switch (routeKey) {
|
|
156
|
+
case RouteKeys.VERIFICATION_STARTED:
|
|
157
|
+
console.log('[WebSocketClient] Verification started');
|
|
158
|
+
this._invokeCallback('onVerificationStarted', payload);
|
|
159
|
+
break;
|
|
160
|
+
|
|
161
|
+
case RouteKeys.VERIFICATION_RESULT:
|
|
162
|
+
console.log('[WebSocketClient] Verification result received');
|
|
163
|
+
this._invokeCallback('onResult', payload);
|
|
164
|
+
break;
|
|
165
|
+
|
|
166
|
+
default:
|
|
167
|
+
console.warn('[WebSocketClient] Unknown message route:', routeKey);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error('[WebSocketClient] Error parsing message:', error);
|
|
173
|
+
this._invokeCallback('onError', {
|
|
174
|
+
message: 'Failed to parse WebSocket message',
|
|
175
|
+
code: 'PARSE_ERROR',
|
|
176
|
+
error: error.message
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Update connection state and notify listeners
|
|
183
|
+
* @private
|
|
184
|
+
* @param {string} newState
|
|
185
|
+
*/
|
|
186
|
+
_updateState(newState) {
|
|
187
|
+
if (this.state !== newState) {
|
|
188
|
+
this.state = newState;
|
|
189
|
+
console.log('[WebSocketClient] State changed:', newState);
|
|
190
|
+
this._invokeCallback('onStatusChange', newState);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Safely invoke a callback if it exists
|
|
196
|
+
* @private
|
|
197
|
+
* @param {string} callbackName
|
|
198
|
+
* @param {*} data
|
|
199
|
+
*/
|
|
200
|
+
_invokeCallback(callbackName, data) {
|
|
201
|
+
if (typeof this.callbacks[callbackName] === 'function') {
|
|
202
|
+
try {
|
|
203
|
+
this.callbacks[callbackName](data);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error(`[WebSocketClient] Error in ${callbackName} callback:`, error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -78,6 +78,71 @@ declare module "verant_id_cloud_scan" {
|
|
|
78
78
|
errorMessages: string;
|
|
79
79
|
dmvVerificationResult?: any;
|
|
80
80
|
}>;
|
|
81
|
+
|
|
82
|
+
// Mobile Verification Types
|
|
83
|
+
export type ConnectionStateValue = 'connecting' | 'open' | 'closed' | 'error';
|
|
84
|
+
|
|
85
|
+
export const ConnectionState: {
|
|
86
|
+
readonly CONNECTING: 'connecting';
|
|
87
|
+
readonly OPEN: 'open';
|
|
88
|
+
readonly CLOSED: 'closed';
|
|
89
|
+
readonly ERROR: 'error';
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export interface VerificationCallbacks {
|
|
93
|
+
onVerificationStarted?: (data: any) => void;
|
|
94
|
+
onResult?: (verifiedFields: any) => void;
|
|
95
|
+
onStatusChange?: (status: ConnectionStateValue) => void;
|
|
96
|
+
onError?: (error: { message: string; code?: string; error?: any }) => void;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Handle returned by `connectToVerificationSession`. `status` is a live
|
|
101
|
+
* getter that reflects the current WebSocket state, not a snapshot.
|
|
102
|
+
*/
|
|
103
|
+
export interface ConnectedSession {
|
|
104
|
+
readonly status: ConnectionStateValue;
|
|
105
|
+
close(): void;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface VerificationSession {
|
|
109
|
+
sessionId: string;
|
|
110
|
+
sessionUrl: string;
|
|
111
|
+
qrCodeUrl: string;
|
|
112
|
+
qrCodeSvg: string;
|
|
113
|
+
readonly status: ConnectionStateValue;
|
|
114
|
+
close: () => void;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface ConnectToVerificationSessionOptions {
|
|
118
|
+
websocketUrl: string;
|
|
119
|
+
callbacks?: VerificationCallbacks;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Low-level primitive: open a WebSocket connection to an existing
|
|
124
|
+
* verification session's API Gateway URL.
|
|
125
|
+
*
|
|
126
|
+
* For the full orchestrated flow (create session + QR + WS connect),
|
|
127
|
+
* use `startMobileVerification`.
|
|
128
|
+
*/
|
|
129
|
+
export function connectToVerificationSession(
|
|
130
|
+
options: ConnectToVerificationSessionOptions
|
|
131
|
+
): Promise<ConnectedSession>;
|
|
132
|
+
|
|
133
|
+
export function startMobileVerification(
|
|
134
|
+
userId: string,
|
|
135
|
+
clientId: string,
|
|
136
|
+
callbacks?: VerificationCallbacks,
|
|
137
|
+
mobileVerifyBaseUrl?: string
|
|
138
|
+
): Promise<VerificationSession>;
|
|
139
|
+
|
|
140
|
+
export class WebSocketClient {
|
|
141
|
+
constructor(callbacks?: VerificationCallbacks);
|
|
142
|
+
connect(wsUrl: string): Promise<void>;
|
|
143
|
+
disconnect(): void;
|
|
144
|
+
getState(): ConnectionStateValue;
|
|
145
|
+
}
|
|
81
146
|
}
|
|
82
147
|
|
|
83
148
|
export function scannerPresent(scannerAddress: string): Promise<boolean>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "verant_id_cloud_scan",
|
|
3
|
-
"version": "1.4.5-beta.
|
|
3
|
+
"version": "1.4.5-beta.9",
|
|
4
4
|
"description": "Verant ID Cloud Scan NPM Library",
|
|
5
5
|
"main": "CloudScan.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -9,5 +9,11 @@
|
|
|
9
9
|
},
|
|
10
10
|
"author": "Verant ID Inc",
|
|
11
11
|
"license": "ISC",
|
|
12
|
-
"type": "module"
|
|
12
|
+
"type": "module",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"qrcode": "^1.5.3"
|
|
15
|
+
},
|
|
16
|
+
"optionalDependencies": {
|
|
17
|
+
"ws": "^8.16.0"
|
|
18
|
+
}
|
|
13
19
|
}
|