verant_id_cloud_scan 1.4.5-beta.2 → 1.4.5-beta.4

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 CHANGED
@@ -40,7 +40,7 @@ const licenseServerAddress = env === 'staging'
40
40
  : "https://lic.verantid.com/api/v1";
41
41
 
42
42
  const dmvServerAddress = env === 'staging'
43
- ? "https://dmv-staging.verantid.com/api/v1/dmv_check"
43
+ ? "https://dmv-check-server-staging-fcaab48bec21.herokuapp.com/api/v1/dmv_check"
44
44
  : "https://dmv.verantid.com/api/v1/dmv_check";
45
45
 
46
46
  export const dmvCheck = async (clientId, scannerType, licenseData) => {
@@ -296,6 +296,9 @@ const postToScannerApi = async (
296
296
  formattedAddress = `http://${scannerAddress}`;
297
297
  }
298
298
 
299
+ // Remove trailing slash to prevent double slashes in URL
300
+ formattedAddress = formattedAddress.replace(/\/+$/, '');
301
+
299
302
  let apiAddress = `${formattedAddress}/securelink`;
300
303
 
301
304
  const controller = new AbortController();
package/CloudScan.js CHANGED
@@ -175,7 +175,7 @@ export const scanId = async (
175
175
  console.log('[AUTO-DMV] Feature enabled, showing verification modal');
176
176
 
177
177
  // Determine scanner type - you can customize this based on your needs
178
- const scannerType = 'DigitalCheck'; // Default scanner type
178
+ const scannerType = scannerResponseObj.scannerProfile || 'DigitalCheck'; // Default scanner type
179
179
 
180
180
  // Create and open the modal
181
181
  const modal = new VerificationModal(clientId, scannerType, barcodeResultsObject, {
package/LocalApi.js CHANGED
@@ -1,3 +1,10 @@
1
+ // Helper function to build consistent scanner API URLs
2
+ const buildScannerApiUrl = (scannerAddress, endpoint) => {
3
+ // Remove trailing slash to prevent double slashes in URL
4
+ const formattedAddress = scannerAddress.replace(/\/+$/, '');
5
+ return `${formattedAddress}/ambirscanwebconnect/${endpoint}`;
6
+ };
7
+
1
8
  // Helper function for making POST requests to the scanner API
2
9
  const callScannerApi = async (
3
10
  requestType,
@@ -5,12 +12,7 @@ const callScannerApi = async (
5
12
  endpoint,
6
13
  bodyObj
7
14
  ) => {
8
- let apiAddress = "";
9
- if (scannerAddress === "https://demo6425275.mockable.io") {
10
- apiAddress = `${scannerAddress}/ambirscanwebconnect/${endpoint}`;
11
- } else {
12
- apiAddress = `${scannerAddress}/ambirscanwebconnect/${endpoint}`;
13
- }
15
+ const apiAddress = buildScannerApiUrl(scannerAddress, endpoint);
14
16
 
15
17
  const response = await fetch(apiAddress, {
16
18
  method: requestType,
@@ -35,9 +37,7 @@ export const getScannerSerialNumber = (scannerAddress) =>
35
37
  callScannerApi("POST", scannerAddress, "getserialnumber", null);
36
38
 
37
39
  export const isFeederLoaded = async (scannerAddress) => {
38
- let apiAddress = "";
39
-
40
- apiAddress = `${scannerAddress}/ambirscanwebconnect/isfeederloaded`;
40
+ const apiAddress = buildScannerApiUrl(scannerAddress, "isfeederloaded");
41
41
 
42
42
  const response = await fetch(apiAddress, {
43
43
  method: "POST",
@@ -45,15 +45,13 @@ export const isFeederLoaded = async (scannerAddress) => {
45
45
  body: null,
46
46
  });
47
47
  if (!response.ok) throw new Error(response.statusText);
48
- let responseText = response.text();
48
+ let responseText = await response.text();
49
49
 
50
50
  return responseText;
51
51
  };
52
52
 
53
53
  export const setBackScanParameters = async (scannerAddress) => {
54
- let apiAddress = "";
55
-
56
- apiAddress = `${scannerAddress}/ambirscanwebconnect/setscanparameters`;
54
+ const apiAddress = buildScannerApiUrl(scannerAddress, "setscanparameters");
57
55
 
58
56
  const response = await fetch(apiAddress, {
59
57
  method: "POST",
@@ -63,14 +61,12 @@ export const setBackScanParameters = async (scannerAddress) => {
63
61
  body: "settings%5BDPI%5D=400&settings%5BAutoCrop%5D=true&settings%5BAutoDeskew%5D=true&settings%5BPaperSize%5D=NONE&settings%5BAutoRotate%5D=true&settings%5BDuplex%5D=false&settings%5BColor%5D=Color",
64
62
  });
65
63
  if (!response.ok) throw new Error(response.statusText);
66
- let responseText = response.text();
64
+ let responseText = await response.text();
67
65
 
68
66
  return responseText;
69
67
  };
70
68
  export const setFrontScanParameters = async (scannerAddress) => {
71
- let apiAddress = "";
72
-
73
- apiAddress = `${scannerAddress}/ambirscanwebconnect/setscanparameters`;
69
+ const apiAddress = buildScannerApiUrl(scannerAddress, "setscanparameters");
74
70
 
75
71
  const response = await fetch(apiAddress, {
76
72
  method: "POST",
@@ -80,7 +76,7 @@ export const setFrontScanParameters = async (scannerAddress) => {
80
76
  body: "settings%5BDPI%5D=400&settings%5BAutoCrop%5D=true&settings%5BAutoDeskew%5D=true&settings%5BPaperSize%5D=NONE&settings%5BAutoRotate%5D=true&settings%5BDuplex%5D=false&settings%5BColor%5D=Color",
81
77
  });
82
78
  if (!response.ok) throw new Error(response.statusText);
83
- let responseText = response.text();
79
+ let responseText = await response.text();
84
80
 
85
81
  return responseText;
86
82
  };
@@ -91,9 +87,7 @@ export const getImageCount = (scannerAddress) =>
91
87
  callScannerApi("GET", scannerAddress, "getimagecount", null);
92
88
 
93
89
  export const getImage = async (scannerAddress, imageIndex) => {
94
- let apiAddress = "";
95
-
96
- apiAddress = `${scannerAddress}/ambirscanwebconnect/getimage/` + imageIndex;
90
+ const apiAddress = buildScannerApiUrl(scannerAddress, `getimage/${imageIndex}`);
97
91
 
98
92
  const response = await fetch(apiAddress, {
99
93
  method: "POST",
@@ -101,7 +95,7 @@ export const getImage = async (scannerAddress, imageIndex) => {
101
95
  body: null,
102
96
  });
103
97
  if (!response.ok) throw new Error(response.statusText);
104
- let responseText = response.text();
98
+ let responseText = await response.text();
105
99
 
106
100
  return responseText;
107
101
  };
package/ScannerApi.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as API from "./Api.js";
2
+ import { getProfile } from "./ScannerProfiles.js";
2
3
 
3
4
  let errorMessages = [];
4
5
  let selectedScannerAddress = "";
@@ -63,6 +64,23 @@ export async function scannerChain(
63
64
  let licenseFrontBase64 = "";
64
65
  let licenseBackBase64 = "";
65
66
 
67
+ // Get scanner profile
68
+ const profileName = optionalConnectionParams?.scannerProfile;
69
+ let profile;
70
+ try {
71
+ profile = getProfile(profileName);
72
+ } catch (e) {
73
+ const message =
74
+ e && typeof e.message === "string"
75
+ ? e.message
76
+ : `Failed to resolve scanner profile${profileName ? ` "${profileName}"` : ""}`;
77
+ buildError(message);
78
+ return {
79
+ success: false,
80
+ errorMessages,
81
+ };
82
+ }
83
+
66
84
  //1 open connection and set the session id
67
85
  const currentSessionId = await openConnection(optConnectionParams);
68
86
  if (!currentSessionId) {
@@ -85,40 +103,49 @@ export async function scannerChain(
85
103
  };
86
104
  }
87
105
 
88
- //check the license for this scanner's mac address
89
- if (!existingParams.ScannerMAC) {
90
- closeScannerConnection(currentSessionId); // Even if scanning has errors, always attempt to close the connection
106
+ //check the license for this scanner's identifier (MAC or Serial)
107
+ const identifierField = profile.licenseIdentifierField;
108
+ const fallbackField = profile.licenseIdentifierFallback;
109
+ let scannerIdentifier = existingParams[identifierField];
110
+
111
+ // Fall back to alternate field if primary is missing
112
+ if (!scannerIdentifier && fallbackField) {
113
+ scannerIdentifier = existingParams[fallbackField];
114
+ }
115
+
116
+ if (!scannerIdentifier) {
117
+ buildError(
118
+ `Error: Missing scanner identifier. Tried ${identifierField}${fallbackField ? ` and ${fallbackField}` : ""}`
119
+ );
120
+ await closeScannerConnection(currentSessionId); // Even if scanning has errors, always attempt to close the connection
91
121
  return {
92
122
  success: false,
93
123
  errorMessages,
94
124
  };
95
- } else {
96
- // Check the license
97
- try {
98
- const isValid = await API.checkLicense(
99
- clientId,
100
- existingParams.ScannerMAC
101
- );
102
-
103
- if (isValid) {
104
- // continue
105
- } else {
106
- buildError("Error: License error!");
107
- closeScannerConnection(currentSessionId); // Even if scanning has errors, always attempt to close the connection
108
- return {
109
- success: false,
110
- errorMessages,
111
- };
112
- }
113
- } catch (error) {
114
- buildError(" Error: " + error.message);
115
- console.error("An error occurred:", error.message);
116
- closeScannerConnection(currentSessionId); // Even if scanning has errors, always attempt to close the connection
125
+ }
126
+
127
+ // Check the license
128
+ try {
129
+ const isValid = await API.checkLicense(clientId, scannerIdentifier);
130
+
131
+ if (isValid) {
132
+ // continue
133
+ } else {
134
+ buildError("Error: License error!");
135
+ await closeScannerConnection(currentSessionId); // Even if scanning has errors, always attempt to close the connection
117
136
  return {
118
137
  success: false,
119
138
  errorMessages,
120
139
  };
121
140
  }
141
+ } catch (error) {
142
+ buildError("Error: " + error.message);
143
+ console.error("An error occurred:", error.message);
144
+ await closeScannerConnection(currentSessionId); // Even if scanning has errors, always attempt to close the connection
145
+ return {
146
+ success: false,
147
+ errorMessages,
148
+ };
122
149
  }
123
150
 
124
151
  //3 clear the params for this session
@@ -134,6 +161,7 @@ export async function scannerChain(
134
161
  //4 set the params for this session
135
162
  const setParamsSuccess = await setScanParameters(
136
163
  currentSessionId,
164
+ profile,
137
165
  optScannerParams
138
166
  );
139
167
  if (!setParamsSuccess) {
@@ -150,7 +178,7 @@ export async function scannerChain(
150
178
  scanDataResults: resultData,
151
179
  licenseFrontBase64: frontBase64,
152
180
  licenseBackBase64: backBase64,
153
- } = await startScanDocument(currentSessionId, optGetDocumentParams);
181
+ } = await startScanDocument(currentSessionId, profile, optGetDocumentParams);
154
182
 
155
183
  scanDataResults = resultData;
156
184
  licenseFrontBase64 = frontBase64;
@@ -165,24 +193,12 @@ export async function scannerChain(
165
193
  }
166
194
 
167
195
  //6 set the params we changed back to what they were
168
- let setParamsBack = {
169
- FeedType: existingParams.FeedType,
170
- FeedSource: existingParams.FeedSource,
171
- fclrEnabled: existingParams.fclrEnabled,
172
- fclrResolution: existingParams.fclrResolution,
173
- rclrEnabled: existingParams.rclrEnabled,
174
- rclrResolution: existingParams.rclrResolution,
175
- fgsEnabled: existingParams.fgsEnabled,
176
- fgsResolution: existingParams.fgsResolution,
177
- rgsEnabled: existingParams.rgsEnabled,
178
- rgsResolution: existingParams.rgsResolution,
179
- fbwEnabled: existingParams.fbwEnabled,
180
- fbwResolution: existingParams.fbwResolution,
181
- rbwEnabled: existingParams.rbwEnabled,
182
- rbwResolution: existingParams.rbwResolution,
183
- rbwThreshold: existingParams.rbwThreshold,
184
- rclrCompressionQuality: existingParams.rclrCompressionQuality,
185
- };
196
+ let setParamsBack = {};
197
+ profile.restoreParamKeys.forEach((key) => {
198
+ if (existingParams[key] !== undefined) {
199
+ setParamsBack[key] = existingParams[key];
200
+ }
201
+ });
186
202
  console.log("Setting Params Back to:", setParamsBack);
187
203
 
188
204
  const setParamsBackSuccess = await setScanParametersBack(
@@ -205,6 +221,7 @@ export async function scannerChain(
205
221
  scanDataResults,
206
222
  licenseFrontBase64: licenseFrontBase64,
207
223
  licenseBackBase64: licenseBackBase64,
224
+ scannerProfile: profileName,
208
225
  errorMessages,
209
226
  };
210
227
  }
@@ -231,6 +248,9 @@ async function makeApiCall(endpointFunction, commandObj, scannerAddress) {
231
248
 
232
249
  // step 1 - start connection
233
250
  async function openConnection(optConnectionParams) {
251
+ // Strip out client-only fields that shouldn't be sent to the scanner
252
+ const { scannerProfile, ...connectionParams } = optConnectionParams || {};
253
+
234
254
  let establishConnectionObj = {
235
255
  Command: "Connect",
236
256
  MessageId: "",
@@ -241,15 +261,48 @@ async function openConnection(optConnectionParams) {
241
261
  //if passed in connection params use them on the object
242
262
  establishConnectionObj = {
243
263
  ...establishConnectionObj,
244
- ...optConnectionParams,
264
+ ...connectionParams,
245
265
  };
246
266
  establishConnectionObj.MessageId = getMessageId();
247
- const responseData = await makeApiCall(
248
- API.establishConnection,
249
- establishConnectionObj,
250
- selectedScannerAddress
251
- );
252
- return responseData ? responseData.SessionId : "";
267
+
268
+ // Call the API directly to get the raw response (not filtered by makeApiCall)
269
+ try {
270
+ const res = await API.establishConnection(
271
+ selectedScannerAddress,
272
+ establishConnectionObj
273
+ );
274
+
275
+ // If there's an error, check if we still got a SessionId that needs cleanup
276
+ if (res && res.ErrorInformation !== "OK" && res.ErrorInformation) {
277
+ buildError("Connect Error: " + res.ErrorInformation);
278
+
279
+ // If scanner returned a SessionId even with error, disconnect it
280
+ if (res.SessionId) {
281
+ let disconnectObj = {
282
+ Command: "Disconnect",
283
+ MessageId: getMessageId(),
284
+ SessionId: res.SessionId,
285
+ };
286
+ try {
287
+ await API.closeConnection(selectedScannerAddress, disconnectObj);
288
+ } catch (disconnectError) {
289
+ // Log cleanup/Disconnect failure separately so it doesn't mask the original connect error
290
+ buildError(
291
+ "Disconnect Error during Connect cleanup: " +
292
+ (disconnectError.message || disconnectError)
293
+ );
294
+ }
295
+ }
296
+
297
+ return "";
298
+ }
299
+
300
+ return res ? res.SessionId : "";
301
+ } catch (error) {
302
+ const errorMessage = error?.message ?? String(error);
303
+ buildError("Connect Error: " + errorMessage);
304
+ return "";
305
+ }
253
306
  }
254
307
 
255
308
  // step 2 - get parameters
@@ -287,32 +340,17 @@ async function resetScanParameters(currentSessionId) {
287
340
  }
288
341
 
289
342
  // step 4 - set parameters
290
- async function setScanParameters(currentSessionId, optScannerParams) {
343
+ async function setScanParameters(currentSessionId, profile, optScannerParams) {
291
344
  let newSetParamsObj = {
292
345
  Command: "SetParameters",
293
346
  MessageId: getMessageId(),
294
347
  SessionId: currentSessionId,
295
348
  Params: {
296
- FeedType: "single",
297
- FeedSource: "id",
298
- fbwResolution: "300dpi",
299
- fclrResolution: "300dpi",
300
- rbwResolution: "300dpi",
301
- rclrResolution: "300dpi",
302
- rclrCompressionQuality: "100",
303
- rbwThreshold: "95",
304
- fclrEnabled: "true",
305
- rgsEnabled: "false",
306
- rbwEnabled: "false",
307
- rclrEnabled: "true",
349
+ ...profile.defaultParams,
350
+ ...optScannerParams,
308
351
  },
309
352
  };
310
353
 
311
- //use the optionally passed in scanner params if any
312
- newSetParamsObj.Params = {
313
- ...newSetParamsObj.Params,
314
- ...optScannerParams,
315
- };
316
354
  console.log("Setting Params for ID Scan to:", newSetParamsObj.Params);
317
355
  const responseData = await makeApiCall(
318
356
  API.setParameters,
@@ -323,7 +361,11 @@ async function setScanParameters(currentSessionId, optScannerParams) {
323
361
  }
324
362
 
325
363
  // step 5 - scan document
326
- async function startScanDocument(currentSessionId, optGetDocumentParams) {
364
+ async function startScanDocument(
365
+ currentSessionId,
366
+ profile,
367
+ optGetDocumentParams
368
+ ) {
327
369
  let scanDocumentObj = {
328
370
  Command: "GetDocument",
329
371
  MessageId: getMessageId(),
@@ -351,12 +393,12 @@ async function startScanDocument(currentSessionId, optGetDocumentParams) {
351
393
 
352
394
  const images = responseData.Images || [];
353
395
 
354
- // Check and set image data
396
+ // Check and set image data using profile-defined image types
355
397
  images.forEach((element) => {
356
- if (element["ImageType"] === "fclr") {
398
+ if (element["ImageType"] === profile.frontImageType) {
357
399
  licenseFrontBase64 = element["data"];
358
400
  }
359
- if (element["ImageType"] === "rclr") {
401
+ if (element["ImageType"] === profile.backImageType) {
360
402
  licenseBackBase64 = element["data"];
361
403
  }
362
404
  });
@@ -0,0 +1,118 @@
1
+ // Scanner profile configurations for different scanner models
2
+
3
+ const PROFILES = {
4
+ DigitalCheck: {
5
+ defaultParams: {
6
+ FeedType: "single",
7
+ FeedSource: "id",
8
+ fbwResolution: "300dpi",
9
+ fclrResolution: "300dpi",
10
+ rbwResolution: "300dpi",
11
+ rclrResolution: "300dpi",
12
+ rclrCompressionQuality: "100",
13
+ rbwThreshold: "95",
14
+ fclrEnabled: "true",
15
+ rgsEnabled: "false",
16
+ rbwEnabled: "false",
17
+ rclrEnabled: "true",
18
+ },
19
+ restoreParamKeys: [
20
+ "FeedType",
21
+ "FeedSource",
22
+ "fclrEnabled",
23
+ "fclrResolution",
24
+ "rclrEnabled",
25
+ "rclrResolution",
26
+ "fgsEnabled",
27
+ "fgsResolution",
28
+ "rgsEnabled",
29
+ "rgsResolution",
30
+ "fbwEnabled",
31
+ "fbwResolution",
32
+ "rbwEnabled",
33
+ "rbwResolution",
34
+ "rbwThreshold",
35
+ "rclrCompressionQuality",
36
+ ],
37
+ frontImageType: "fclr",
38
+ backImageType: "rclr",
39
+ licenseIdentifierField: "ScannerMAC",
40
+ licenseIdentifierFallback: "ScannerSerial",
41
+ },
42
+
43
+ IDXpress: {
44
+ defaultParams: {
45
+ FeedType: "single",
46
+ FeedSource: "id",
47
+ fclrResolution: "600dpi",
48
+ rclrResolution: "600dpi",
49
+ rclrCompressionQuality: "100",
50
+ fclrEnabled: "true",
51
+ rgsEnabled: "false",
52
+ rclrEnabled: "true",
53
+ },
54
+ restoreParamKeys: [
55
+ "FeedType",
56
+ "FeedSource",
57
+ "fclrEnabled",
58
+ "fclrResolution",
59
+ "rclrEnabled",
60
+ "rclrResolution",
61
+ "fgsEnabled",
62
+ "fgsResolution",
63
+ "rgsEnabled",
64
+ "rgsResolution",
65
+ "rclrCompressionQuality",
66
+ ],
67
+ frontImageType: "fclr",
68
+ backImageType: "rclr",
69
+ licenseIdentifierField: "ScannerMAC",
70
+ licenseIdentifierFallback: "ScannerSerial",
71
+ },
72
+
73
+ IDXpressPlus: {
74
+ defaultParams: {
75
+ FeedType: "single",
76
+ FeedSource: "id",
77
+ fclrResolution: "600dpi",
78
+ rclrResolution: "600dpi",
79
+ rclrCompressionQuality: "100",
80
+ fclrEnabled: "true",
81
+ rgsEnabled: "false",
82
+ rclrEnabled: "true",
83
+ },
84
+ restoreParamKeys: [
85
+ "FeedType",
86
+ "FeedSource",
87
+ "fclrEnabled",
88
+ "fclrResolution",
89
+ "rclrEnabled",
90
+ "rclrResolution",
91
+ "fgsEnabled",
92
+ "fgsResolution",
93
+ "rgsEnabled",
94
+ "rgsResolution",
95
+ "rclrCompressionQuality",
96
+ ],
97
+ frontImageType: "fclr",
98
+ backImageType: "rclr",
99
+ licenseIdentifierField: "ScannerMAC",
100
+ licenseIdentifierFallback: "ScannerSerial",
101
+ },
102
+ };
103
+
104
+ export function getProfile(profileName) {
105
+ if (!profileName) {
106
+ return PROFILES.DigitalCheck; // Default to DigitalCheck for backward compatibility
107
+ }
108
+
109
+ // Use own-property check to prevent prototype pollution attacks
110
+ const hasOwn =
111
+ typeof Object.hasOwn === "function"
112
+ ? Object.hasOwn(PROFILES, profileName)
113
+ : Object.prototype.hasOwnProperty.call(PROFILES, profileName);
114
+ if (!hasOwn) {
115
+ throw new Error(`Unknown scanner profile: ${profileName}`);
116
+ }
117
+ return PROFILES[profileName];
118
+ }
package/index.d.ts CHANGED
@@ -29,11 +29,16 @@ declare module "verant_id_cloud_scan" {
29
29
  dmvVerificationResult?: any;
30
30
  }>;
31
31
 
32
+ export interface OptionalConnectionParams {
33
+ scannerProfile?: "DigitalCheck" | "IDXpress" | "IDXpressPlus";
34
+ [key: string]: any;
35
+ }
36
+
32
37
  export function scanId(
33
38
  scannerAddress: string,
34
39
  includeData: boolean,
35
40
  clientId: string,
36
- optionalConnectionParams?: any,
41
+ optionalConnectionParams?: OptionalConnectionParams,
37
42
  optionalScannerParams?: any,
38
43
  optionalGetDocumentParams?: any,
39
44
  ): Promise<{
@@ -47,7 +52,15 @@ declare module "verant_id_cloud_scan" {
47
52
  export function localScanId(
48
53
  scannerAddress: string,
49
54
  clientId: string,
50
- ): Promise<boolean>;
55
+ ): Promise<
56
+ | boolean
57
+ | {
58
+ barcodeResultsObject: any;
59
+ licenseFrontBase64: string;
60
+ licenseBackBase64: string;
61
+ errorMessages: string;
62
+ }
63
+ >;
51
64
 
52
65
  export function localContinueScanId(
53
66
  scannerAddress: string,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "verant_id_cloud_scan",
3
- "version": "1.4.5-beta.2",
3
+ "version": "1.4.5-beta.4",
4
4
  "description": "Verant ID Cloud Scan NPM Library",
5
5
  "main": "CloudScan.js",
6
6
  "types": "index.d.ts",