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
package/dist/compliance/index.js
CHANGED
|
@@ -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.
|
|
302
|
+
var SDK_VERSION = "1.7.0";
|
|
228
303
|
|
|
229
304
|
// src/shared/browser-utils.ts
|
|
230
305
|
function generateUUID() {
|
|
@@ -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 ?? "",
|
|
@@ -1516,10 +1592,10 @@ var ComplianceClient = class {
|
|
|
1516
1592
|
device_fingerprint: request.deviceFingerprint
|
|
1517
1593
|
}, requestOptions);
|
|
1518
1594
|
}
|
|
1519
|
-
const
|
|
1520
|
-
if (
|
|
1595
|
+
const structuredBlockReasons = this.evaluateRegistrationBlock(geoVerification, cipherTextResult);
|
|
1596
|
+
if (structuredBlockReasons.length > 0) {
|
|
1521
1597
|
if (this.config.debug) {
|
|
1522
|
-
this.logger.debug("Registration blocked at geo stage", { blockReasons });
|
|
1598
|
+
this.logger.debug("Registration blocked at geo stage", { blockReasons: structuredBlockReasons });
|
|
1523
1599
|
}
|
|
1524
1600
|
return {
|
|
1525
1601
|
allowed: false,
|
|
@@ -1527,9 +1603,7 @@ var ComplianceClient = class {
|
|
|
1527
1603
|
profile: null,
|
|
1528
1604
|
requiresKYC: false,
|
|
1529
1605
|
requiresEDD: false,
|
|
1530
|
-
|
|
1531
|
-
processingTime: Date.now() - startTime,
|
|
1532
|
-
cipherTextValidation: cipherTextResult
|
|
1606
|
+
...this.buildReasonTail(structuredBlockReasons, startTime, cipherTextResult)
|
|
1533
1607
|
};
|
|
1534
1608
|
}
|
|
1535
1609
|
const profile = await this.riskClient.createProfile({
|
|
@@ -1563,9 +1637,7 @@ var ComplianceClient = class {
|
|
|
1563
1637
|
profile,
|
|
1564
1638
|
requiresKYC,
|
|
1565
1639
|
requiresEDD,
|
|
1566
|
-
|
|
1567
|
-
processingTime: Date.now() - startTime,
|
|
1568
|
-
cipherTextValidation: cipherTextResult
|
|
1640
|
+
...this.buildReasonTail([], startTime, cipherTextResult)
|
|
1569
1641
|
};
|
|
1570
1642
|
} catch (error) {
|
|
1571
1643
|
if (this.config.debug) {
|
|
@@ -1599,52 +1671,62 @@ var ComplianceClient = class {
|
|
|
1599
1671
|
evaluateRegistrationBlock(geoVerification, cipherTextResult) {
|
|
1600
1672
|
const blockReasons = [];
|
|
1601
1673
|
if (geoVerification.is_blocked) {
|
|
1602
|
-
blockReasons.push(...geoVerification.
|
|
1674
|
+
blockReasons.push(...geoVerification.risk_reasons_structured ?? []);
|
|
1603
1675
|
}
|
|
1604
1676
|
if (!geoVerification.is_compliant) {
|
|
1605
|
-
if (!blockReasons.
|
|
1606
|
-
blockReasons.push(
|
|
1677
|
+
if (!blockReasons.some((r) => r.code === "JURISDICTION_NON_COMPLIANT")) {
|
|
1678
|
+
blockReasons.push(sdkReasons.jurisdictionNonCompliant());
|
|
1607
1679
|
}
|
|
1608
1680
|
}
|
|
1609
1681
|
const jurisdiction = geoVerification.jurisdiction;
|
|
1610
1682
|
if (jurisdiction) {
|
|
1611
1683
|
if (jurisdiction.allow_registration === false) {
|
|
1612
|
-
blockReasons.push(
|
|
1684
|
+
blockReasons.push(sdkReasons.jurisdictionRegistrationDenied());
|
|
1613
1685
|
}
|
|
1614
1686
|
if (jurisdiction.status === "blocked" || jurisdiction.status === "sanctioned") {
|
|
1615
|
-
if (!blockReasons.
|
|
1616
|
-
blockReasons.push("
|
|
1687
|
+
if (!blockReasons.some((r) => r.code === "JURISDICTION_BLOCKED")) {
|
|
1688
|
+
blockReasons.push(sdkReasons.jurisdictionBlocked(jurisdiction.country_name ?? "", jurisdiction.country_iso ?? ""));
|
|
1617
1689
|
}
|
|
1618
1690
|
}
|
|
1619
1691
|
if (jurisdiction.status === "restricted" && jurisdiction.allow_registration === false) {
|
|
1620
|
-
if (!blockReasons.
|
|
1621
|
-
blockReasons.push(
|
|
1692
|
+
if (!blockReasons.some((r) => r.code === "JURISDICTION_RESTRICTED")) {
|
|
1693
|
+
blockReasons.push(sdkReasons.jurisdictionRestricted());
|
|
1622
1694
|
}
|
|
1623
1695
|
}
|
|
1624
1696
|
}
|
|
1625
1697
|
if (geoVerification.geofence_evaluation?.blocked) {
|
|
1626
|
-
blockReasons.push(
|
|
1698
|
+
blockReasons.push(
|
|
1699
|
+
...(geoVerification.geofence_evaluation.reasons ?? []).map((m) => ({
|
|
1700
|
+
code: "JURISDICTION_GEOFENCE_VIOLATION",
|
|
1701
|
+
message: m
|
|
1702
|
+
}))
|
|
1703
|
+
);
|
|
1627
1704
|
}
|
|
1628
1705
|
if (geoVerification.risk_level === "critical") {
|
|
1629
|
-
if (!blockReasons.
|
|
1630
|
-
blockReasons.push(
|
|
1706
|
+
if (!blockReasons.some((r) => r.code === "RISK_CRITICAL_LEVEL")) {
|
|
1707
|
+
blockReasons.push(sdkReasons.riskCriticalLevel());
|
|
1631
1708
|
}
|
|
1632
1709
|
}
|
|
1633
1710
|
if (cipherTextResult) {
|
|
1634
1711
|
if (!cipherTextResult.valid) {
|
|
1635
|
-
blockReasons.push(
|
|
1712
|
+
blockReasons.push(sdkReasons.ciphertextInvalid());
|
|
1636
1713
|
}
|
|
1637
1714
|
if (cipherTextResult.risk?.is_blocked) {
|
|
1638
|
-
blockReasons.push(...cipherTextResult.risk.
|
|
1715
|
+
blockReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
1639
1716
|
}
|
|
1640
1717
|
if (cipherTextResult.risk?.location_mismatch) {
|
|
1641
|
-
blockReasons.push(
|
|
1718
|
+
blockReasons.push(sdkReasons.gpsIPMismatch());
|
|
1642
1719
|
}
|
|
1643
1720
|
}
|
|
1644
1721
|
if (geoVerification.gps_required && !cipherTextResult) {
|
|
1645
|
-
blockReasons.push(
|
|
1722
|
+
blockReasons.push(sdkReasons.gpsRequired());
|
|
1646
1723
|
}
|
|
1647
|
-
|
|
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
|
+
});
|
|
1648
1730
|
}
|
|
1649
1731
|
/**
|
|
1650
1732
|
* Validate registration request has all required fields
|
|
@@ -1815,9 +1897,7 @@ var ComplianceClient = class {
|
|
|
1815
1897
|
geolocation: geoVerification,
|
|
1816
1898
|
profile: null,
|
|
1817
1899
|
requiresStepUp: false,
|
|
1818
|
-
|
|
1819
|
-
processingTime: Date.now() - startTime,
|
|
1820
|
-
cipherTextValidation: cipherTextResult
|
|
1900
|
+
...this.buildReasonTail(loginBlockReasons, startTime, cipherTextResult)
|
|
1821
1901
|
};
|
|
1822
1902
|
}
|
|
1823
1903
|
let profile;
|
|
@@ -1837,14 +1917,13 @@ var ComplianceClient = class {
|
|
|
1837
1917
|
profile = await this.createProfileFromGeo(request.customerId, geoVerification);
|
|
1838
1918
|
}
|
|
1839
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) : [];
|
|
1840
1921
|
return {
|
|
1841
1922
|
allowed: !isBlocked && profile.customer_status !== "suspended",
|
|
1842
1923
|
geolocation: geoVerification,
|
|
1843
1924
|
profile,
|
|
1844
1925
|
requiresStepUp,
|
|
1845
|
-
|
|
1846
|
-
processingTime: Date.now() - startTime,
|
|
1847
|
-
cipherTextValidation: cipherTextResult
|
|
1926
|
+
...this.buildReasonTail(loginFinalStructured, startTime, cipherTextResult)
|
|
1848
1927
|
};
|
|
1849
1928
|
} catch (error) {
|
|
1850
1929
|
throw new ComplianceError("Login verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -1926,20 +2005,19 @@ var ComplianceClient = class {
|
|
|
1926
2005
|
}
|
|
1927
2006
|
const geoBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
|
|
1928
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
|
+
);
|
|
1929
2014
|
return {
|
|
1930
2015
|
allowed: false,
|
|
1931
2016
|
geolocation: geoVerification,
|
|
1932
2017
|
profile: null,
|
|
1933
2018
|
transactionRisk: { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1934
2019
|
requiresApproval: false,
|
|
1935
|
-
|
|
1936
|
-
geoVerification,
|
|
1937
|
-
{ score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1938
|
-
true,
|
|
1939
|
-
cipherTextResult
|
|
1940
|
-
),
|
|
1941
|
-
processingTime: Date.now() - startTime,
|
|
1942
|
-
cipherTextValidation: cipherTextResult
|
|
2020
|
+
...this.buildReasonTail(earlyStructured, startTime, cipherTextResult)
|
|
1943
2021
|
};
|
|
1944
2022
|
}
|
|
1945
2023
|
if (!profileResult) {
|
|
@@ -1959,20 +2037,19 @@ var ComplianceClient = class {
|
|
|
1959
2037
|
geoVerification.jurisdiction
|
|
1960
2038
|
);
|
|
1961
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
|
+
);
|
|
1962
2046
|
return {
|
|
1963
2047
|
allowed: isAllowed,
|
|
1964
2048
|
geolocation: geoVerification,
|
|
1965
2049
|
profile,
|
|
1966
2050
|
transactionRisk,
|
|
1967
2051
|
requiresApproval: transactionRisk.requiresManualReview,
|
|
1968
|
-
|
|
1969
|
-
geoVerification,
|
|
1970
|
-
transactionRisk,
|
|
1971
|
-
jurisdictionAllowed,
|
|
1972
|
-
cipherTextResult
|
|
1973
|
-
),
|
|
1974
|
-
processingTime: Date.now() - startTime,
|
|
1975
|
-
cipherTextValidation: cipherTextResult
|
|
2052
|
+
...this.buildReasonTail(txStructured, startTime, cipherTextResult)
|
|
1976
2053
|
};
|
|
1977
2054
|
} catch (error) {
|
|
1978
2055
|
throw new ComplianceError("Transaction verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -2025,30 +2102,42 @@ var ComplianceClient = class {
|
|
|
2025
2102
|
}
|
|
2026
2103
|
}
|
|
2027
2104
|
const cipherTextBlocked = cipherTextResult ? !cipherTextResult.valid || cipherTextResult.risk?.is_blocked === true : false;
|
|
2028
|
-
const
|
|
2105
|
+
const structuredEventReasons = [...geoVerification.risk_reasons_structured ?? []];
|
|
2029
2106
|
if (cipherTextResult) {
|
|
2030
2107
|
if (!cipherTextResult.valid) {
|
|
2031
|
-
|
|
2108
|
+
structuredEventReasons.push(sdkReasons.ciphertextInvalid());
|
|
2032
2109
|
}
|
|
2033
2110
|
if (cipherTextResult.risk?.is_blocked) {
|
|
2034
|
-
|
|
2111
|
+
structuredEventReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
2035
2112
|
}
|
|
2036
2113
|
}
|
|
2037
2114
|
const gpsBlocked = geoVerification.gps_required && !cipherTextResult;
|
|
2038
2115
|
if (gpsBlocked) {
|
|
2039
|
-
|
|
2116
|
+
structuredEventReasons.push(sdkReasons.gpsRequired());
|
|
2040
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
|
+
});
|
|
2041
2124
|
return {
|
|
2042
2125
|
allowed: geoVerification.is_compliant && !geoVerification.is_blocked && !cipherTextBlocked && !gpsBlocked,
|
|
2043
2126
|
geolocation: geoVerification,
|
|
2044
|
-
|
|
2045
|
-
processingTime: Date.now() - startTime,
|
|
2046
|
-
cipherTextValidation: cipherTextResult
|
|
2127
|
+
...this.buildReasonTail(dedupedStructured, startTime, cipherTextResult)
|
|
2047
2128
|
};
|
|
2048
2129
|
}
|
|
2049
2130
|
// ============================================================================
|
|
2050
2131
|
// Helper Methods
|
|
2051
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
|
+
}
|
|
2052
2141
|
shouldUpdateProfile(profile, newCity) {
|
|
2053
2142
|
return !profile.location || !profile.location.includes(newCity);
|
|
2054
2143
|
}
|
|
@@ -2125,7 +2214,8 @@ var ComplianceClient = class {
|
|
|
2125
2214
|
is_blocked: risk.is_blocked,
|
|
2126
2215
|
risk_level: risk.level,
|
|
2127
2216
|
risk_score: risk.score,
|
|
2128
|
-
risk_reasons:
|
|
2217
|
+
risk_reasons: [],
|
|
2218
|
+
risk_reasons_structured: risk.is_blocked && risk.block_reasons_structured ? risk.block_reasons_structured : [],
|
|
2129
2219
|
jurisdiction: ct.jurisdiction,
|
|
2130
2220
|
geofence_evaluation: ct.geofence_evaluation,
|
|
2131
2221
|
record_id: ct.record_id ?? "",
|
|
@@ -2140,35 +2230,35 @@ var ComplianceClient = class {
|
|
|
2140
2230
|
);
|
|
2141
2231
|
}
|
|
2142
2232
|
let riskScore = 0;
|
|
2143
|
-
const
|
|
2233
|
+
const structuredFactors = [];
|
|
2144
2234
|
const normalizedAmount = this.normalizeToUSD(amount, currency);
|
|
2145
2235
|
if (normalizedAmount > 1e4) {
|
|
2146
2236
|
riskScore += 30;
|
|
2147
|
-
|
|
2237
|
+
structuredFactors.push(sdkReasons.transactionHighAmount(normalizedAmount, currency, 1e4));
|
|
2148
2238
|
} else if (normalizedAmount > 5e3) {
|
|
2149
2239
|
riskScore += 15;
|
|
2150
|
-
|
|
2240
|
+
structuredFactors.push(sdkReasons.transactionElevatedAmount(normalizedAmount, currency, 5e3));
|
|
2151
2241
|
}
|
|
2152
2242
|
riskScore += geoVerification.risk_score * 0.4;
|
|
2153
2243
|
if (geoVerification.risk_level === "high" || geoVerification.risk_level === "critical") {
|
|
2154
|
-
|
|
2244
|
+
structuredFactors.push(sdkReasons.riskHighLocation());
|
|
2155
2245
|
}
|
|
2156
2246
|
riskScore += profile.risk_score * 0.3;
|
|
2157
2247
|
if (profile.risk_category === "high" || profile.risk_category === "critical") {
|
|
2158
|
-
|
|
2248
|
+
structuredFactors.push(sdkReasons.riskHighCustomer());
|
|
2159
2249
|
}
|
|
2160
2250
|
if (geoVerification.location.is_vpn || geoVerification.location.is_proxy) {
|
|
2161
2251
|
riskScore += 20;
|
|
2162
|
-
|
|
2252
|
+
structuredFactors.push(sdkReasons.anonymizationDetected());
|
|
2163
2253
|
}
|
|
2164
2254
|
if (profile.customer_status === "suspended") {
|
|
2165
2255
|
riskScore += 50;
|
|
2166
|
-
|
|
2256
|
+
structuredFactors.push(sdkReasons.accountSuspended());
|
|
2167
2257
|
}
|
|
2168
2258
|
if (cipherTextResult) {
|
|
2169
2259
|
if (cipherTextResult.risk?.location_mismatch) {
|
|
2170
2260
|
riskScore += 20;
|
|
2171
|
-
|
|
2261
|
+
structuredFactors.push(sdkReasons.gpsIPMismatch());
|
|
2172
2262
|
}
|
|
2173
2263
|
if (cipherTextResult.risk?.score) {
|
|
2174
2264
|
riskScore += cipherTextResult.risk.score * 0.2;
|
|
@@ -2177,7 +2267,8 @@ var ComplianceClient = class {
|
|
|
2177
2267
|
return {
|
|
2178
2268
|
score: Math.min(riskScore, 100),
|
|
2179
2269
|
level: this.getRiskLevel(riskScore),
|
|
2180
|
-
factors,
|
|
2270
|
+
factors: structuredFactors.map((r) => r.message),
|
|
2271
|
+
factorsStructured: structuredFactors,
|
|
2181
2272
|
allowed: riskScore < 70,
|
|
2182
2273
|
requiresManualReview: riskScore >= 60 && riskScore < 70
|
|
2183
2274
|
};
|
|
@@ -2202,52 +2293,62 @@ var ComplianceClient = class {
|
|
|
2202
2293
|
getBlockReasons(geoVerification, profile, cipherTextResult) {
|
|
2203
2294
|
const reasons = [];
|
|
2204
2295
|
if (geoVerification.is_blocked) {
|
|
2205
|
-
reasons.push(...geoVerification.
|
|
2296
|
+
reasons.push(...geoVerification.risk_reasons_structured ?? []);
|
|
2206
2297
|
}
|
|
2207
2298
|
if (profile) {
|
|
2208
2299
|
if (profile.customer_status === "suspended") {
|
|
2209
|
-
reasons.push(
|
|
2300
|
+
reasons.push(sdkReasons.accountSuspended());
|
|
2210
2301
|
}
|
|
2211
2302
|
if (profile.has_sanctions) {
|
|
2212
|
-
reasons.push(
|
|
2303
|
+
reasons.push(sdkReasons.sanctionsMatch());
|
|
2213
2304
|
}
|
|
2214
2305
|
}
|
|
2215
2306
|
if (cipherTextResult) {
|
|
2216
2307
|
if (!cipherTextResult.valid) {
|
|
2217
|
-
reasons.push(
|
|
2308
|
+
reasons.push(sdkReasons.ciphertextInvalid());
|
|
2218
2309
|
}
|
|
2219
2310
|
if (cipherTextResult.risk?.is_blocked) {
|
|
2220
|
-
reasons.push(...cipherTextResult.risk.
|
|
2311
|
+
reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
2221
2312
|
}
|
|
2222
2313
|
}
|
|
2223
2314
|
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2224
|
-
reasons.push(
|
|
2315
|
+
reasons.push(sdkReasons.gpsRequired());
|
|
2225
2316
|
}
|
|
2226
|
-
|
|
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
|
+
});
|
|
2227
2323
|
}
|
|
2228
2324
|
getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed, cipherTextResult) {
|
|
2229
2325
|
const reasons = [];
|
|
2230
2326
|
if (!geoVerification.is_compliant) {
|
|
2231
|
-
reasons.push(
|
|
2327
|
+
reasons.push(sdkReasons.jurisdictionNonCompliant());
|
|
2232
2328
|
}
|
|
2233
2329
|
if (!jurisdictionAllowed) {
|
|
2234
|
-
reasons.push(
|
|
2330
|
+
reasons.push(sdkReasons.transactionJurisdictionLimit());
|
|
2235
2331
|
}
|
|
2236
2332
|
if (!transactionRisk.allowed) {
|
|
2237
|
-
reasons.push(...transactionRisk.
|
|
2333
|
+
reasons.push(...transactionRisk.factorsStructured ?? []);
|
|
2238
2334
|
}
|
|
2239
2335
|
if (cipherTextResult) {
|
|
2240
2336
|
if (!cipherTextResult.valid) {
|
|
2241
|
-
reasons.push(
|
|
2337
|
+
reasons.push(sdkReasons.ciphertextInvalid());
|
|
2242
2338
|
}
|
|
2243
2339
|
if (cipherTextResult.risk?.is_blocked) {
|
|
2244
|
-
reasons.push(...cipherTextResult.risk.
|
|
2340
|
+
reasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
2245
2341
|
}
|
|
2246
2342
|
}
|
|
2247
2343
|
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2248
|
-
reasons.push(
|
|
2344
|
+
reasons.push(sdkReasons.gpsRequired());
|
|
2249
2345
|
}
|
|
2250
|
-
|
|
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
|
+
});
|
|
2251
2352
|
}
|
|
2252
2353
|
// ============================================================================
|
|
2253
2354
|
// Location Request Methods
|
|
@@ -2467,5 +2568,6 @@ var ComplianceClient = class {
|
|
|
2467
2568
|
|
|
2468
2569
|
exports.ComplianceClient = ComplianceClient;
|
|
2469
2570
|
exports.DEFAULT_CURRENCY_RATES = DEFAULT_CURRENCY_RATES;
|
|
2571
|
+
exports.sdkReasons = sdkReasons;
|
|
2470
2572
|
//# sourceMappingURL=index.js.map
|
|
2471
2573
|
//# sourceMappingURL=index.js.map
|