idmission-web-sdk 2.3.200 → 2.3.201

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.
@@ -235,7 +235,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
235
235
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
236
236
  };
237
237
 
238
- var webSdkVersion = '2.3.200';
238
+ var webSdkVersion = '2.3.201';
239
239
 
240
240
  function getPlatform() {
241
241
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -1239,57 +1239,476 @@ function AuthProvider(_a) {
1239
1239
  }, children));
1240
1240
  }
1241
1241
 
1242
- exports.defaultSubmissionUrl = 'https://portal-api.idmission.com/swagger';
1243
- function setDefaultSubmissionUrl(url) {
1244
- exports.defaultSubmissionUrl = url;
1242
+ /**
1243
+ * Parser for AAMVA (American Association of Motor Vehicle Administrators)
1244
+ * PDF417 barcode data found on US and Canadian driver's licenses.
1245
+ */
1246
+ // AAMVA field codes to human-readable labels
1247
+ var AAMVA_FIELD_LABELS = {
1248
+ // Required fields
1249
+ DCS: 'Last Name',
1250
+ DAC: 'First Name',
1251
+ DAD: 'Middle Name',
1252
+ DAA: 'Full Name',
1253
+ // Older AAMVA versions (1-3) use this instead of separate name fields
1254
+ DBB: 'Date of Birth',
1255
+ DBC: 'Sex',
1256
+ DAY: 'Eye Color',
1257
+ DAU: 'Height',
1258
+ DAG: 'Street Address',
1259
+ DAI: 'City',
1260
+ DAJ: 'State',
1261
+ DAK: 'ZIP Code',
1262
+ DAQ: 'License Number',
1263
+ DCF: 'Document Discriminator',
1264
+ DCG: 'Country',
1265
+ DDE: 'Last Name Truncation',
1266
+ DDF: 'First Name Truncation',
1267
+ DDG: 'Middle Name Truncation',
1268
+ // Optional fields
1269
+ DBD: 'Document Issue Date',
1270
+ DBA: 'Document Expiration Date',
1271
+ DCD: 'Jurisdiction Restriction Codes',
1272
+ DCB: 'Jurisdiction Endorsement Codes',
1273
+ DCA: 'Vehicle Class',
1274
+ DCE: 'Weight Range',
1275
+ DCL: 'Race/Ethnicity',
1276
+ DCM: 'Standard Vehicle Classification',
1277
+ DCN: 'Standard Endorsement Code',
1278
+ DCO: 'Standard Restriction Code',
1279
+ DCP: 'Jurisdiction Vehicle Class Description',
1280
+ DCQ: 'Jurisdiction Endorsement Code Description',
1281
+ DCR: 'Jurisdiction Restriction Code Description',
1282
+ DDA: 'Compliance Type',
1283
+ DDB: 'Card Revision Date',
1284
+ DDC: 'HAZMAT Endorsement Expiration Date',
1285
+ DDD: 'Limited Duration Document Indicator',
1286
+ DDH: 'Under 18 Until',
1287
+ DDI: 'Under 19 Until',
1288
+ DDJ: 'Under 21 Until',
1289
+ DDK: 'Organ Donor Indicator',
1290
+ DDL: 'Veteran Indicator',
1291
+ DAW: 'Weight (lbs)',
1292
+ DAX: 'Weight (kg)',
1293
+ DAZ: 'Hair Color',
1294
+ DBN: 'Alias/AKA Last Name',
1295
+ DBG: 'Alias/AKA First Name',
1296
+ DBS: 'Alias/AKA Suffix',
1297
+ DCU: 'Name Suffix',
1298
+ DCT: 'First Name Alias',
1299
+ DAH: 'Street Address Line 2',
1300
+ DAL: 'Residence Street Address',
1301
+ DAN: 'Residence City',
1302
+ DAO: 'Residence State',
1303
+ DAP: 'Residence ZIP'
1304
+ };
1305
+ // Sex code mappings
1306
+ var SEX_CODES = {
1307
+ '1': 'Male',
1308
+ '2': 'Female',
1309
+ '9': 'Not Specified'
1310
+ };
1311
+ // Eye color code mappings
1312
+ var EYE_COLOR_CODES = {
1313
+ BLK: 'Black',
1314
+ BLU: 'Blue',
1315
+ BRO: 'Brown',
1316
+ GRY: 'Gray',
1317
+ GRN: 'Green',
1318
+ HAZ: 'Hazel',
1319
+ MAR: 'Maroon',
1320
+ PNK: 'Pink',
1321
+ DIC: 'Dichromatic',
1322
+ UNK: 'Unknown'
1323
+ };
1324
+ // Hair color code mappings
1325
+ var HAIR_COLOR_CODES = {
1326
+ BAL: 'Bald',
1327
+ BLK: 'Black',
1328
+ BLN: 'Blond',
1329
+ BRO: 'Brown',
1330
+ GRY: 'Gray',
1331
+ RED: 'Red/Auburn',
1332
+ SDY: 'Sandy',
1333
+ WHI: 'White',
1334
+ UNK: 'Unknown'
1335
+ };
1336
+ /**
1337
+ * Formats a date string from AAMVA format to readable format (MM/DD/YYYY).
1338
+ * AAMVA versions 1-3 use YYYYMMDD (CCYYMMDD) format.
1339
+ * AAMVA versions 4+ use MMDDYYYY (MMDDCCYY) format.
1340
+ */
1341
+ function formatDate(value, aamvaVersion) {
1342
+ if (value.length !== 8) return value;
1343
+ // AAMVA versions 1-3 (pre-2000) use YYYYMMDD format
1344
+ // AAMVA versions 4+ (2000 onwards) use MMDDYYYY format
1345
+ var usesYYYYMMDD = aamvaVersion !== undefined && aamvaVersion <= 3;
1346
+ var month, day, year;
1347
+ if (usesYYYYMMDD) {
1348
+ // YYYYMMDD format (older versions)
1349
+ year = value.substring(0, 4);
1350
+ month = value.substring(4, 6);
1351
+ day = value.substring(6, 8);
1352
+ } else {
1353
+ // MMDDYYYY format (newer versions, default)
1354
+ month = value.substring(0, 2);
1355
+ day = value.substring(2, 4);
1356
+ year = value.substring(4, 8);
1357
+ }
1358
+ return "".concat(month, "/").concat(day, "/").concat(year);
1245
1359
  }
1246
- var defaultDocumentServiceUrl = 'https://portal-api.idmission.com/files/';
1247
- function setDefaultDocumentServiceUrl(url) {
1248
- defaultDocumentServiceUrl = url;
1360
+ /**
1361
+ * Formats a value based on its field code
1362
+ */
1363
+ function formatValue$1(code, value, aamvaVersion) {
1364
+ // Date fields
1365
+ if (['DBB', 'DBD', 'DBA', 'DDB', 'DDC', 'DDH', 'DDI', 'DDJ'].includes(code)) {
1366
+ return formatDate(value, aamvaVersion);
1367
+ }
1368
+ // Sex field
1369
+ if (code === 'DBC') {
1370
+ return SEX_CODES[value] || value;
1371
+ }
1372
+ // Eye color
1373
+ if (code === 'DAY') {
1374
+ return EYE_COLOR_CODES[value] || value;
1375
+ }
1376
+ // Hair color
1377
+ if (code === 'DAZ') {
1378
+ return HAIR_COLOR_CODES[value] || value;
1379
+ }
1380
+ // Height - format as feet and inches
1381
+ if (code === 'DAU') {
1382
+ // Format is typically "XXX in" or "FT IN"
1383
+ var match = value.match(/^(\d{3})/);
1384
+ if (match) {
1385
+ var inches = parseInt(match[1], 10);
1386
+ var feet = Math.floor(inches / 12);
1387
+ var remainingInches = inches % 12;
1388
+ return "".concat(feet, "'").concat(remainingInches, "\"");
1389
+ }
1390
+ return value;
1391
+ }
1392
+ // ZIP code - format with hyphen if 9 digits
1393
+ if (code === 'DAK' && value.length === 9) {
1394
+ return "".concat(value.substring(0, 5), "-").concat(value.substring(5));
1395
+ }
1396
+ return value.trim();
1249
1397
  }
1250
- function setServerUrl(url) {
1251
- setDefaultAuthUrl(url);
1252
- setDefaultSubmissionUrl(url + '/swagger');
1253
- setDefaultDocumentServiceUrl(url + '/files/');
1398
+ /**
1399
+ * Extracts the AAMVA version from the barcode header.
1400
+ * Header format: ANSI <IIN(6 digits)><AAMVA Version(2 digits)><Jurisdiction Version(2 digits)>...
1401
+ * Returns undefined if version cannot be determined.
1402
+ */
1403
+ function extractAAMVAVersion(rawData) {
1404
+ // Match ANSI followed by at least 8 digits (6 for IIN + 2 for version)
1405
+ var headerMatch = rawData.match(/ANSI\s*(\d{6})(\d{2})/);
1406
+ if (headerMatch) {
1407
+ var version = parseInt(headerMatch[2], 10);
1408
+ // Valid AAMVA versions are 1-99 (realistically 1-10 as of 2024)
1409
+ if (version >= 1 && version <= 99) {
1410
+ return version;
1411
+ }
1412
+ }
1413
+ return undefined;
1254
1414
  }
1255
- var capturedDocumentTypeToSubmissionKey = {
1256
- idCardFront: 'idFrontImage',
1257
- idCardBack: 'idBackImage',
1258
- passport: 'passportImage',
1259
- singlePage: 'idFrontImage',
1260
- selfie: 'selfieImage',
1261
- idFrontIrImage: 'idFrontIrImage',
1262
- idBackIrImage: 'idBackIrImage',
1263
- idFrontUvImage: 'idFrontUvImage',
1264
- idBackUvImage: 'idBackUvImage',
1265
- idBarcodeImage: 'idBarcodeImage'
1266
- };
1267
- var sanitizeMetadata = function sanitizeMetadata(metadata) {
1268
- var entries = Object.entries(metadata).filter(function (_a) {
1269
- var value = _a[1];
1270
- return value !== undefined && value !== null;
1415
+ /**
1416
+ * Parses the DAA field (full name) used in older AAMVA versions.
1417
+ * Format is typically "LAST,FIRST,MIDDLE" or "LAST,FIRST MIDDLE".
1418
+ * Returns an array of ParsedAAMVAField for LastName, FirstName, and MiddleName.
1419
+ */
1420
+ function parseDAAField(value) {
1421
+ var fields = [];
1422
+ // DAA format is typically "LASTNAME,FIRSTNAME,MIDDLENAME" or "LASTNAME,FIRSTNAME MIDDLENAME"
1423
+ // Some jurisdictions use spaces instead of commas
1424
+ var parts = value.split(',').map(function (p) {
1425
+ return p.trim();
1271
1426
  });
1272
- if (!entries.length) return null;
1273
- return Object.fromEntries(entries);
1274
- };
1275
- var SubmissionContext = /*#__PURE__*/React.createContext({
1276
- submit: function submit() {
1277
- return __awaiter(void 0, void 0, void 0, function () {
1278
- return __generator(this, function (_a) {
1279
- return [2 /*return*/, null];
1427
+ if (parts.length >= 1 && parts[0]) {
1428
+ fields.push({
1429
+ code: 'DCS',
1430
+ label: 'Last Name',
1431
+ value: parts[0]
1432
+ });
1433
+ }
1434
+ if (parts.length >= 2 && parts[1]) {
1435
+ // The second part might contain "FIRSTNAME MIDDLENAME"
1436
+ var nameParts = parts[1].split(/\s+/);
1437
+ if (nameParts[0]) {
1438
+ fields.push({
1439
+ code: 'DAC',
1440
+ label: 'First Name',
1441
+ value: nameParts[0]
1442
+ });
1443
+ }
1444
+ // If there's more after the first name, treat it as middle name
1445
+ if (nameParts.length > 1) {
1446
+ fields.push({
1447
+ code: 'DAD',
1448
+ label: 'Middle Name',
1449
+ value: nameParts.slice(1).join(' ')
1280
1450
  });
1451
+ }
1452
+ }
1453
+ // If there's a third comma-separated part, it's the middle name
1454
+ if (parts.length >= 3 && parts[2]) {
1455
+ // Check if we already added a middle name from the second part
1456
+ var existingMiddle = fields.find(function (f) {
1457
+ return f.code === 'DAD';
1281
1458
  });
1282
- },
1283
- submissionStatus: SubmissionStatus.READY,
1284
- submissionRequest: null,
1285
- submissionResponse: null,
1286
- submissionError: null,
1287
- submissionEnvironment: 'prod',
1288
- idFrontImage: null,
1289
- idBackImage: null,
1290
- passportImage: null,
1291
- idFrontIrImage: null,
1292
- idBackIrImage: null,
1459
+ if (!existingMiddle) {
1460
+ fields.push({
1461
+ code: 'DAD',
1462
+ label: 'Middle Name',
1463
+ value: parts[2]
1464
+ });
1465
+ }
1466
+ }
1467
+ return fields;
1468
+ }
1469
+ /**
1470
+ * Parses AAMVA PDF417 barcode data into structured fields
1471
+ */
1472
+ function parseAAMVABarcode(rawData) {
1473
+ var result = {
1474
+ fields: [],
1475
+ rawData: rawData
1476
+ };
1477
+ // Extract AAMVA version first - needed for date format detection
1478
+ result.aamvaVersion = extractAAMVAVersion(rawData);
1479
+ // Extract jurisdiction ID from header
1480
+ var headerMatch = rawData.match(/ANSI\s*(\d{6})/);
1481
+ if (headerMatch) {
1482
+ result.jurisdictionId = headerMatch[1];
1483
+ }
1484
+ // Clean up the data - remove control characters but keep newlines for parsing
1485
+ // AAMVA uses various separators: \n, \r, record separator (0x1E), etc.
1486
+ // eslint-disable-next-line no-control-regex
1487
+ var controlCharRegex = /[\x00-\x09\x0B\x0C\x0E-\x1F]/g;
1488
+ var cleanData = rawData.replace(controlCharRegex, '\n') // Replace control chars with newlines
1489
+ .replace(/\r\n/g, '\n').replace(/\r/g, '\n');
1490
+ // Split into lines
1491
+ var lines = cleanData.split('\n').filter(function (line) {
1492
+ return line.trim();
1493
+ });
1494
+ // Extract fields using regex - AAMVA fields are 3-letter codes followed by data
1495
+ var fieldRegex = /^([A-Z]{3})(.*)$/;
1496
+ // Track if we've seen separate name fields (DCS, DAC, DAD)
1497
+ var hasSeenNameFields = {
1498
+ DCS: false,
1499
+ DAC: false,
1500
+ DAD: false
1501
+ };
1502
+ var daaValue = null;
1503
+ for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
1504
+ var line = lines_1[_i];
1505
+ var match = line.match(fieldRegex);
1506
+ if (match) {
1507
+ var code = match[1],
1508
+ rawValue = match[2];
1509
+ var value = rawValue.trim();
1510
+ // Skip empty values and header/version info
1511
+ if (!value || code === 'ANS') continue;
1512
+ // Track name fields
1513
+ if (code === 'DCS' || code === 'DAC' || code === 'DAD') {
1514
+ hasSeenNameFields[code] = true;
1515
+ }
1516
+ // Store DAA value for later processing (in case no separate name fields exist)
1517
+ if (code === 'DAA') {
1518
+ daaValue = value;
1519
+ continue; // Don't add DAA directly, we'll process it below
1520
+ }
1521
+ var label = AAMVA_FIELD_LABELS[code] || code;
1522
+ var formattedValue = formatValue$1(code, value, result.aamvaVersion);
1523
+ result.fields.push({
1524
+ code: code,
1525
+ label: label,
1526
+ value: formattedValue
1527
+ });
1528
+ }
1529
+ }
1530
+ // If we have a DAA field and are missing any separate name fields, parse DAA
1531
+ if (daaValue && (!hasSeenNameFields.DCS || !hasSeenNameFields.DAC)) {
1532
+ var daaFields = parseDAAField(daaValue);
1533
+ var _loop_1 = function _loop_1(field) {
1534
+ // Only add if we don't already have this field
1535
+ var existingField = result.fields.find(function (f) {
1536
+ return f.code === field.code;
1537
+ });
1538
+ if (!existingField) {
1539
+ result.fields.push(field);
1540
+ }
1541
+ };
1542
+ for (var _a = 0, daaFields_1 = daaFields; _a < daaFields_1.length; _a++) {
1543
+ var field = daaFields_1[_a];
1544
+ _loop_1(field);
1545
+ }
1546
+ }
1547
+ return result;
1548
+ }
1549
+ /**
1550
+ * Gets a specific field value from parsed AAMVA data
1551
+ */
1552
+ function getAAMVAField(parsed, code) {
1553
+ var field = parsed.fields.find(function (f) {
1554
+ return f.code === code;
1555
+ });
1556
+ return field === null || field === void 0 ? void 0 : field.value;
1557
+ }
1558
+ /**
1559
+ * Converts a date from MM/DD/YYYY format to DD/MM/YYYY format.
1560
+ * Returns empty string if input is empty or invalid.
1561
+ */
1562
+ function convertToApiDateFormat(dateStr) {
1563
+ if (!dateStr) return '';
1564
+ var parts = dateStr.split('/');
1565
+ if (parts.length !== 3) return dateStr;
1566
+ var month = parts[0],
1567
+ day = parts[1],
1568
+ year = parts[2];
1569
+ return "".concat(day, "/").concat(month, "/").concat(year);
1570
+ }
1571
+ /**
1572
+ * Converts parsed AAMVA barcode data to ocrMetadata format for submission API.
1573
+ * Returns the IDData object ready to be stringified for the ocrMetadata field.
1574
+ */
1575
+ function convertAAMVAToOCRMetadata(parsed) {
1576
+ var getField = function getField(code) {
1577
+ return getAAMVAField(parsed, code);
1578
+ };
1579
+ // Get state code for various fields
1580
+ var state = getField('DAJ') || '';
1581
+ // Determine gender from sex code
1582
+ var sexCode = getField('DBC');
1583
+ var gender = '';
1584
+ if (sexCode === 'Male' || sexCode === '1') gender = 'M';else if (sexCode === 'Female' || sexCode === '2') gender = 'F';
1585
+ // Get dates and convert from MM/DD/YYYY to DD/MM/YYYY format
1586
+ var expiryDate = convertToApiDateFormat(getField('DBA') || '');
1587
+ var issueDate = convertToApiDateFormat(getField('DBD') || '');
1588
+ var dateOfBirth = convertToApiDateFormat(getField('DBB') || '');
1589
+ // Calculate Under21 status based on DOB (using original MM/DD/YYYY format)
1590
+ var under21 = 'N';
1591
+ var rawDob = getField('DBB') || '';
1592
+ if (rawDob) {
1593
+ var parts = rawDob.split('/');
1594
+ if (parts.length === 3) {
1595
+ var month = parseInt(parts[0], 10);
1596
+ var day = parseInt(parts[1], 10);
1597
+ var year = parseInt(parts[2], 10);
1598
+ var dob = new Date(year, month - 1, day);
1599
+ var today = new Date();
1600
+ var age = today.getFullYear() - dob.getFullYear();
1601
+ var monthDiff = today.getMonth() - dob.getMonth();
1602
+ if (monthDiff < 0 || monthDiff === 0 && today.getDate() < dob.getDate()) {
1603
+ if (age - 1 < 21) under21 = 'Y';
1604
+ } else {
1605
+ if (age < 21) under21 = 'Y';
1606
+ }
1607
+ }
1608
+ }
1609
+ var idData = {
1610
+ IDCountry: 'USA',
1611
+ IDCountry_ISO2: 'US',
1612
+ IssuingCountry: 'USA',
1613
+ IDType: 'DL',
1614
+ DocumentTypeCode: 'DL',
1615
+ IDNumber: getField('DAQ') || '',
1616
+ IDState: state,
1617
+ State: state,
1618
+ FirstName: getField('DAC') || '',
1619
+ MiddleName: getField('DAD') || '',
1620
+ LastName: getField('DCS') || '',
1621
+ Gender: gender,
1622
+ DateofBirth: dateOfBirth,
1623
+ DateOfExpiry: expiryDate,
1624
+ ExpiryDate: expiryDate,
1625
+ DateOfIssue: issueDate,
1626
+ IssueDate: issueDate,
1627
+ AddressLine1: getField('DAG') || '',
1628
+ City: getField('DAI') || '',
1629
+ ZipCode: (getField('DAK') || '').replace(/-/g, ''),
1630
+ // Remove hyphen for API
1631
+ Country: 'USA',
1632
+ Eyes: getField('DAY') || '',
1633
+ Under21: under21,
1634
+ BarcodeDataParsed: 'Y'
1635
+ };
1636
+ // Remove empty string values to keep the payload clean
1637
+ var cleanedIdData = Object.fromEntries(Object.entries(idData).filter(function (_a) {
1638
+ var value = _a[1];
1639
+ return value !== '';
1640
+ }));
1641
+ // Always include BarcodeDataParsed
1642
+ cleanedIdData.BarcodeDataParsed = 'Y';
1643
+ return {
1644
+ IDData: cleanedIdData
1645
+ };
1646
+ }
1647
+ /**
1648
+ * Builds the ocrMetadata payload reported when a barcode capture flow ran
1649
+ * but no barcode was successfully parsed. Records the attempt count so the
1650
+ * backend can distinguish "user never tried" from "user tried N times".
1651
+ */
1652
+ function buildNoBarcodeOCRMetadata(attemptCount) {
1653
+ return {
1654
+ IDData: {
1655
+ BarcodeDataParsed: 'N',
1656
+ BarcodeAttemptCount: String(attemptCount)
1657
+ }
1658
+ };
1659
+ }
1660
+
1661
+ exports.defaultSubmissionUrl = 'https://portal-api.idmission.com/swagger';
1662
+ function setDefaultSubmissionUrl(url) {
1663
+ exports.defaultSubmissionUrl = url;
1664
+ }
1665
+ var defaultDocumentServiceUrl = 'https://portal-api.idmission.com/files/';
1666
+ function setDefaultDocumentServiceUrl(url) {
1667
+ defaultDocumentServiceUrl = url;
1668
+ }
1669
+ function setServerUrl(url) {
1670
+ setDefaultAuthUrl(url);
1671
+ setDefaultSubmissionUrl(url + '/swagger');
1672
+ setDefaultDocumentServiceUrl(url + '/files/');
1673
+ }
1674
+ var capturedDocumentTypeToSubmissionKey = {
1675
+ idCardFront: 'idFrontImage',
1676
+ idCardBack: 'idBackImage',
1677
+ passport: 'passportImage',
1678
+ singlePage: 'idFrontImage',
1679
+ selfie: 'selfieImage',
1680
+ idFrontIrImage: 'idFrontIrImage',
1681
+ idBackIrImage: 'idBackIrImage',
1682
+ idFrontUvImage: 'idFrontUvImage',
1683
+ idBackUvImage: 'idBackUvImage',
1684
+ idBarcodeImage: 'idBarcodeImage'
1685
+ };
1686
+ var sanitizeMetadata = function sanitizeMetadata(metadata) {
1687
+ var entries = Object.entries(metadata).filter(function (_a) {
1688
+ var value = _a[1];
1689
+ return value !== undefined && value !== null;
1690
+ });
1691
+ if (!entries.length) return null;
1692
+ return Object.fromEntries(entries);
1693
+ };
1694
+ var SubmissionContext = /*#__PURE__*/React.createContext({
1695
+ submit: function submit() {
1696
+ return __awaiter(void 0, void 0, void 0, function () {
1697
+ return __generator(this, function (_a) {
1698
+ return [2 /*return*/, null];
1699
+ });
1700
+ });
1701
+ },
1702
+ submissionStatus: SubmissionStatus.READY,
1703
+ submissionRequest: null,
1704
+ submissionResponse: null,
1705
+ submissionError: null,
1706
+ submissionEnvironment: 'prod',
1707
+ idFrontImage: null,
1708
+ idBackImage: null,
1709
+ passportImage: null,
1710
+ idFrontIrImage: null,
1711
+ idBackIrImage: null,
1293
1712
  idFrontUvImage: null,
1294
1713
  idBackUvImage: null,
1295
1714
  idBarcodeImage: null,
@@ -1931,6 +2350,8 @@ var SubmissionProvider = function SubmissionProvider(_a) {
1931
2350
  }
1932
2351
  if (ocrMetadata) {
1933
2352
  submissionRequest.additionalData.ocrMetadata = ocrMetadata;
2353
+ } else if (barcodeCaptureAttempts.length > 0) {
2354
+ submissionRequest.additionalData.ocrMetadata = JSON.stringify(buildNoBarcodeOCRMetadata(barcodeCaptureAttempts.length));
1934
2355
  }
1935
2356
  if (signatureData) {
1936
2357
  submissionRequest.customerData.signatureData = {
@@ -10593,412 +11014,6 @@ var Card = styled__default.default.div(templateObject_1$G || (templateObject_1$G
10593
11014
  var FlexCard = styled__default.default(Card)(templateObject_2$C || (templateObject_2$C = __makeTemplateObject(["\n display: flex;\n flex-direction: column;\n"], ["\n display: flex;\n flex-direction: column;\n"])));
10594
11015
  var templateObject_1$G, templateObject_2$C;
10595
11016
 
10596
- /**
10597
- * Parser for AAMVA (American Association of Motor Vehicle Administrators)
10598
- * PDF417 barcode data found on US and Canadian driver's licenses.
10599
- */
10600
- // AAMVA field codes to human-readable labels
10601
- var AAMVA_FIELD_LABELS = {
10602
- // Required fields
10603
- DCS: 'Last Name',
10604
- DAC: 'First Name',
10605
- DAD: 'Middle Name',
10606
- DAA: 'Full Name',
10607
- // Older AAMVA versions (1-3) use this instead of separate name fields
10608
- DBB: 'Date of Birth',
10609
- DBC: 'Sex',
10610
- DAY: 'Eye Color',
10611
- DAU: 'Height',
10612
- DAG: 'Street Address',
10613
- DAI: 'City',
10614
- DAJ: 'State',
10615
- DAK: 'ZIP Code',
10616
- DAQ: 'License Number',
10617
- DCF: 'Document Discriminator',
10618
- DCG: 'Country',
10619
- DDE: 'Last Name Truncation',
10620
- DDF: 'First Name Truncation',
10621
- DDG: 'Middle Name Truncation',
10622
- // Optional fields
10623
- DBD: 'Document Issue Date',
10624
- DBA: 'Document Expiration Date',
10625
- DCD: 'Jurisdiction Restriction Codes',
10626
- DCB: 'Jurisdiction Endorsement Codes',
10627
- DCA: 'Vehicle Class',
10628
- DCE: 'Weight Range',
10629
- DCL: 'Race/Ethnicity',
10630
- DCM: 'Standard Vehicle Classification',
10631
- DCN: 'Standard Endorsement Code',
10632
- DCO: 'Standard Restriction Code',
10633
- DCP: 'Jurisdiction Vehicle Class Description',
10634
- DCQ: 'Jurisdiction Endorsement Code Description',
10635
- DCR: 'Jurisdiction Restriction Code Description',
10636
- DDA: 'Compliance Type',
10637
- DDB: 'Card Revision Date',
10638
- DDC: 'HAZMAT Endorsement Expiration Date',
10639
- DDD: 'Limited Duration Document Indicator',
10640
- DDH: 'Under 18 Until',
10641
- DDI: 'Under 19 Until',
10642
- DDJ: 'Under 21 Until',
10643
- DDK: 'Organ Donor Indicator',
10644
- DDL: 'Veteran Indicator',
10645
- DAW: 'Weight (lbs)',
10646
- DAX: 'Weight (kg)',
10647
- DAZ: 'Hair Color',
10648
- DBN: 'Alias/AKA Last Name',
10649
- DBG: 'Alias/AKA First Name',
10650
- DBS: 'Alias/AKA Suffix',
10651
- DCU: 'Name Suffix',
10652
- DCT: 'First Name Alias',
10653
- DAH: 'Street Address Line 2',
10654
- DAL: 'Residence Street Address',
10655
- DAN: 'Residence City',
10656
- DAO: 'Residence State',
10657
- DAP: 'Residence ZIP'
10658
- };
10659
- // Sex code mappings
10660
- var SEX_CODES = {
10661
- '1': 'Male',
10662
- '2': 'Female',
10663
- '9': 'Not Specified'
10664
- };
10665
- // Eye color code mappings
10666
- var EYE_COLOR_CODES = {
10667
- BLK: 'Black',
10668
- BLU: 'Blue',
10669
- BRO: 'Brown',
10670
- GRY: 'Gray',
10671
- GRN: 'Green',
10672
- HAZ: 'Hazel',
10673
- MAR: 'Maroon',
10674
- PNK: 'Pink',
10675
- DIC: 'Dichromatic',
10676
- UNK: 'Unknown'
10677
- };
10678
- // Hair color code mappings
10679
- var HAIR_COLOR_CODES = {
10680
- BAL: 'Bald',
10681
- BLK: 'Black',
10682
- BLN: 'Blond',
10683
- BRO: 'Brown',
10684
- GRY: 'Gray',
10685
- RED: 'Red/Auburn',
10686
- SDY: 'Sandy',
10687
- WHI: 'White',
10688
- UNK: 'Unknown'
10689
- };
10690
- /**
10691
- * Formats a date string from AAMVA format to readable format (MM/DD/YYYY).
10692
- * AAMVA versions 1-3 use YYYYMMDD (CCYYMMDD) format.
10693
- * AAMVA versions 4+ use MMDDYYYY (MMDDCCYY) format.
10694
- */
10695
- function formatDate(value, aamvaVersion) {
10696
- if (value.length !== 8) return value;
10697
- // AAMVA versions 1-3 (pre-2000) use YYYYMMDD format
10698
- // AAMVA versions 4+ (2000 onwards) use MMDDYYYY format
10699
- var usesYYYYMMDD = aamvaVersion !== undefined && aamvaVersion <= 3;
10700
- var month, day, year;
10701
- if (usesYYYYMMDD) {
10702
- // YYYYMMDD format (older versions)
10703
- year = value.substring(0, 4);
10704
- month = value.substring(4, 6);
10705
- day = value.substring(6, 8);
10706
- } else {
10707
- // MMDDYYYY format (newer versions, default)
10708
- month = value.substring(0, 2);
10709
- day = value.substring(2, 4);
10710
- year = value.substring(4, 8);
10711
- }
10712
- return "".concat(month, "/").concat(day, "/").concat(year);
10713
- }
10714
- /**
10715
- * Formats a value based on its field code
10716
- */
10717
- function formatValue$1(code, value, aamvaVersion) {
10718
- // Date fields
10719
- if (['DBB', 'DBD', 'DBA', 'DDB', 'DDC', 'DDH', 'DDI', 'DDJ'].includes(code)) {
10720
- return formatDate(value, aamvaVersion);
10721
- }
10722
- // Sex field
10723
- if (code === 'DBC') {
10724
- return SEX_CODES[value] || value;
10725
- }
10726
- // Eye color
10727
- if (code === 'DAY') {
10728
- return EYE_COLOR_CODES[value] || value;
10729
- }
10730
- // Hair color
10731
- if (code === 'DAZ') {
10732
- return HAIR_COLOR_CODES[value] || value;
10733
- }
10734
- // Height - format as feet and inches
10735
- if (code === 'DAU') {
10736
- // Format is typically "XXX in" or "FT IN"
10737
- var match = value.match(/^(\d{3})/);
10738
- if (match) {
10739
- var inches = parseInt(match[1], 10);
10740
- var feet = Math.floor(inches / 12);
10741
- var remainingInches = inches % 12;
10742
- return "".concat(feet, "'").concat(remainingInches, "\"");
10743
- }
10744
- return value;
10745
- }
10746
- // ZIP code - format with hyphen if 9 digits
10747
- if (code === 'DAK' && value.length === 9) {
10748
- return "".concat(value.substring(0, 5), "-").concat(value.substring(5));
10749
- }
10750
- return value.trim();
10751
- }
10752
- /**
10753
- * Extracts the AAMVA version from the barcode header.
10754
- * Header format: ANSI <IIN(6 digits)><AAMVA Version(2 digits)><Jurisdiction Version(2 digits)>...
10755
- * Returns undefined if version cannot be determined.
10756
- */
10757
- function extractAAMVAVersion(rawData) {
10758
- // Match ANSI followed by at least 8 digits (6 for IIN + 2 for version)
10759
- var headerMatch = rawData.match(/ANSI\s*(\d{6})(\d{2})/);
10760
- if (headerMatch) {
10761
- var version = parseInt(headerMatch[2], 10);
10762
- // Valid AAMVA versions are 1-99 (realistically 1-10 as of 2024)
10763
- if (version >= 1 && version <= 99) {
10764
- return version;
10765
- }
10766
- }
10767
- return undefined;
10768
- }
10769
- /**
10770
- * Parses the DAA field (full name) used in older AAMVA versions.
10771
- * Format is typically "LAST,FIRST,MIDDLE" or "LAST,FIRST MIDDLE".
10772
- * Returns an array of ParsedAAMVAField for LastName, FirstName, and MiddleName.
10773
- */
10774
- function parseDAAField(value) {
10775
- var fields = [];
10776
- // DAA format is typically "LASTNAME,FIRSTNAME,MIDDLENAME" or "LASTNAME,FIRSTNAME MIDDLENAME"
10777
- // Some jurisdictions use spaces instead of commas
10778
- var parts = value.split(',').map(function (p) {
10779
- return p.trim();
10780
- });
10781
- if (parts.length >= 1 && parts[0]) {
10782
- fields.push({
10783
- code: 'DCS',
10784
- label: 'Last Name',
10785
- value: parts[0]
10786
- });
10787
- }
10788
- if (parts.length >= 2 && parts[1]) {
10789
- // The second part might contain "FIRSTNAME MIDDLENAME"
10790
- var nameParts = parts[1].split(/\s+/);
10791
- if (nameParts[0]) {
10792
- fields.push({
10793
- code: 'DAC',
10794
- label: 'First Name',
10795
- value: nameParts[0]
10796
- });
10797
- }
10798
- // If there's more after the first name, treat it as middle name
10799
- if (nameParts.length > 1) {
10800
- fields.push({
10801
- code: 'DAD',
10802
- label: 'Middle Name',
10803
- value: nameParts.slice(1).join(' ')
10804
- });
10805
- }
10806
- }
10807
- // If there's a third comma-separated part, it's the middle name
10808
- if (parts.length >= 3 && parts[2]) {
10809
- // Check if we already added a middle name from the second part
10810
- var existingMiddle = fields.find(function (f) {
10811
- return f.code === 'DAD';
10812
- });
10813
- if (!existingMiddle) {
10814
- fields.push({
10815
- code: 'DAD',
10816
- label: 'Middle Name',
10817
- value: parts[2]
10818
- });
10819
- }
10820
- }
10821
- return fields;
10822
- }
10823
- /**
10824
- * Parses AAMVA PDF417 barcode data into structured fields
10825
- */
10826
- function parseAAMVABarcode(rawData) {
10827
- var result = {
10828
- fields: [],
10829
- rawData: rawData
10830
- };
10831
- // Extract AAMVA version first - needed for date format detection
10832
- result.aamvaVersion = extractAAMVAVersion(rawData);
10833
- // Extract jurisdiction ID from header
10834
- var headerMatch = rawData.match(/ANSI\s*(\d{6})/);
10835
- if (headerMatch) {
10836
- result.jurisdictionId = headerMatch[1];
10837
- }
10838
- // Clean up the data - remove control characters but keep newlines for parsing
10839
- // AAMVA uses various separators: \n, \r, record separator (0x1E), etc.
10840
- // eslint-disable-next-line no-control-regex
10841
- var controlCharRegex = /[\x00-\x09\x0B\x0C\x0E-\x1F]/g;
10842
- var cleanData = rawData.replace(controlCharRegex, '\n') // Replace control chars with newlines
10843
- .replace(/\r\n/g, '\n').replace(/\r/g, '\n');
10844
- // Split into lines
10845
- var lines = cleanData.split('\n').filter(function (line) {
10846
- return line.trim();
10847
- });
10848
- // Extract fields using regex - AAMVA fields are 3-letter codes followed by data
10849
- var fieldRegex = /^([A-Z]{3})(.*)$/;
10850
- // Track if we've seen separate name fields (DCS, DAC, DAD)
10851
- var hasSeenNameFields = {
10852
- DCS: false,
10853
- DAC: false,
10854
- DAD: false
10855
- };
10856
- var daaValue = null;
10857
- for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
10858
- var line = lines_1[_i];
10859
- var match = line.match(fieldRegex);
10860
- if (match) {
10861
- var code = match[1],
10862
- rawValue = match[2];
10863
- var value = rawValue.trim();
10864
- // Skip empty values and header/version info
10865
- if (!value || code === 'ANS') continue;
10866
- // Track name fields
10867
- if (code === 'DCS' || code === 'DAC' || code === 'DAD') {
10868
- hasSeenNameFields[code] = true;
10869
- }
10870
- // Store DAA value for later processing (in case no separate name fields exist)
10871
- if (code === 'DAA') {
10872
- daaValue = value;
10873
- continue; // Don't add DAA directly, we'll process it below
10874
- }
10875
- var label = AAMVA_FIELD_LABELS[code] || code;
10876
- var formattedValue = formatValue$1(code, value, result.aamvaVersion);
10877
- result.fields.push({
10878
- code: code,
10879
- label: label,
10880
- value: formattedValue
10881
- });
10882
- }
10883
- }
10884
- // If we have a DAA field and are missing any separate name fields, parse DAA
10885
- if (daaValue && (!hasSeenNameFields.DCS || !hasSeenNameFields.DAC)) {
10886
- var daaFields = parseDAAField(daaValue);
10887
- var _loop_1 = function _loop_1(field) {
10888
- // Only add if we don't already have this field
10889
- var existingField = result.fields.find(function (f) {
10890
- return f.code === field.code;
10891
- });
10892
- if (!existingField) {
10893
- result.fields.push(field);
10894
- }
10895
- };
10896
- for (var _a = 0, daaFields_1 = daaFields; _a < daaFields_1.length; _a++) {
10897
- var field = daaFields_1[_a];
10898
- _loop_1(field);
10899
- }
10900
- }
10901
- return result;
10902
- }
10903
- /**
10904
- * Gets a specific field value from parsed AAMVA data
10905
- */
10906
- function getAAMVAField(parsed, code) {
10907
- var field = parsed.fields.find(function (f) {
10908
- return f.code === code;
10909
- });
10910
- return field === null || field === void 0 ? void 0 : field.value;
10911
- }
10912
- /**
10913
- * Converts a date from MM/DD/YYYY format to DD/MM/YYYY format.
10914
- * Returns empty string if input is empty or invalid.
10915
- */
10916
- function convertToApiDateFormat(dateStr) {
10917
- if (!dateStr) return '';
10918
- var parts = dateStr.split('/');
10919
- if (parts.length !== 3) return dateStr;
10920
- var month = parts[0],
10921
- day = parts[1],
10922
- year = parts[2];
10923
- return "".concat(day, "/").concat(month, "/").concat(year);
10924
- }
10925
- /**
10926
- * Converts parsed AAMVA barcode data to ocrMetadata format for submission API.
10927
- * Returns the IDData object ready to be stringified for the ocrMetadata field.
10928
- */
10929
- function convertAAMVAToOCRMetadata(parsed) {
10930
- var getField = function getField(code) {
10931
- return getAAMVAField(parsed, code);
10932
- };
10933
- // Get state code for various fields
10934
- var state = getField('DAJ') || '';
10935
- // Determine gender from sex code
10936
- var sexCode = getField('DBC');
10937
- var gender = '';
10938
- if (sexCode === 'Male' || sexCode === '1') gender = 'M';else if (sexCode === 'Female' || sexCode === '2') gender = 'F';
10939
- // Get dates and convert from MM/DD/YYYY to DD/MM/YYYY format
10940
- var expiryDate = convertToApiDateFormat(getField('DBA') || '');
10941
- var issueDate = convertToApiDateFormat(getField('DBD') || '');
10942
- var dateOfBirth = convertToApiDateFormat(getField('DBB') || '');
10943
- // Calculate Under21 status based on DOB (using original MM/DD/YYYY format)
10944
- var under21 = 'N';
10945
- var rawDob = getField('DBB') || '';
10946
- if (rawDob) {
10947
- var parts = rawDob.split('/');
10948
- if (parts.length === 3) {
10949
- var month = parseInt(parts[0], 10);
10950
- var day = parseInt(parts[1], 10);
10951
- var year = parseInt(parts[2], 10);
10952
- var dob = new Date(year, month - 1, day);
10953
- var today = new Date();
10954
- var age = today.getFullYear() - dob.getFullYear();
10955
- var monthDiff = today.getMonth() - dob.getMonth();
10956
- if (monthDiff < 0 || monthDiff === 0 && today.getDate() < dob.getDate()) {
10957
- if (age - 1 < 21) under21 = 'Y';
10958
- } else {
10959
- if (age < 21) under21 = 'Y';
10960
- }
10961
- }
10962
- }
10963
- var idData = {
10964
- IDCountry: 'USA',
10965
- IDCountry_ISO2: 'US',
10966
- IssuingCountry: 'USA',
10967
- IDType: 'DL',
10968
- DocumentTypeCode: 'DL',
10969
- IDNumber: getField('DAQ') || '',
10970
- IDState: state,
10971
- State: state,
10972
- FirstName: getField('DAC') || '',
10973
- MiddleName: getField('DAD') || '',
10974
- LastName: getField('DCS') || '',
10975
- Gender: gender,
10976
- DateofBirth: dateOfBirth,
10977
- DateOfExpiry: expiryDate,
10978
- ExpiryDate: expiryDate,
10979
- DateOfIssue: issueDate,
10980
- IssueDate: issueDate,
10981
- AddressLine1: getField('DAG') || '',
10982
- City: getField('DAI') || '',
10983
- ZipCode: (getField('DAK') || '').replace(/-/g, ''),
10984
- // Remove hyphen for API
10985
- Country: 'USA',
10986
- Eyes: getField('DAY') || '',
10987
- Under21: under21,
10988
- BarcodeDataParsed: 'Y'
10989
- };
10990
- // Remove empty string values to keep the payload clean
10991
- var cleanedIdData = Object.fromEntries(Object.entries(idData).filter(function (_a) {
10992
- var value = _a[1];
10993
- return value !== '';
10994
- }));
10995
- // Always include BarcodeDataParsed
10996
- cleanedIdData.BarcodeDataParsed = 'Y';
10997
- return {
10998
- IDData: cleanedIdData
10999
- };
11000
- }
11001
-
11002
11017
  var imageDisplayOrder = ['idCardFront', 'idCardBack', 'idBarcodeImage', 'passport', 'singlePage', 'idFrontIrImage', 'idBackIrImage', 'idFrontUvImage', 'idBackUvImage'];
11003
11018
  var downloadImage = function downloadImage(dataUrl, filename) {
11004
11019
  var link = document.createElement('a');