vesant-sdk 1.6.6 → 1.7.0-dev.117915b

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-B0qhE2kr.d.mts +436 -0
  3. package/dist/{client-ePzhQKp9.d.mts → client-BolQlL5e.d.mts} +1 -1
  4. package/dist/{client-ePzhQKp9.d.ts → client-BolQlL5e.d.ts} +1 -1
  5. package/dist/{client-BlCxjbY2.d.mts → client-DF7hlMEz.d.ts} +18 -3
  6. package/dist/{client-C_A7QLcB.d.ts → client-DrjgZoH_.d.mts} +18 -3
  7. package/dist/client-DtH2RLuy.d.ts +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 +186 -105
  11. package/dist/compliance/index.js.map +1 -1
  12. package/dist/compliance/index.mjs +186 -106
  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 +305 -299
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +304 -298
  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 +86 -27
  35. package/dist/kyc/core.js.map +1 -1
  36. package/dist/kyc/core.mjs +86 -28
  37. package/dist/kyc/core.mjs.map +1 -1
  38. package/dist/kyc/index.d.mts +309 -50
  39. package/dist/kyc/index.d.ts +309 -50
  40. package/dist/kyc/index.js +86 -27
  41. package/dist/kyc/index.js.map +1 -1
  42. package/dist/kyc/index.mjs +86 -28
  43. package/dist/kyc/index.mjs.map +1 -1
  44. package/dist/react.d.mts +48 -9
  45. package/dist/react.d.ts +48 -9
  46. package/dist/react.js +930 -276
  47. package/dist/react.js.map +1 -1
  48. package/dist/react.mjs +929 -275
  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 +23 -41
  63. package/dist/tax/index.d.ts +23 -41
  64. package/dist/tax/index.js +5 -37
  65. package/dist/tax/index.js.map +1 -1
  66. package/dist/tax/index.mjs +5 -37
  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,59 @@ 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 || []);
1657
- }
1658
- if (cipherTextResult.risk?.location_mismatch) {
1659
- blockReasons.push("gps_ip_location_mismatch");
1715
+ blockReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
1660
1716
  }
1661
1717
  }
1662
1718
  if (geoVerification.gps_required && !cipherTextResult) {
1663
- blockReasons.push("gps_verification_required");
1719
+ blockReasons.push(sdkReasons.gpsRequired());
1664
1720
  }
1665
- return [...new Set(blockReasons)];
1721
+ const seen = /* @__PURE__ */ new Set();
1722
+ return blockReasons.filter((r) => {
1723
+ if (seen.has(r.code)) return false;
1724
+ seen.add(r.code);
1725
+ return true;
1726
+ });
1666
1727
  }
