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