vesant-sdk 1.6.6 → 1.7.0-dev.e0ee6d5

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.
Files changed (86) hide show
  1. package/README.md +14 -4
  2. package/dist/{client-ePzhQKp9.d.mts → client-BolQlL5e.d.mts} +1 -1
  3. package/dist/{client-ePzhQKp9.d.ts → client-BolQlL5e.d.ts} +1 -1
  4. package/dist/client-C3DCmGe9.d.ts +436 -0
  5. package/dist/{client-C_A7QLcB.d.ts → client-DMIRx7Tu.d.mts} +5 -3
  6. package/dist/{client-BlCxjbY2.d.mts → client-DoMSYMMR.d.ts} +5 -3
  7. package/dist/client-ZNdnpWe7.d.mts +436 -0
  8. package/dist/compliance/index.d.mts +25 -429
  9. package/dist/compliance/index.d.ts +25 -429
  10. package/dist/compliance/index.js +187 -103
  11. package/dist/compliance/index.js.map +1 -1
  12. package/dist/compliance/index.mjs +187 -104
  13. package/dist/compliance/index.mjs.map +1 -1
  14. package/dist/decisions/index.d.mts +2 -2
  15. package/dist/decisions/index.d.ts +2 -2
  16. package/dist/decisions/index.js +1 -1
  17. package/dist/decisions/index.js.map +1 -1
  18. package/dist/decisions/index.mjs +1 -1
  19. package/dist/decisions/index.mjs.map +1 -1
  20. package/dist/geolocation/index.d.mts +4 -4
  21. package/dist/geolocation/index.d.ts +4 -4
  22. package/dist/geolocation/index.js +7 -24
  23. package/dist/geolocation/index.js.map +1 -1
  24. package/dist/geolocation/index.mjs +7 -24
  25. package/dist/geolocation/index.mjs.map +1 -1
  26. package/dist/index.d.mts +12 -70
  27. package/dist/index.d.ts +12 -70
  28. package/dist/index.js +294 -292
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +293 -291
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/kyc/core.d.mts +4 -4
  33. package/dist/kyc/core.d.ts +4 -4
  34. package/dist/kyc/core.js +78 -23
  35. package/dist/kyc/core.js.map +1 -1
  36. package/dist/kyc/core.mjs +78 -24
  37. package/dist/kyc/core.mjs.map +1 -1
  38. package/dist/kyc/index.d.mts +269 -45
  39. package/dist/kyc/index.d.ts +269 -45
  40. package/dist/kyc/index.js +78 -23
  41. package/dist/kyc/index.js.map +1 -1
  42. package/dist/kyc/index.mjs +78 -24
  43. package/dist/kyc/index.mjs.map +1 -1
  44. package/dist/react.d.mts +42 -7
  45. package/dist/react.d.ts +42 -7
  46. package/dist/react.js +663 -277
  47. package/dist/react.js.map +1 -1
  48. package/dist/react.mjs +663 -277
  49. package/dist/react.mjs.map +1 -1
  50. package/dist/risk-profile/index.d.mts +4 -4
  51. package/dist/risk-profile/index.d.ts +4 -4
  52. package/dist/risk-profile/index.js +1 -1
  53. package/dist/risk-profile/index.js.map +1 -1
  54. package/dist/risk-profile/index.mjs +1 -1
  55. package/dist/risk-profile/index.mjs.map +1 -1
  56. package/dist/scores/index.d.mts +2 -2
  57. package/dist/scores/index.d.ts +2 -2
  58. package/dist/scores/index.js +1 -1
  59. package/dist/scores/index.js.map +1 -1
  60. package/dist/scores/index.mjs +1 -1
  61. package/dist/scores/index.mjs.map +1 -1
  62. package/dist/tax/index.d.mts +6 -41
  63. package/dist/tax/index.d.ts +6 -41
  64. package/dist/tax/index.js +1 -36
  65. package/dist/tax/index.js.map +1 -1
  66. package/dist/tax/index.mjs +1 -36
  67. package/dist/tax/index.mjs.map +1 -1
  68. package/dist/{types-1RzYeSal.d.mts → types-BOFaMQxI.d.mts} +2 -2
  69. package/dist/{types-B4Ezqo7V.d.mts → types-CBQRNL-l.d.mts} +14 -1
  70. package/dist/{types-B4Ezqo7V.d.ts → types-CBQRNL-l.d.ts} +14 -1
  71. package/dist/{types-X5Md_dD_.d.ts → types-UGyDl1fd.d.ts} +2 -2
  72. package/dist/webhooks/index.d.mts +189 -2
  73. package/dist/webhooks/index.d.ts +189 -2
  74. package/dist/webhooks/index.js +49 -7
  75. package/dist/webhooks/index.js.map +1 -1
  76. package/dist/webhooks/index.mjs +49 -7
  77. package/dist/webhooks/index.mjs.map +1 -1
  78. package/package.json +16 -13
  79. package/dist/fraud/index.d.mts +0 -80
  80. package/dist/fraud/index.d.ts +0 -80
  81. package/dist/fraud/index.js +0 -606
  82. package/dist/fraud/index.js.map +0 -1
  83. package/dist/fraud/index.mjs +0 -604
  84. package/dist/fraud/index.mjs.map +0 -1
  85. package/dist/index-B04H4xfJ.d.mts +0 -320
  86. package/dist/index-CItMPmLL.d.ts +0 -320