1667
1728
  /**
1668
1729
  * Validate registration request has all required fields
@@ -1833,9 +1894,7 @@ var ComplianceClient = class {
1833
1894
  geolocation: geoVerification,
1834
1895
  profile: null,
1835
1896
  requiresStepUp: false,
1836
- blockReasons: loginBlockReasons,
1837
- processingTime: Date.now() - startTime,
1838
- cipherTextValidation: cipherTextResult
1897
+ ...this.buildReasonTail(loginBlockReasons, startTime, cipherTextResult)
1839
1898
  };
1840
1899
  }
1841
1900
  let profile;
@@ -1855,14 +1914,13 @@ var ComplianceClient = class {
1855
1914
  profile = await this.createProfileFromGeo(request.customerId, geoVerification);
1856
1915
  }
1857
1916
  const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical" || cipherTextResult?.risk?.location_mismatch === true;
1917
+ const loginFinalStructured = isBlocked || profile.customer_status === "suspended" ? this.getBlockReasons(geoVerification, profile, cipherTextResult) : [];
1858
1918
  return {
1859
1919
  allowed: !isBlocked && profile.customer_status !== "suspended",
1860
1920
  geolocation: geoVerification,
1861
1921
  profile,
1862
1922
  requiresStepUp,
1863
- blockReasons: isBlocked || profile.customer_status === "suspended" ? this.getBlockReasons(geoVerification, profile, cipherTextResult) : [],
1864
- processingTime: Date.now() - startTime,
1865
- cipherTextValidation: cipherTextResult
1923
+ ...this.buildReasonTail(loginFinalStructured, startTime, cipherTextResult)
1866
1924
  };
1867
1925
  } catch (error) {
1868
1926
  throw new ComplianceError("Login verification failed", error instanceof Error ? error.message : void 0);
@@ -1944,20 +2002,19 @@ var ComplianceClient = class {
1944
2002
  }
1945
2003
  const geoBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
1946
2004
  if (geoBlocked && !profileResult) {
2005
+ const earlyStructured = this.getTransactionBlockReasons(
2006
+ geoVerification,
2007
+ { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
2008
+ true,
2009
+ cipherTextResult
2010
+ );
1947
2011
  return {
1948
2012
  allowed: false,
1949
2013
  geolocation: geoVerification,
1950
2014
  profile: null,
1951
2015
  transactionRisk: { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
1952
2016
  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
2017
+ ...this.buildReasonTail(earlyStructured, startTime, cipherTextResult)
1961
2018
  };
1962
2019
  }
1963
2020
  if (!profileResult) {
@@ -1977,20 +2034,19 @@ var ComplianceClient = class {
1977
2034
  geoVerification.jurisdiction
1978
2035
  );
1979
2036
  const isAllowed = !geoBlocked && jurisdictionAllowed && transactionRisk.allowed && profile.customer_status !== "suspended";
2037
+ const txStructured = this.getTransactionBlockReasons(
2038
+ geoVerification,
2039
+ transactionRisk,
2040
+ jurisdictionAllowed,
2041
+ cipherTextResult
2042
+ );
1980
2043
  return {
1981
2044
  allowed: isAllowed,
1982
2045
  geolocation: geoVerification,
1983
2046
  profile,
1984
2047
  transactionRisk,
1985
2048
  requiresApproval: transactionRisk.requiresManualReview,
1986
- blockReasons: this.getTransactionBlockReasons(
1987
- geoVerification,
1988
- transactionRisk,
1989
- jurisdictionAllowed,
1990
- cipherTextResult
1991
- ),
1992
- processingTime: Date.now() - startTime,
1993
- cipherTextValidation: cipherTextResult
2049
+ ...this.buildReasonTail(txStructured, startTime, cipherTextResult)
1994
2050
  };
1995
2051
  } catch (error) {
1996
2052
  throw new ComplianceError("Transaction verification failed", error instanceof Error ? error.message : void 0);
@@ -2043,30 +2099,42 @@ var ComplianceClient = class {
2043
2099
  }
2044
2100
  }
2045
2101
  const cipherTextBlocked = cipherTextResult ? !cipherTextResult.valid || cipherTextResult.risk?.is_blocked === true : false;
2046
- const blockReasons = [...geoVerification.risk_reasons ?? []];
2102
+ const structuredEventReasons = [...geoVerification.risk_reasons_structured ?? []];
2047
2103
  if (cipherTextResult) {
2048
2104
  if (!cipherTextResult.valid) {
2049
- blockReasons.push("ciphertext_validation_failed");
2105
+ structuredEventReasons.push(sdkReasons.ciphertextInvalid());
2050
2106
  }
2051
2107
  if (cipherTextResult.risk?.is_blocked) {
2052
- blockReasons.push(...cipherTextResult.risk.block_reasons || []);
2108
+ structuredEventReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
2053
2109
  }
2054
2110
  }
2055
2111
  const gpsBlocked = geoVerification.gps_required && !cipherTextResult;
2056
2112
  if (gpsBlocked) {
2057
- blockReasons.push("gps_verification_required");
2113
+ structuredEventReasons.push(sdkReasons.gpsRequired());
2058
2114
  }
2115
+ const seen = /* @__PURE__ */ new Set();
2116
+ const dedupedStructured = structuredEventReasons.filter((r) => {
2117
+ if (seen.has(r.code)) return false;
2118
+ seen.add(r.code);
2119
+ return true;
2120
+ });
2059
2121
  return {
2060
2122
  allowed: geoVerification.is_compliant && !geoVerification.is_blocked && !cipherTextBlocked && !gpsBlocked,
2061
2123
  geolocation: geoVerification,
2062
- blockReasons: [...new Set(blockReasons)],
2063
- processingTime: Date.now() - startTime,
2064
- cipherTextValidation: cipherTextResult
2124
+ ...this.buildReasonTail(dedupedStructured, startTime, cipherTextResult)
2065
2125
  };
