vesant-sdk 1.6.6-next.ac58d2b → 1.7.0-dev.059da4f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/client-C3DCmGe9.d.ts +436 -0
- package/dist/{client-D6PE3pcB.d.mts → client-DMIRx7Tu.d.mts} +4 -2
- package/dist/{client-DPtiuQvW.d.ts → client-DoMSYMMR.d.ts} +4 -2
- package/dist/client-ZNdnpWe7.d.mts +436 -0
- package/dist/compliance/index.d.mts +25 -429
- package/dist/compliance/index.d.ts +25 -429
- package/dist/compliance/index.js +181 -79
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +181 -80
- package/dist/compliance/index.mjs.map +1 -1
- package/dist/decisions/index.d.mts +1 -1
- package/dist/decisions/index.d.ts +1 -1
- package/dist/decisions/index.js +1 -1
- package/dist/decisions/index.js.map +1 -1
- package/dist/decisions/index.mjs +1 -1
- package/dist/decisions/index.mjs.map +1 -1
- package/dist/geolocation/index.d.mts +3 -3
- package/dist/geolocation/index.d.ts +3 -3
- package/dist/geolocation/index.js +2 -1
- package/dist/geolocation/index.js.map +1 -1
- package/dist/geolocation/index.mjs +2 -1
- package/dist/geolocation/index.mjs.map +1 -1
- package/dist/index.d.mts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +269 -93
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +268 -94
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.d.mts +3 -3
- package/dist/kyc/core.d.ts +3 -3
- package/dist/kyc/core.js +77 -15
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs +77 -16
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.d.mts +267 -26
- package/dist/kyc/index.d.ts +267 -26
- package/dist/kyc/index.js +77 -15
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs +77 -16
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +45 -8
- package/dist/react.d.ts +45 -8
- package/dist/react.js +874 -272
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +873 -271
- package/dist/react.mjs.map +1 -1
- package/dist/risk-profile/index.d.mts +3 -3
- package/dist/risk-profile/index.d.ts +3 -3
- package/dist/risk-profile/index.js +1 -1
- package/dist/risk-profile/index.js.map +1 -1
- package/dist/risk-profile/index.mjs +1 -1
- package/dist/risk-profile/index.mjs.map +1 -1
- package/dist/scores/index.d.mts +1 -1
- package/dist/scores/index.d.ts +1 -1
- package/dist/scores/index.js +1 -1
- package/dist/scores/index.js.map +1 -1
- package/dist/scores/index.mjs +1 -1
- package/dist/scores/index.mjs.map +1 -1
- package/dist/tax/index.d.mts +41 -1
- package/dist/tax/index.d.ts +41 -1
- package/dist/tax/index.js +13 -1
- package/dist/tax/index.js.map +1 -1
- package/dist/tax/index.mjs +13 -1
- package/dist/tax/index.mjs.map +1 -1
- package/dist/{types-DGDVnogO.d.mts → types-BOFaMQxI.d.mts} +2 -2
- package/dist/{types-B4Ezqo7V.d.mts → types-CBQRNL-l.d.mts} +14 -1
- package/dist/{types-B4Ezqo7V.d.ts → types-CBQRNL-l.d.ts} +14 -1
- package/dist/{types-_YQdS3Ax.d.ts → types-UGyDl1fd.d.ts} +2 -2
- package/dist/webhooks/index.d.mts +12 -4
- package/dist/webhooks/index.d.ts +12 -4
- package/package.json +1 -1
|
@@ -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.
|
|
300
|
+
var SDK_VERSION = "1.7.0";
|
|
226
301
|
|
|
227
302
|
// src/shared/browser-utils.ts
|
|
228
303
|
function generateUUID() {
|
|
@@ -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 ?? "",
|
|
@@ -1514,10 +1590,10 @@ var ComplianceClient = class {
|
|
|
1514
1590
|
device_fingerprint: request.deviceFingerprint
|
|
1515
1591
|
}, requestOptions);
|
|
1516
1592
|
}
|
|
1517
|
-
const
|
|
1518
|
-
if (
|
|
1593
|
+
const structuredBlockReasons = this.evaluateRegistrationBlock(geoVerification, cipherTextResult);
|
|
1594
|
+
if (structuredBlockReasons.length > 0) {
|
|
1519
1595
|
if (this.config.debug) {
|
|
1520
|
-
this.logger.debug("Registration blocked at geo stage", { blockReasons });
|
|
1596
|
+
this.logger.debug("Registration blocked at geo stage", { blockReasons: structuredBlockReasons });
|
|
1521
1597
|
}
|
|
1522
1598
|
return {
|
|
1523
1599
|
allowed: false,
|
|
@@ -1525,9 +1601,7 @@ var ComplianceClient = class {
|
|
|
1525
1601
|
profile: null,
|
|
1526
1602
|
requiresKYC: false,
|
|
1527
1603
|
requiresEDD: false,
|
|
1528
|
-
|
|
1529
|
-
processingTime: Date.now() - startTime,
|
|
1530
|
-
cipherTextValidation: cipherTextResult
|
|
1604
|
+
...this.buildReasonTail(structuredBlockReasons, startTime, cipherTextResult)
|
|
1531
1605
|
};
|
|
1532
1606
|
}
|
|
1533
1607
|
const profile = await this.riskClient.createProfile({
|
|
@@ -1561,9 +1635,7 @@ var ComplianceClient = class {
|
|
|
1561
1635
|
profile,
|
|
1562
1636
|
requiresKYC,
|
|
1563
1637
|
requiresEDD,
|
|
1564
|
-
|
|
1565
|
-
processingTime: Date.now() - startTime,
|
|
1566
|
-
cipherTextValidation: cipherTextResult
|
|
1638
|
+
...this.buildReasonTail([], startTime, cipherTextResult)
|
|
1567
1639
|
};
|
|
1568
1640
|
} catch (error) {
|
|
1569
1641
|
if (this.config.debug) {
|
|
@@ -1597,52 +1669,62 @@ var ComplianceClient = class {
|
|
|
1597
1669
|
evaluateRegistrationBlock(geoVerification, cipherTextResult) {
|
|
1598
1670
|
const blockReasons = [];
|
|
1599
1671
|
if (geoVerification.is_blocked) {
|
|
1600
|
-
blockReasons.push(...geoVerification.
|
|
1672
|
+
blockReasons.push(...geoVerification.risk_reasons_structured ?? []);
|
|
1601
1673
|
}
|
|
1602
1674
|
if (!geoVerification.is_compliant) {
|
|
1603
|
-
if (!blockReasons.
|
|
1604
|
-
blockReasons.push(
|
|
1675
|
+
if (!blockReasons.some((r) => r.code === "JURISDICTION_NON_COMPLIANT")) {
|
|
1676
|
+
blockReasons.push(sdkReasons.jurisdictionNonCompliant());
|
|
1605
1677
|
}
|
|
1606
1678
|
}
|
|
1607
1679
|
const jurisdiction = geoVerification.jurisdiction;
|
|
1608
1680
|
if (jurisdiction) {
|
|
1609
1681
|
if (jurisdiction.allow_registration === false) {
|
|
1610
|
-
blockReasons.push(
|
|
1682
|
+
blockReasons.push(sdkReasons.jurisdictionRegistrationDenied());
|
|
1611
1683
|
}
|
|
1612
1684
|
if (jurisdiction.status === "blocked" || jurisdiction.status === "sanctioned") {
|
|
1613
|
-
if (!blockReasons.
|
|
1614
|
-
blockReasons.push("
|
|
1685
|
+
if (!blockReasons.some((r) => r.code === "JURISDICTION_BLOCKED")) {
|
|
1686
|
+
blockReasons.push(sdkReasons.jurisdictionBlocked(jurisdiction.country_name ?? "", jurisdiction.country_iso ?? ""));
|
|
1615
1687
|
}
|
|
1616
1688
|
}
|
|
1617
1689
|
if (jurisdiction.status === "restricted" && jurisdiction.allow_registration === false) {
|
|
1618
|
-
if (!blockReasons.
|
|
1619
|
-
blockReasons.push(
|
|
1690
|
+
if (!blockReasons.some((r) => r.code === "JURISDICTION_RESTRICTED")) {
|
|
1691
|
+
blockReasons.push(sdkReasons.jurisdictionRestricted());
|
|
1620
1692
|
}
|
|
1621
1693
|
}
|
|
1622
1694
|
}
|
|
1623
1695
|
if (geoVerification.geofence_evaluation?.blocked) {
|
|
1624
|
-
blockReasons.push(
|
|
1696
|
+
blockReasons.push(
|
|
1697
|
+
...(geoVerification.geofence_evaluation.reasons ?? []).map((m) => ({
|
|
1698
|
+
code: "JURISDICTION_GEOFENCE_VIOLATION",
|
|
1699
|
+
message: m
|
|
1700
|
+
}))
|
|
1701
|
+
);
|
|
1625
1702
|
}
|
|
1626
1703
|
if (geoVerification.risk_level === "critical") {
|
|
1627
|
-
if (!blockReasons.
|
|
1628
|
-
blockReasons.push(
|
|
1704
|
+
if (!blockReasons.some((r) => r.code === "RISK_CRITICAL_LEVEL")) {
|
|
1705
|
+
blockReasons.push(sdkReasons.riskCriticalLevel());
|
|
1629
1706
|
}
|
|
1630
1707
|
}
|
|
1631
1708
|
if (cipherTextResult) {
|
|
1632
1709
|
if (!cipherTextResult.valid) {
|
|
1633
|
-
blockReasons.push(
|
|
1710
|
+
blockReasons.push(sdkReasons.ciphertextInvalid());
|
|
1634
1711
|
}
|
|
1635
1712
|
if (cipherTextResult.risk?.is_blocked) {
|
|
1636
|
-
blockReasons.push(...cipherTextResult.risk.
|
|
1713
|
+
blockReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
1637
1714
|
}
|
|
1638
1715
|
if (cipherTextResult.risk?.location_mismatch) {
|
|
1639
|
-
blockReasons.push(
|
|
1716
|
+
blockReasons.push(sdkReasons.gpsIPMismatch());
|
|
1640
1717
|
}
|
|
1641
1718
|
}
|
|
1642
1719
|
if (geoVerification.gps_required && !cipherTextResult) {
|
|
1643
|
-
blockReasons.push(
|
|
1720
|
+
blockReasons.push(sdkReasons.gpsRequired());
|
|
1644
1721
|
}
|
|
1645
|
-
|
|
1722
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1723
|
+
return blockReasons.filter((r) => {
|
|
1724
|
+
if (seen.has(r.code)) return false;
|
|
1725
|
+
seen.add(r.code);
|
|
1726
|
+
return true;
|
|
1727
|
+
});
|
|
1646
1728
|
}
|
|
1647
1729
|
/**
|
|
1648
1730
|
* Validate registration request has all required fields
|
|
@@ -1813,9 +1895,7 @@ var ComplianceClient = class {
|
|
|
1813
1895
|
geolocation: geoVerification,
|
|
1814
1896
|
profile: null,
|
|
1815
1897
|
requiresStepUp: false,
|
|
1816
|
-
|
|
1817
|
-
processingTime: Date.now() - startTime,
|
|
1818
|
-
cipherTextValidation: cipherTextResult
|
|
1898
|
+
...this.buildReasonTail(loginBlockReasons, startTime, cipherTextResult)
|
|
1819
1899
|
};
|
|
1820
1900
|
}
|
|
1821
1901
|
let profile;
|
|
@@ -1835,14 +1915,13 @@ var ComplianceClient = class {
|
|
|
1835
1915
|
profile = await this.createProfileFromGeo(request.customerId, geoVerification);
|
|
1836
1916
|
}
|
|
1837
1917
|
const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical" || cipherTextResult?.risk?.location_mismatch === true;
|
|
1918
|
+
const loginFinalStructured = isBlocked || profile.customer_status === "suspended" ? this.getBlockReasons(geoVerification, profile, cipherTextResult) : [];
|
|
1838
1919
|
return {
|
|
1839
1920
|
allowed: !isBlocked && profile.customer_status !== "suspended",
|
|
1840
1921
|
geolocation: geoVerification,
|
|
1841
1922
|
profile,
|
|
1842
1923
|
requiresStepUp,
|
|
1843
|
-
|
|
1844
|
-
processingTime: Date.now() - startTime,
|
|
1845
|
-
cipherTextValidation: cipherTextResult
|
|
1924
|
+
...this.buildReasonTail(loginFinalStructured, startTime, cipherTextResult)
|
|
1846
1925
|
};
|
|
1847
1926
|
} catch (error) {
|
|
1848
1927
|
throw new ComplianceError("Login verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -1924,20 +2003,19 @@ var ComplianceClient = class {
|
|
|
1924
2003
|
}
|
|
1925
2004
|
const geoBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
|
|
1926
2005
|
if (geoBlocked && !profileResult) {
|
|
2006
|
+
const earlyStructured = this.getTransactionBlockReasons(
|
|
2007
|
+
geoVerification,
|
|
2008
|
+
{ score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
2009
|
+
true,
|
|
2010
|
+
cipherTextResult
|
|
2011
|
+
);
|
|
1927
2012
|
return {
|
|
1928
2013
|
allowed: false,
|
|
1929
2014
|
geolocation: geoVerification,
|
|
1930
2015
|
profile: null,
|
|
1931
2016
|
transactionRisk: { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1932
2017
|
requiresApproval: false,
|
|
1933
|
-
|
|
1934
|
-
geoVerification,
|
|
1935
|
-
{ score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1936
|
-
true,
|
|
1937
|
-
cipherTextResult
|
|
1938
|
-
),
|
|
1939
|
-
processingTime: Date.now() - startTime,
|
|
1940
|
-
cipherTextValidation: cipherTextResult
|
|
2018
|
+
...this.buildReasonTail(earlyStructured, startTime, cipherTextResult)
|
|
1941
2019
|
};
|
|
1942
2020
|
}
|
|
1943
2021
|
if (!profileResult) {
|
|
@@ -1957,20 +2035,19 @@ var ComplianceClient = class {
|
|
|
1957
2035
|
geoVerification.jurisdiction
|
|
1958
2036
|
);
|
|
1959
2037
|
const isAllowed = !geoBlocked && jurisdictionAllowed && transactionRisk.allowed && profile.customer_status !== "suspended";
|
|
2038
|
+
const txStructured = this.getTransactionBlockReasons(
|
|
2039
|
+
geoVerification,
|
|
2040
|
+
transactionRisk,
|
|
2041
|
+
jurisdictionAllowed,
|
|
2042
|
+
cipherTextResult
|
|
2043
|
+
);
|
|
1960
2044
|
return {
|
|
1961
2045
|
allowed: isAllowed,
|
|
1962
2046
|
geolocation: geoVerification,
|
|
1963
2047
|
profile,
|
|
1964
2048
|
transactionRisk,
|
|
1965
2049
|
requiresApproval: transactionRisk.requiresManualReview,
|
|
1966
|
-
|
|
1967
|
-
geoVerification,
|
|
1968
|
-
transactionRisk,
|
|
1969
|
-
jurisdictionAllowed,
|
|
1970
|
-
cipherTextResult
|
|
1971
|
-
),
|
|
1972
|
-
processingTime: Date.now() - startTime,
|
|
1973
|
-
cipherTextValidation: cipherTextResult
|
|
2050
|
+
...this.buildReasonTail(txStructured, startTime, cipherTextResult)
|
|
1974
2051
|
};
|
|
1975
2052
|
} catch (error) {
|
|
1976
2053
|
throw new ComplianceError("Transaction verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -2023,30 +2100,42 @@ var ComplianceClient = class {
|
|
|
2023
2100
|
}
|
|
2024
2101
|
}
|
|
2025
2102
|
const cipherTextBlocked = cipherTextResult ? !cipherTextResult.valid || cipherTextResult.risk?.is_blocked === true : false;
|
|
2026
|
-
const
|
|
2103
|
+
const structuredEventReasons = [...geoVerification.risk_reasons_structured ?? []];
|
|
2027
2104
|
if (cipherTextResult) {
|
|
2028
2105
|
if (!cipherTextResult.valid) {
|
|
2029
|
-
|
|
2106
|
+
structuredEventReasons.push(sdkReasons.ciphertextInvalid());
|
|
2030
2107
|
}
|
|
2031
2108
|
if (cipherTextResult.risk?.is_blocked) {
|
|
2032
|
-
|
|
2109
|
+
structuredEventReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
2033
2110
|
}
|
|
2034
2111
|
}
|
|
2035
2112
|
const gpsBlocked = geoVerification.gps_required && !cipherTextResult;
|
|
2036
2113
|
if (gpsBlocked) {
|
|
2037
|
-
|
|
2114
|
+
structuredEventReasons.push(sdkReasons.gpsRequired());
|
|
2038
2115
|
}
|
|
2116
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2117
|
+
const dedupedStructured = structuredEventReasons.filter((r) => {
|
|
2118
|
+
if (seen.has(r.code)) return false;
|
|
2119
|
+
seen.add(r.code);
|
|
2120
|
+
return true;
|
|
2121
|
+
});
|
|
2039
2122
|
return {
|
|
2040
2123
|
allowed: geoVerification.is_compliant && !geoVerification.is_blocked && !cipherTextBlocked && !gpsBlocked,
|
|
2041
2124
|
geolocation: geoVerification,
|
|
2042
|
-
|
|
2043
|
-
processingTime: Date.now() - startTime,
|
|
2044
|
-
cipherTextValidation: cipherTextResult
|
|
2125
|
+
...this.buildReasonTail(dedupedStructured, startTime, cipherTextResult)
|
|
2045
2126
|
};
|
|
2046
2127
|
}
|
|
2047
2128
|
// ============================================================================
|
|
2048
2129
|
// Helper Methods
|
|
2049
2130
|
// ============================================================================
|
|
2131
|
+
buildReasonTail(structured, startTime, cipherTextResult) {
|
|
2132
|
+
return {
|
|
2133
|
+
blockReasons: structured.map((r) => r.message),
|
|
2134
|
+
blockReasonsStructured: structured,
|
|
2135
|
+
processingTime: Date.now() - startTime,
|
|
2136
|
+
cipherTextValidation: cipherTextResult
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2050
2139
|
shouldUpdateProfile(profile, newCity) {
|
|
2051
2140
|
return !profile.location || !profile.location.includes(newCity);
|
|
2052
2141
|
}
|
|
@@ -2123,7 +2212,8 @@ var ComplianceClient = class {
|
|
|
2123
2212
|
is_blocked: risk.is_blocked,
|
|
2124
2213
|
risk_level: risk.level,
|
|
2125
2214
|
risk_score: risk.score,
|
|
2126
|
-
risk_reasons:
|
|
2215
|
+
risk_reasons: [],
|
|
2216
|
+
risk_reasons_structured: risk.is_blocked && risk.block_reasons_structured ? risk.block_reasons_structured : [],
|
|
2127
2217
|
jurisdiction: ct.jurisdiction,
|
|
2128
2218
|
geofence_evaluation: ct.geofence_evaluation,
|
|
2129
2219
|
record_id: ct.record_id ?? "",
|
|
@@ -2138,35 +2228,35 @@ var ComplianceClient = class {
|
|
|
2138
2228
|
);
|
|
2139
2229
|
}
|
|
2140
2230
|
let riskScore = 0;
|
|
2141
|
-
const
|
|
2231
|
+
const structuredFactors = [];
|
|
2142
2232
|
const normalizedAmount = this.normalizeToUSD(amount, currency);
|
|
2143
2233
|
if (normalizedAmount > 1e4) {
|
|
2144
2234
|
riskScore += 30;
|
|
2145
|
-
|
|
2235
|
+
structuredFactors.push(sdkReasons.transactionHighAmount(normalizedAmount, currency, 1e4));
|
|
2146
2236
|
} else if (normalizedAmount > 5e3) {
|
|
2147
2237
|
riskScore += 15;
|
|
2148
|
-
|
|
2238
|
+
structuredFactors.push(sdkReasons.transactionElevatedAmount(normalizedAmount, currency, 5e3));
|
|
2149
2239
|
}
|
|
2150
2240
|
riskScore += geoVerification.risk_score * 0.4;
|
|
2151
2241
|
if (geoVerification.risk_level === "high" || geoVerification.risk_level === "critical") {
|
|
2152
|
-
|
|
2242
|
+
structuredFactors.push(sdkReasons.riskHighLocation());
|
|
2153
2243
|
}
|
|
2154
2244
|
riskScore += profile.risk_score * 0.3;
|
|
2155
2245
|
if (profile.risk_category === "high" || profile.risk_category === "critical") {
|
|
2156
|
-
|
|
2246
|
+
structuredFactors.push(sdkReasons.riskHighCustomer());
|
|
2157
2247
|
}
|
|
2158
2248
|
if (geoVerification.location.is_vpn || geoVerification.location.is_proxy) {
|
|
2159
2249
|
riskScore += 20;
|
|
2160
|
-
|
|
2250
|
+
structuredFactors.push(sdkReasons.anonymizationDetected());
|
|
2161
2251
|
}
|
|
2162
2252
|
if (profile.customer_status === "suspended") {
|
|
2163
2253
|
riskScore += 50;
|
|
2164
|
-
|
|
2254
|
+
structuredFactors.push(sdkReasons.accountSuspended());
|
|
2165
2255
|
}
|
|
2166
2256
|
if (cipherTextResult) {
|
|
2167
2257
|
if (cipherTextResult.risk?.location_mismatch) {
|
|
2168
2258
|
riskScore += 20;
|
|
2169
|
-
|
|
2259
|
+
structuredFactors.push(sdkReasons.gpsIPMismatch());
|
|
2170
2260
|
}
|
|
2171
2261
|
if (cipherTextResult.risk?.score) {
|
|
2172
2262
|
riskScore += cipherTextResult.risk.score * 0.2;
|
|
@@ -2175,7 +2265,8 @@ var ComplianceClient = class {
|
|
|
2175
2265
|
return {
|
|
2176
2266
|
score: Math.min(riskScore, 100),
|
|
2177
2267
|
level: this.getRiskLevel(riskScore),
|
|
2178
|
-
factors,
|
|
2268
|
+
factors: structuredFactors.map((r) => r.message),
|
|
2269
|
+
factorsStructured: structuredFactors,
|
|
2179
2270
|
allowed: riskScore < 70,
|
|
2180
2271
|
requiresManualReview: riskScore >= 60 && riskScore < 70
|
|
2181
2272
|
};
|
|
@@ -2200,52 +2291,62 @@ var ComplianceClient = class {
|
|
|
2200
2291
|
getBlockReasons(geoVerification, profile, cipherTextResult) {
|
|
2201
2292
|
const reasons = [];
|
|
2202
2293
|
if (geoVerification.is_blocked) {
|
|
2203
|
-
reasons.push(...geoVerification.
|
|
2294
|
+
reasons.push(...geoVerification.risk_reasons_structured ?? []);
|
|
2204
2295
|
}
|
|
2205
2296
|
if (profile) {
|
|
2206
2297
|
if (profile.customer_status === "suspended") {
|
|
2207
|
-
reasons.push(
|
|
2298
|
+
reasons.push(sdkReasons.accountSuspended());
|
|
2208
2299
|
}
|
|
2209
2300
|
if (profile.has_sanctions) {
|
|
2210
|
-
reasons.push(
|
|
2301
|
+
reasons.push(sdkReasons.sanctionsMatch());
|
|
2211
2302
|
}
|
|
2212
2303
|
}
|
|
2213
2304
|
if (cipherTextResult) {
|
|
2214
2305
|
if (!cipherTextResult.valid) {
|
|
2215
|
-
reasons.push(
|
|
2306
|
+
reasons.push(sdkReasons.ciphertextInvalid());
|
|
2216
2307
|
}
|
|
2217
2308
|
if (cipherTextResult.risk?.is_blocked) {
|
|
2218
|
-
reasons.push(...cipherTextResult.risk.
|
|
2309
|
+
reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
2219
2310
|
}
|
|
2220
2311
|
}
|
|
2221
2312
|
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2222
|
-
reasons.push(
|
|
2313
|
+
reasons.push(sdkReasons.gpsRequired());
|
|
2223
2314
|
}
|
|
2224
|
-
|
|
2315
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2316
|
+
return reasons.filter((r) => {
|
|
2317
|
+
if (seen.has(r.code)) return false;
|
|
2318
|
+
seen.add(r.code);
|
|
2319
|
+
return true;
|
|
2320
|
+
});
|
|
2225
2321
|
}
|
|
2226
2322
|
getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed, cipherTextResult) {
|
|
2227
2323
|
const reasons = [];
|
|
2228
2324
|
if (!geoVerification.is_compliant) {
|
|
2229
|
-
reasons.push(
|
|
2325
|
+
reasons.push(sdkReasons.jurisdictionNonCompliant());
|
|
2230
2326
|
}
|
|
2231
2327
|
if (!jurisdictionAllowed) {
|
|
2232
|
-
reasons.push(
|
|
2328
|
+
reasons.push(sdkReasons.transactionJurisdictionLimit());
|
|
2233
2329
|
}
|
|
2234
2330
|
if (!transactionRisk.allowed) {
|
|
2235
|
-
reasons.push(...transactionRisk.
|
|
2331
|
+
reasons.push(...transactionRisk.factorsStructured ?? []);
|
|
2236
2332
|
}
|
|
2237
2333
|
if (cipherTextResult) {
|
|
2238
2334
|
if (!cipherTextResult.valid) {
|
|
2239
|
-
reasons.push(
|
|
2335
|
+
reasons.push(sdkReasons.ciphertextInvalid());
|
|
2240
2336
|
}
|
|
2241
2337
|
if (cipherTextResult.risk?.is_blocked) {
|
|
2242
|
-
reasons.push(...cipherTextResult.risk.
|
|
2338
|
+
reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
2243
2339
|
}
|
|
2244
2340
|
}
|
|
2245
2341
|
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2246
|
-
reasons.push(
|
|
2342
|
+
reasons.push(sdkReasons.gpsRequired());
|
|
2247
2343
|
}
|
|
2248
|
-
|
|
2344
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2345
|
+
return reasons.filter((r) => {
|
|
2346
|
+
if (seen.has(r.code)) return false;
|
|
2347
|
+
seen.add(r.code);
|
|
2348
|
+
return true;
|
|
2349
|
+
});
|
|
2249
2350
|
}
|
|
2250
2351
|
// ============================================================================
|
|
2251
2352
|
// Location Request Methods
|
|
@@ -2463,6 +2564,6 @@ var ComplianceClient = class {
|
|
|
2463
2564
|
}
|
|
2464
2565
|
};
|
|
2465
2566
|
|
|
2466
|
-
export { ComplianceClient, DEFAULT_CURRENCY_RATES };
|
|
2567
|
+
export { ComplianceClient, DEFAULT_CURRENCY_RATES, sdkReasons };
|
|
2467
2568
|
//# sourceMappingURL=index.mjs.map
|
|
2468
2569
|
//# sourceMappingURL=index.mjs.map
|