@@ -1,5 +1,80 @@
1
1
  'use strict';
2
2
 
3
+ // src/compliance/block-reasons.ts
4
+ var sdkReasons = {
5
+ // Jurisdiction
6
+ jurisdictionBlocked: (country, countryISO) => ({
7
+ code: "JURISDICTION_BLOCKED",
8
+ message: "Access from a blocked jurisdiction",
9
+ metadata: { country, country_iso: countryISO }
10
+ }),
11
+ jurisdictionNonCompliant: () => ({
12
+ code: "JURISDICTION_NON_COMPLIANT",
13
+ message: "Location does not meet compliance requirements"
14
+ }),
15
+ jurisdictionRegistrationDenied: () => ({
16
+ code: "JURISDICTION_REGISTRATION_DENIED",
17
+ message: "Registration is not permitted in this jurisdiction"
18
+ }),
19
+ jurisdictionRestricted: () => ({
20
+ code: "JURISDICTION_RESTRICTED",
21
+ message: "Access from a restricted jurisdiction"
22
+ }),
23
+ // Risk
24
+ riskCriticalLevel: () => ({
25
+ code: "RISK_CRITICAL_LEVEL",
26
+ message: "Risk assessment reached critical threshold"
27
+ }),
28
+ accountSuspended: () => ({
29
+ code: "RISK_ACCOUNT_SUSPENDED",
30
+ message: "Customer account is suspended"
31
+ }),
32
+ sanctionsMatch: () => ({
33
+ code: "RISK_SANCTIONS_MATCH",
34
+ message: "Customer profile matched against sanctions list"
35
+ }),
36
+ riskHighLocation: () => ({
37
+ code: "RISK_HIGH_LOCATION",
38
+ message: "High-risk geographic location"
39
+ }),
40
+ riskHighCustomer: () => ({
41
+ code: "RISK_HIGH_CUSTOMER",
42
+ message: "Customer flagged as high risk"
43
+ }),
44
+ // Device
45
+ ciphertextInvalid: () => ({
46
+ code: "DEVICE_CIPHERTEXT_INVALID",
47
+ message: "Device verification payload failed validation"
48
+ }),
49
+ gpsIPMismatch: () => ({
50
+ code: "DEVICE_GPS_IP_MISMATCH",
51
+ message: "GPS location does not match IP-derived location"
52
+ }),
53
+ gpsRequired: () => ({
54
+ code: "DEVICE_GPS_REQUIRED",
55
+ message: "GPS verification is required but was not provided"
56
+ }),
57
+ // Transaction
58
+ transactionHighAmount: (amount, currency, threshold) => ({
59
+ code: "TRANSACTION_HIGH_AMOUNT",
60
+ message: "Transaction amount exceeds high-value threshold",
61
+ metadata: { amount, currency, threshold }
62
+ }),
63
+ transactionElevatedAmount: (amount, currency, threshold) => ({
64
+ code: "TRANSACTION_ELEVATED_AMOUNT",
65
+ message: "Transaction amount exceeds elevated-value threshold",
66
+ metadata: { amount, currency, threshold }
67
+ }),
68
+ transactionJurisdictionLimit: () => ({
69
+ code: "TRANSACTION_JURISDICTION_LIMIT",
70
+ message: "Transaction amount exceeds jurisdiction limit"
71
+ }),
72
+ anonymizationDetected: () => ({
73
+ code: "NETWORK_ANONYMIZER_DETECTED",
74
+ message: "Anonymization tool detected"
75
+ })
76
+ };
77
+
3
78
  // src/core/errors.ts