2066
2126
  }
2067
2127
  // ============================================================================
2068
2128
  // Helper Methods
2069
2129
  // ============================================================================
2130
+ buildReasonTail(structured, startTime, cipherTextResult) {
2131
+ return {
2132
+ blockReasons: structured.map((r) => r.message),
2133
+ blockReasonsStructured: structured,
2134
+ processingTime: Date.now() - startTime,
2135
+ cipherTextValidation: cipherTextResult
2136
+ };
2137
+ }
2070
2138
  shouldUpdateProfile(profile, newCity) {
2071
2139
  return !profile.location || !profile.location.includes(newCity);
2072
2140
  }
@@ -2143,7 +2211,8 @@ var ComplianceClient = class {
2143
2211
  is_blocked: risk.is_blocked,
2144
2212
  risk_level: risk.level,
2145
2213
  risk_score: risk.score,
2146
- risk_reasons: risk.is_blocked && risk.block_reasons ? risk.block_reasons : risk.factors ?? [],
2214
+ risk_reasons: [],
2215
+ risk_reasons_structured: risk.is_blocked && risk.block_reasons_structured ? risk.block_reasons_structured : [],
2147
2216
  jurisdiction: ct.jurisdiction,
2148
2217
  geofence_evaluation: ct.geofence_evaluation,
2149
2218
  record_id: ct.record_id ?? "",
@@ -2158,35 +2227,35 @@ var ComplianceClient = class {
2158
2227
  );
2159
2228
  }
2160
2229
  let riskScore = 0;
2161
- const factors = [];
2230
+ const structuredFactors = [];
2162
2231
  const normalizedAmount = this.normalizeToUSD(amount, currency);
2163
2232
  if (normalizedAmount > 1e4) {
2164
2233
  riskScore += 30;
2165
- factors.push("high_transaction_amount");
2234
+ structuredFactors.push(sdkReasons.transactionHighAmount(normalizedAmount, currency, 1e4));
2166
2235
  } else if (normalizedAmount > 5e3) {
2167
2236
  riskScore += 15;
2168
- factors.push("elevated_transaction_amount");
2237
+ structuredFactors.push(sdkReasons.transactionElevatedAmount(normalizedAmount, currency, 5e3));
2169
2238
  }
2170
2239
  riskScore += geoVerification.risk_score * 0.4;
2171
2240
  if (geoVerification.risk_level === "high" || geoVerification.risk_level === "critical") {
2172
- factors.push("high_risk_location");
2241
+ structuredFactors.push(sdkReasons.riskHighLocation());
2173
2242
  }
2174
2243
  riskScore += profile.risk_score * 0.3;
2175
2244
  if (profile.risk_category === "high" || profile.risk_category === "critical") {
2176
- factors.push("high_risk_customer");
2245
+ structuredFactors.push(sdkReasons.riskHighCustomer());
2177
2246
  }
2178
2247
  if (geoVerification.location.is_vpn || geoVerification.location.is_proxy) {
2179
2248
  riskScore += 20;
2180
- factors.push("anonymization_detected");
2249
+ structuredFactors.push(sdkReasons.anonymizationDetected());
2181
2250
  }
2182
2251
  if (profile.customer_status === "suspended") {
2183
2252
  riskScore += 50;
2184
- factors.push("account_suspended");
2253
+ structuredFactors.push(sdkReasons.accountSuspended());
2185
2254
  }