4
79
  var VesantError = class _VesantError extends Error {
5
80
  constructor(message, code, statusCode, details) {
@@ -224,7 +299,7 @@ function createConsoleLogger() {
224
299
  }
225
300
 
226
301
  // src/core/version.ts
227
- var SDK_VERSION = "1.6.6";
302
+ var SDK_VERSION = "1.7.0";
228
303
 
229
304
  // src/shared/browser-utils.ts
230
305
  function generateUUID() {
@@ -727,7 +802,7 @@ function encodePayload(payload) {
727
802
  } else if (typeof Buffer !== "undefined") {
728
803
  return Buffer.from(json, "utf-8").toString("base64");
729
804
  }
730
- throw new Error("No base64 encoding method available");
805
+ throw new VesantError("No base64 encoding method available", "BASE64_UNAVAILABLE");
731
806
  }
732
807
  async function generateCipherText(options, config) {
733
808
  const warnings = [];
@@ -752,8 +827,9 @@ async function generateCipherText(options, config) {
752
827
  if (location) {
753
828
  locationData = location;
754
829
  } else if (gpsRequiredByConfig) {
755
- throw new Error(
756
- `GPS location is required for ${options.reason} by tenant configuration, but GPS was not available or permission was denied`
830
+ throw new VesantError(
831
+ `GPS location is required for ${options.reason} by tenant configuration, but GPS was not available or permission was denied`,
832
+ "GPS_REQUIRED"
757
833
  );
758
834
  } else {
759
835
  warnings.push("GPS location not available or permission denied");
@@ -847,10 +923,9 @@ var GeolocationClient = class extends BaseClient {
847
923
  if (!request.ip_address?.trim()) {
848
924
  throw new ValidationError("ip_address is required and must be a non-empty string", ["ip_address"]);
849
925
  }
850
- const enrichedRequest = request.device_fingerprint ? request : { ...request, device_fingerprint: collectDeviceFingerprint() };
851
926
  return this.requestWithRetry("/api/v1/geo/verify", {
852
927
  method: "POST",
853
- body: JSON.stringify(enrichedRequest)
928
+ body: JSON.stringify(request)
854
929
  }, void 0, void 0, requestOptions);
855
930
  }
856
931
  /**
@@ -1075,6 +1150,7 @@ var GeolocationClient = class extends BaseClient {
1075
1150
  risk_level: risk.level ?? "low",
1076
1151
  risk_score: risk.score ?? 0,
1077
1152
  risk_reasons: risk.is_blocked && risk.block_reasons ? risk.block_reasons : risk.factors ?? [],
1153
+ risk_reasons_structured: risk.block_reasons_structured ?? [],
1078
1154
  jurisdiction: cipherTextResult.jurisdiction,
1079
1155
  geofence_evaluation: cipherTextResult.geofence_evaluation,
1080
1156
  record_id: cipherTextResult.record_id ?? "",
@@ -1254,24 +1330,6 @@ var GeolocationClient = class extends BaseClient {
1254
1330
  // Utility Methods (inherited from BaseClient: healthCheck, updateConfig, getConfig, buildQueryString)
1255
1331
  // ============================================================================
1256
1332
  };
1257
- function collectDeviceFingerprint() {
1258
- const deviceId = generateDeviceId();
1259
- const browserInfo = getBrowserInfo();
1260
- const userAgent = typeof navigator !== "undefined" ? navigator.userAgent : "server";
1261
- const platform = typeof navigator !== "undefined" ? navigator.platform || "unknown" : "server";
1262
- return {
1263
- device_id: deviceId,
1264
- user_agent: userAgent,
1265
- platform,
1266
- browser: browserInfo.browser,
1267
- browser_version: browserInfo.browser_version,
1268
- os: browserInfo.os,
1269
- os_version: browserInfo.os_version,
1270
- screen_resolution: typeof screen !== "undefined" ? `${screen.width}x${screen.height}` : void 0,
1271
- language: typeof navigator !== "undefined" ? navigator.language : void 0,
1272
- timezone: Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone
1273
- };
1274
- }
1275
1333
 
1276
1334
  // src/risk-profile/client.ts
1277
1335
  var RiskProfileClient = class extends BaseClient {
@@ -1534,10 +1592,10 @@ var ComplianceClient = class {
1534
1592
  device_fingerprint: request.deviceFingerprint
1535
1593
  }, requestOptions);
1536
1594
  }
1537
- const blockReasons = this.evaluateRegistrationBlock(geoVerification, cipherTextResult);
1538
- if (blockReasons.length > 0) {
1595
+ const structuredBlockReasons = this.evaluateRegistrationBlock(geoVerification, cipherTextResult);
1596
+ if (structuredBlockReasons.length > 0) {
1539
1597
  if (this.config.debug) {
1540
- this.logger.debug("Registration blocked at geo stage", { blockReasons });
1598
+ this.logger.debug("Registration blocked at geo stage", { blockReasons: structuredBlockReasons });
1541
1599
  }
1542
1600
  return {
1543
1601
  allowed: false,
@@ -1545,9 +1603,7 @@ var ComplianceClient = class {
1545
1603
  profile: null,
1546
1604
  requiresKYC: false,
1547
1605
  requiresEDD: false,
1548
- blockReasons,
1549
- processingTime: Date.now() - startTime,
1550
- cipherTextValidation: cipherTextResult
1606
+ ...this.buildReasonTail(structuredBlockReasons, startTime, cipherTextResult)
1551
1607
  };
1552
1608
  }
1553
1609
  const profile = await this.riskClient.createProfile({
@@ -1581,14 +1637,12 @@ var ComplianceClient = class {
1581
1637
  profile,
1582
1638
  requiresKYC,
1583
1639
  requiresEDD,
1584
- blockReasons: [],
1585
- processingTime: Date.now() - startTime,
1586
- cipherTextValidation: cipherTextResult
1640
+ ...this.buildReasonTail([], startTime, cipherTextResult)
1587
1641
  };
1588
1642
  } catch (error) {
1589
1643
  if (this.config.debug) {
1590
1644
  this.logger.error("Registration verification failed", {
1591
- code: error instanceof Error ? error.code : void 0,
1645
+ code: error instanceof VesantError ? error.code : void 0,
1592
1646
  message: error instanceof Error ? error.message : "Unknown error"
1593
1647
  });
1594
1648
  }
@@ -1617,52 +1671,62 @@ var ComplianceClient = class {
1617
1671
  evaluateRegistrationBlock(geoVerification, cipherTextResult) {
1618
1672
  const blockReasons = [];
1619
1673
  if (geoVerification.is_blocked) {
1620
- blockReasons.push(...geoVerification.risk_reasons ?? []);
1674
+ blockReasons.push(...geoVerification.risk_reasons_structured ?? []);
1621
1675
  }
1622
1676
  if (!geoVerification.is_compliant) {
1623
- if (!blockReasons.includes("non_compliant_jurisdiction")) {
1624
- blockReasons.push("non_compliant_jurisdiction");
1677
+ if (!blockReasons.some((r) => r.code === "JURISDICTION_NON_COMPLIANT")) {
1678
+ blockReasons.push(sdkReasons.jurisdictionNonCompliant());
1625
1679
  }
1626
1680
  }
1627
1681
  const jurisdiction = geoVerification.jurisdiction;
1628
1682
  if (jurisdiction) {
1629
1683
  if (jurisdiction.allow_registration === false) {
1630
- blockReasons.push("registration_not_allowed_in_jurisdiction");
1684
+ blockReasons.push(sdkReasons.jurisdictionRegistrationDenied());
1631
1685
  }
1632
1686
  if (jurisdiction.status === "blocked" || jurisdiction.status === "sanctioned") {
1633
- if (!blockReasons.includes("blocked_jurisdiction")) {
1634
- blockReasons.push("blocked_jurisdiction");
1687
+ if (!blockReasons.some((r) => r.code === "JURISDICTION_BLOCKED")) {
1688
+ blockReasons.push(sdkReasons.jurisdictionBlocked(jurisdiction.country_name ?? "", jurisdiction.country_iso ?? ""));
1635
1689
  }
1636
1690
  }
1637
1691
  if (jurisdiction.status === "restricted" && jurisdiction.allow_registration === false) {
1638
- if (!blockReasons.includes("restricted_jurisdiction_no_registration")) {
1639
- blockReasons.push("restricted_jurisdiction_no_registration");
1692
+ if (!blockReasons.some((r) => r.code === "JURISDICTION_RESTRICTED")) {
1693
+ blockReasons.push(sdkReasons.jurisdictionRestricted());
1640
1694
  }
1641
1695
  }
1642
1696
  }
1643
1697
  if (geoVerification.geofence_evaluation?.blocked) {
1644
- blockReasons.push(...geoVerification.geofence_evaluation.reasons ?? []);
1698
+ blockReasons.push(
1699
+ ...(geoVerification.geofence_evaluation.reasons ?? []).map((m) => ({
1700
+ code: "JURISDICTION_GEOFENCE_VIOLATION",
1701
+ message: m
1702
+ }))
1703
+ );
1645
1704
  }
1646
1705
  if (geoVerification.risk_level === "critical") {
1647
- if (!blockReasons.includes("critical_risk_level")) {
1648
- blockReasons.push("critical_risk_level");
1706
+ if (!blockReasons.some((r) => r.code === "RISK_CRITICAL_LEVEL")) {
1707
+ blockReasons.push(sdkReasons.riskCriticalLevel());
1649
1708
  }
1650
1709
  }
1651
1710
  if (cipherTextResult) {
1652
1711
  if (!cipherTextResult.valid) {
1653
- blockReasons.push("ciphertext_validation_failed");
1712
+ blockReasons.push(sdkReasons.ciphertextInvalid());
1654
1713
  }
1655
1714
  if (cipherTextResult.risk?.is_blocked) {
1656
- blockReasons.push(...cipherTextResult.risk.block_reasons || []);
1715
+ blockReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
1657
1716
  }
1658
1717
  if (cipherTextResult.risk?.location_mismatch) {
1659
- blockReasons.push("gps_ip_location_mismatch");
1718
+ blockReasons.push(sdkReasons.gpsIPMismatch());
1660
1719
  }
1661
1720
  }
1662
1721
  if (geoVerification.gps_required && !cipherTextResult) {
1663
- blockReasons.push("gps_verification_required");
1722
+ blockReasons.push(sdkReasons.gpsRequired());
1664
1723
  }
1665
- return [...new Set(blockReasons)];
1724
+ const seen = /* @__PURE__ */ new Set();
1725
+ return blockReasons.filter((r) => {
1726
+ if (seen.has(r.code)) return false;
1727
+ seen.add(r.code);
1728
+ return true;
1729
+ });
1666
1730
  }
1667
1731
  /**
1668
1732
  * Validate registration request has all required fields
@@ -1833,9 +1897,7 @@ var ComplianceClient = class {
1833
1897
  geolocation: geoVerification,
1834
1898
  profile: null,
1835
1899
  requiresStepUp: false,
1836
- blockReasons: loginBlockReasons,
1837
- processingTime: Date.now() - startTime,
1838
- cipherTextValidation: cipherTextResult
1900
+ ...this.buildReasonTail(loginBlockReasons, startTime, cipherTextResult)
1839
1901
  };
1840
1902
  }
1841
1903
  let profile;
@@ -1855,14 +1917,13 @@ var ComplianceClient = class {
1855
1917
  profile = await this.createProfileFromGeo(request.customerId, geoVerification);
1856
1918
  }
1857
1919
  const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical" || cipherTextResult?.risk?.location_mismatch === true;
1920
+ const loginFinalStructured = isBlocked || profile.customer_status === "suspended" ? this.getBlockReasons(geoVerification, profile, cipherTextResult) : [];
1858
1921
  return {
1859
1922
  allowed: !isBlocked && profile.customer_status !== "suspended",
1860
1923
  geolocation: geoVerification,
1861
1924
  profile,
1862
1925
  requiresStepUp,
1863
- blockReasons: isBlocked || profile.customer_status === "suspended" ? this.getBlockReasons(geoVerification, profile, cipherTextResult) : [],
1864
- processingTime: Date.now() - startTime,
1865
- cipherTextValidation: cipherTextResult
1926
+ ...this.buildReasonTail(loginFinalStructured, startTime, cipherTextResult)
1866
1927
  };
1867
1928
  } catch (error) {
1868
1929
  throw new ComplianceError("Login verification failed", error instanceof Error ? error.message : void 0);
@@ -1944,20 +2005,19 @@ var ComplianceClient = class {
1944
2005
  }
1945
2006
  const geoBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
1946
2007
  if (geoBlocked && !profileResult) {
2008
+ const earlyStructured = this.getTransactionBlockReasons(
2009
+ geoVerification,
2010
+ { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
2011
+ true,
2012
+ cipherTextResult
2013
+ );
1947
2014
  return {
1948
2015
  allowed: false,
1949
2016
  geolocation: geoVerification,
1950
2017
  profile: null,
1951
2018
  transactionRisk: { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
1952
2019
  requiresApproval: false,
1953
- blockReasons: this.getTransactionBlockReasons(
1954
- geoVerification,
1955
- { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
1956
- true,
1957
- cipherTextResult
1958
- ),
1959
- processingTime: Date.now() - startTime,
1960
- cipherTextValidation: cipherTextResult
2020
+ ...this.buildReasonTail(earlyStructured, startTime, cipherTextResult)
1961
2021
  };
1962
2022
  }
1963
2023
  if (!profileResult) {
@@ -1977,20 +2037,19 @@ var ComplianceClient = class {
1977
2037
  geoVerification.jurisdiction
1978
2038
  );
1979
2039
  const isAllowed = !geoBlocked && jurisdictionAllowed && transactionRisk.allowed && profile.customer_status !== "suspended";
2040
+ const txStructured = this.getTransactionBlockReasons(
2041
+ geoVerification,
2042
+ transactionRisk,
2043
+ jurisdictionAllowed,
2044
+ cipherTextResult
2045
+ );
1980
2046
  return {
1981
2047
  allowed: isAllowed,
1982
2048
  geolocation: geoVerification,
1983
2049
  profile,
1984
2050
  transactionRisk,
1985
2051
  requiresApproval: transactionRisk.requiresManualReview,
1986
- blockReasons: this.getTransactionBlockReasons(
1987
- geoVerification,
1988
- transactionRisk,
1989
- jurisdictionAllowed,
1990
- cipherTextResult
1991
- ),
1992
- processingTime: Date.now() - startTime,
1993
- cipherTextValidation: cipherTextResult
2052
+ ...this.buildReasonTail(txStructured, startTime, cipherTextResult)
1994
2053
  };
1995
2054
  } catch (error) {
1996
2055
  throw new ComplianceError("Transaction verification failed", error instanceof Error ? error.message : void 0);
@@ -2043,30 +2102,42 @@ var ComplianceClient = class {
2043
2102
  }
2044
2103
  }
2045
2104
  const cipherTextBlocked = cipherTextResult ? !cipherTextResult.valid || cipherTextResult.risk?.is_blocked === true : false;
2046
- const blockReasons = [...geoVerification.risk_reasons ?? []];
2105
+ const structuredEventReasons = [...geoVerification.risk_reasons_structured ?? []];
2047
2106
  if (cipherTextResult) {
2048
2107
  if (!cipherTextResult.valid) {
2049
- blockReasons.push("ciphertext_validation_failed");
2108
+ structuredEventReasons.push(sdkReasons.ciphertextInvalid());
2050
2109
  }
2051
2110
  if (cipherTextResult.risk?.is_blocked) {
2052
- blockReasons.push(...cipherTextResult.risk.block_reasons || []);
2111
+ structuredEventReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
2053
2112
  }
2054
2113
  }
2055
2114
  const gpsBlocked = geoVerification.gps_required && !cipherTextResult;
2056
2115
  if (gpsBlocked) {
2057
- blockReasons.push("gps_verification_required");
2116
+ structuredEventReasons.push(sdkReasons.gpsRequired());
2058
2117
  }
2118
+ const seen = /* @__PURE__ */ new Set();
2119
+ const dedupedStructured = structuredEventReasons.filter((r) => {
2120
+ if (seen.has(r.code)) return false;
2121
+ seen.add(r.code);
2122
+ return true;
2123
+ });
2059
2124
  return {
2060
2125
  allowed: geoVerification.is_compliant && !geoVerification.is_blocked && !cipherTextBlocked && !gpsBlocked,
2061
2126
  geolocation: geoVerification,
2062
- blockReasons: [...new Set(blockReasons)],
2063
- processingTime: Date.now() - startTime,
2064
- cipherTextValidation: cipherTextResult
2127
+ ...this.buildReasonTail(dedupedStructured, startTime, cipherTextResult)
2065
2128
  };
2066
2129
  }
2067
2130
  // ============================================================================
2068
2131
  // Helper Methods
2069
2132
  // ============================================================================
2133
+ buildReasonTail(structured, startTime, cipherTextResult) {
2134
+ return {
2135
+ blockReasons: structured.map((r) => r.message),
2136
+ blockReasonsStructured: structured,
2137
+ processingTime: Date.now() - startTime,
2138
+ cipherTextValidation: cipherTextResult
2139
+ };
2140
+ }
2070
2141
  shouldUpdateProfile(profile, newCity) {
2071
2142
  return !profile.location || !profile.location.includes(newCity);
2072
2143
  }
@@ -2143,7 +2214,8 @@ var ComplianceClient = class {
2143
2214
  is_blocked: risk.is_blocked,
2144
2215
  risk_level: risk.level,
2145
2216
  risk_score: risk.score,
2146
- risk_reasons: risk.is_blocked && risk.block_reasons ? risk.block_reasons : risk.factors ?? [],
2217
+ risk_reasons: [],
2218
+ risk_reasons_structured: risk.is_blocked && risk.block_reasons_structured ? risk.block_reasons_structured : [],
2147
2219
  jurisdiction: ct.jurisdiction,
2148
2220
  geofence_evaluation: ct.geofence_evaluation,
2149
2221
  record_id: ct.record_id ?? "",
@@ -2158,35 +2230,35 @@ var ComplianceClient = class {
2158
2230
  );
2159
2231
  }
2160
2232
  let riskScore = 0;
2161
- const factors = [];
2233
+ const structuredFactors = [];
2162
2234
  const normalizedAmount = this.normalizeToUSD(amount, currency);
2163
2235
  if (normalizedAmount > 1e4) {
2164
2236
  riskScore += 30;
2165
- factors.push("high_transaction_amount");
2237
+ structuredFactors.push(sdkReasons.transactionHighAmount(normalizedAmount, currency, 1e4));
2166
2238
  } else if (normalizedAmount > 5e3) {
2167
2239
  riskScore += 15;
2168
- factors.push("elevated_transaction_amount");
2240
+ structuredFactors.push(sdkReasons.transactionElevatedAmount(normalizedAmount, currency, 5e3));
2169
2241
  }
2170
2242
  riskScore += geoVerification.risk_score * 0.4;
2171
2243
  if (geoVerification.risk_level === "high" || geoVerification.risk_level === "critical") {
2172
- factors.push("high_risk_location");
2244
+ structuredFactors.push(sdkReasons.riskHighLocation());
2173
2245
  }
2174
2246
  riskScore += profile.risk_score * 0.3;
2175
2247
  if (profile.risk_category === "high" || profile.risk_category === "critical") {
2176
- factors.push("high_risk_customer");
2248
+ structuredFactors.push(sdkReasons.riskHighCustomer());
2177
2249
  }
2178
2250
  if (geoVerification.location.is_vpn || geoVerification.location.is_proxy) {
2179
2251
  riskScore += 20;
2180
- factors.push("anonymization_detected");
2252
+ structuredFactors.push(sdkReasons.anonymizationDetected());
2181
2253
  }
2182
2254
  if (profile.customer_status === "suspended") {
2183
2255
  riskScore += 50;
2184
- factors.push("account_suspended");
2256
+ structuredFactors.push(sdkReasons.accountSuspended());
2185
2257
  }
2186
2258
  if (cipherTextResult) {
2187
2259
  if (cipherTextResult.risk?.location_mismatch) {
2188
2260
  riskScore += 20;
2189
- factors.push("gps_ip_location_mismatch");
2261
+ structuredFactors.push(sdkReasons.gpsIPMismatch());
2190
2262
  }
2191
2263
  if (cipherTextResult.risk?.score) {
2192
2264
  riskScore += cipherTextResult.risk.score * 0.2;
@@ -2195,7 +2267,8 @@ var ComplianceClient = class {
2195
2267
  return {
2196
2268
  score: Math.min(riskScore, 100),
2197
2269
  level: this.getRiskLevel(riskScore),
2198
- factors,
2270
+ factors: structuredFactors.map((r) => r.message),
2271
+ factorsStructured: structuredFactors,
2199
2272
  allowed: riskScore < 70,
2200
2273
  requiresManualReview: riskScore >= 60 && riskScore < 70
2201
2274
  };
@@ -2220,52 +2293,62 @@ var ComplianceClient = class {
2220
2293
  getBlockReasons(geoVerification, profile, cipherTextResult) {
2221
2294
  const reasons = [];
2222
2295
  if (geoVerification.is_blocked) {
2223
- reasons.push(...geoVerification.risk_reasons ?? []);
2296
+ reasons.push(...geoVerification.risk_reasons_structured ?? []);
2224
2297
  }
2225
2298
  if (profile) {
2226
2299
  if (profile.customer_status === "suspended") {
2227
- reasons.push("account_suspended");
2300
+ reasons.push(sdkReasons.accountSuspended());
2228
2301
  }
2229
2302
  if (profile.has_sanctions) {
2230
- reasons.push("sanctions_match");
2303
+ reasons.push(sdkReasons.sanctionsMatch());
2231
2304
  }
2232
2305
  }
2233
2306
  if (cipherTextResult) {
2234
2307
  if (!cipherTextResult.valid) {
2235
- reasons.push("ciphertext_validation_failed");
2308
+ reasons.push(sdkReasons.ciphertextInvalid());
2236
2309
  }
2237
2310
  if (cipherTextResult.risk?.is_blocked) {
2238
- reasons.push(...cipherTextResult.risk.block_reasons || []);
2311
+ reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
2239
2312
  }
2240
2313
  }
2241
2314
  if (geoVerification.gps_required && !cipherTextResult) {
2242
- reasons.push("gps_verification_required");
2315
+ reasons.push(sdkReasons.gpsRequired());
2243
2316
  }
2244
- return [...new Set(reasons)];
2317
+ const seen = /* @__PURE__ */ new Set();
2318
+ return reasons.filter((r) => {
2319
+ if (seen.has(r.code)) return false;
2320
+ seen.add(r.code);
2321
+ return true;
2322
+ });
2245
2323
  }
2246
2324
  getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed, cipherTextResult) {
2247
2325
  const reasons = [];
2248
2326
  if (!geoVerification.is_compliant) {
2249
- reasons.push("non_compliant_jurisdiction");
2327
+ reasons.push(sdkReasons.jurisdictionNonCompliant());
2250
2328
  }
2251
2329
  if (!jurisdictionAllowed) {
2252
- reasons.push("exceeds_jurisdiction_limit");
2330
+ reasons.push(sdkReasons.transactionJurisdictionLimit());
2253
2331
  }
2254
2332
  if (!transactionRisk.allowed) {
2255
- reasons.push(...transactionRisk.factors);
2333
+ reasons.push(...transactionRisk.factorsStructured ?? []);
2256
2334
  }
2257
2335
  if (cipherTextResult) {
2258
2336
  if (!cipherTextResult.valid) {
2259
- reasons.push("ciphertext_validation_failed");
2337
+ reasons.push(sdkReasons.ciphertextInvalid());
2260
2338
  }
2261
2339
  if (cipherTextResult.risk?.is_blocked) {
2262
- reasons.push(...cipherTextResult.risk.block_reasons || []);
2340
+ reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
2263
2341
  }
2264
2342
  }
2265
2343
  if (geoVerification.gps_required && !cipherTextResult) {
2266
- reasons.push("gps_verification_required");
2344
+ reasons.push(sdkReasons.gpsRequired());
2267
2345
  }
2268
- return [...new Set(reasons)];
2346
+ const seen = /* @__PURE__ */ new Set();
2347
+ return reasons.filter((r) => {
2348
+ if (seen.has(r.code)) return false;
2349
+ seen.add(r.code);
2350
+ return true;
2351
+ });
2269
2352
  }
2270
2353
  // ============================================================================
2271
2354
  // Location Request Methods
@@ -2485,5 +2568,6 @@ var ComplianceClient = class {
2485
2568
 
2486
2569
  exports.ComplianceClient = ComplianceClient;
2487
2570
  exports.DEFAULT_CURRENCY_RATES = DEFAULT_CURRENCY_RATES;
2571
+ exports.sdkReasons = sdkReasons;
2488
2572
  //# sourceMappingURL=index.js.map
2489
2573
  //# sourceMappingURL=index.js.map