2186
2255
  if (cipherTextResult) {
2187
2256
  if (cipherTextResult.risk?.location_mismatch) {
2188
2257
  riskScore += 20;
2189
- factors.push("gps_ip_location_mismatch");
2258
+ structuredFactors.push(sdkReasons.gpsIPMismatch());
2190
2259
  }
2191
2260
  if (cipherTextResult.risk?.score) {
2192
2261
  riskScore += cipherTextResult.risk.score * 0.2;
@@ -2195,7 +2264,8 @@ var ComplianceClient = class {
2195
2264
  return {
2196
2265
  score: Math.min(riskScore, 100),
2197
2266
  level: this.getRiskLevel(riskScore),
2198
- factors,
2267
+ factors: structuredFactors.map((r) => r.message),
2268
+ factorsStructured: structuredFactors,
2199
2269
  allowed: riskScore < 70,
2200
2270
  requiresManualReview: riskScore >= 60 && riskScore < 70
2201
2271
  };
@@ -2220,52 +2290,62 @@ var ComplianceClient = class {
2220
2290
  getBlockReasons(geoVerification, profile, cipherTextResult) {
2221
2291
  const reasons = [];
2222
2292
  if (geoVerification.is_blocked) {
2223
- reasons.push(...geoVerification.risk_reasons ?? []);
2293
+ reasons.push(...geoVerification.risk_reasons_structured ?? []);
2224
2294
  }
2225
2295
  if (profile) {
2226
2296
  if (profile.customer_status === "suspended") {
2227
- reasons.push("account_suspended");
2297
+ reasons.push(sdkReasons.accountSuspended());
2228
2298
  }
2229
2299
  if (profile.has_sanctions) {
2230
- reasons.push("sanctions_match");
2300
+ reasons.push(sdkReasons.sanctionsMatch());
2231
2301
  }
2232
2302
  }
2233
2303
  if (cipherTextResult) {
2234
2304
  if (!cipherTextResult.valid) {
2235
- reasons.push("ciphertext_validation_failed");
2305
+ reasons.push(sdkReasons.ciphertextInvalid());
2236
2306
  }
2237
2307
  if (cipherTextResult.risk?.is_blocked) {
2238
- reasons.push(...cipherTextResult.risk.block_reasons || []);
2308
+ reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
2239
2309
  }
2240
2310
  }
2241
2311
  if (geoVerification.gps_required && !cipherTextResult) {
2242
- reasons.push("gps_verification_required");
2312
+ reasons.push(sdkReasons.gpsRequired());
2243
2313
  }
2244
- return [...new Set(reasons)];
2314
+ const seen = /* @__PURE__ */ new Set();
2315
+ return reasons.filter((r) => {
2316
+ if (seen.has(r.code)) return false;
2317
+ seen.add(r.code);
2318
+ return true;
2319
+ });
2245
2320
  }
2246
2321
  getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed, cipherTextResult) {
2247
2322
  const reasons = [];
2248
2323
  if (!geoVerification.is_compliant) {
2249
- reasons.push("non_compliant_jurisdiction");
2324
+ reasons.push(sdkReasons.jurisdictionNonCompliant());
2250
2325
  }
2251
2326
  if (!jurisdictionAllowed) {
2252
- reasons.push("exceeds_jurisdiction_limit");
2327
+ reasons.push(sdkReasons.transactionJurisdictionLimit());
2253
2328
  }
2254
2329
  if (!transactionRisk.allowed) {
2255
- reasons.push(...transactionRisk.factors);
2330
+ reasons.push(...transactionRisk.factorsStructured ?? []);
2256
2331
  }
2257
2332
  if (cipherTextResult) {
2258
2333
  if (!cipherTextResult.valid) {
2259
- reasons.push("ciphertext_validation_failed");
2334
+ reasons.push(sdkReasons.ciphertextInvalid());
2260
2335
  }
2261
2336
  if (cipherTextResult.risk?.is_blocked) {
2262
- reasons.push(...cipherTextResult.risk.block_reasons || []);
2337
+ reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
2263
2338
  }
2264
2339
  }
2265
2340
  if (geoVerification.gps_required && !cipherTextResult) {
2266
- reasons.push("gps_verification_required");
2341
+ reasons.push(sdkReasons.gpsRequired());
2267
2342
  }
2268
- return [...new Set(reasons)];
2343
+ const seen = /* @__PURE__ */ new Set();
2344
+ return reasons.filter((r) => {
2345
+ if (seen.has(r.code)) return false;
2346
+ seen.add(r.code);
2347
+ return true;
2348
+ });
2269
2349
  }
2270
2350
  // ============================================================================
2271
2351
  // Location Request Methods
@@ -2485,5 +2565,6 @@ var ComplianceClient = class {
2485
2565
 
2486
2566
  exports.ComplianceClient = ComplianceClient;
2487
2567
  exports.DEFAULT_CURRENCY_RATES = DEFAULT_CURRENCY_RATES;
2568
+ exports.sdkReasons = sdkReasons;
2488
2569
  //# sourceMappingURL=index.js.map
2489
2570
  //# sourceMappingURL=index.js.map