vesant-sdk 1.5.2 → 1.6.1
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/dist/{client-BZxzOidG.d.mts → client-DW1Xiz6a.d.mts} +4 -2
- package/dist/{client-B8pFrXx_.d.ts → client-eLbtPRkh.d.ts} +4 -2
- package/dist/{client-CIon-bGS.d.mts → client-ePzhQKp9.d.mts} +2 -0
- package/dist/{client-CIon-bGS.d.ts → client-ePzhQKp9.d.ts} +2 -0
- package/dist/compliance/index.d.mts +18 -5
- package/dist/compliance/index.d.ts +18 -5
- package/dist/compliance/index.js +222 -42
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +222 -42
- 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 +14 -1
- package/dist/decisions/index.js.map +1 -1
- package/dist/decisions/index.mjs +14 -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 +14 -1
- package/dist/geolocation/index.js.map +1 -1
- package/dist/geolocation/index.mjs +14 -1
- package/dist/geolocation/index.mjs.map +1 -1
- package/dist/index.d.mts +6 -376
- package/dist/index.d.ts +6 -376
- package/dist/index.js +289 -251
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +289 -251
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.d.mts +1 -1
- package/dist/kyc/core.d.ts +1 -1
- package/dist/kyc/core.js +14 -1
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs +14 -1
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.d.mts +1 -1
- package/dist/kyc/index.d.ts +1 -1
- package/dist/kyc/index.js +14 -1
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs +14 -1
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1 -1
- package/dist/react.mjs.map +1 -1
- package/dist/risk-profile/index.d.mts +1 -1
- package/dist/risk-profile/index.d.ts +1 -1
- package/dist/risk-profile/index.js +14 -1
- package/dist/risk-profile/index.js.map +1 -1
- package/dist/risk-profile/index.mjs +14 -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 +14 -1
- package/dist/scores/index.js.map +1 -1
- package/dist/scores/index.mjs +14 -1
- package/dist/scores/index.mjs.map +1 -1
- package/dist/tax/index.d.mts +256 -0
- package/dist/tax/index.d.ts +256 -0
- package/dist/tax/index.js +652 -0
- package/dist/tax/index.js.map +1 -0
- package/dist/tax/index.mjs +650 -0
- package/dist/tax/index.mjs.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -242,7 +242,7 @@ var noopLogger = {
|
|
|
242
242
|
};
|
|
243
243
|
|
|
244
244
|
// src/core/version.ts
|
|
245
|
-
var SDK_VERSION = "1.
|
|
245
|
+
var SDK_VERSION = "1.6.1";
|
|
246
246
|
|
|
247
247
|
// src/shared/browser-utils.ts
|
|
248
248
|
function generateUUID() {
|
|
@@ -416,6 +416,19 @@ var BaseClient = class {
|
|
|
416
416
|
if (this.rateLimitTracker) {
|
|
417
417
|
this.rateLimitTracker.updateFromHeaders(response.headers);
|
|
418
418
|
}
|
|
419
|
+
if (requestOptions?.responseType === "arraybuffer") {
|
|
420
|
+
if (!response.ok) {
|
|
421
|
+
let errData = {};
|
|
422
|
+
try {
|
|
423
|
+
errData = await response.json();
|
|
424
|
+
} catch {
|
|
425
|
+
}
|
|
426
|
+
this.handleErrorResponse(response.status, errData, requestId);
|
|
427
|
+
}
|
|
428
|
+
this.circuitBreaker?.onSuccess();
|
|
429
|
+
const buffer = await response.arrayBuffer();
|
|
430
|
+
return buffer;
|
|
431
|
+
}
|
|
419
432
|
let data;
|
|
420
433
|
try {
|
|
421
434
|
data = await response.json();
|
|
@@ -1525,17 +1538,34 @@ var ComplianceClient = class {
|
|
|
1525
1538
|
const startTime = Date.now();
|
|
1526
1539
|
this.validateRegistrationRequest(request);
|
|
1527
1540
|
let geoVerification = null;
|
|
1541
|
+
let cipherTextResult;
|
|
1528
1542
|
try {
|
|
1529
1543
|
if (this.config.debug) {
|
|
1530
1544
|
this.logger.debug("Starting registration verification", { customerId: request.customerId });
|
|
1531
1545
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1546
|
+
const customerData = request.cipherText ? {
|
|
1547
|
+
full_name: request.fullName,
|
|
1548
|
+
email: request.emailAddress,
|
|
1549
|
+
phone: request.phoneNumber,
|
|
1550
|
+
date_of_birth: request.dateOfBirth
|
|
1551
|
+
} : void 0;
|
|
1552
|
+
[cipherTextResult, geoVerification] = await Promise.all([
|
|
1553
|
+
this.executeCipherTextValidation(
|
|
1554
|
+
request.cipherText,
|
|
1555
|
+
request.customerId,
|
|
1556
|
+
"registration",
|
|
1557
|
+
request.ipAddress,
|
|
1558
|
+
customerData,
|
|
1559
|
+
requestOptions
|
|
1560
|
+
),
|
|
1561
|
+
this.geoClient.verifyIP({
|
|
1562
|
+
ip_address: request.ipAddress,
|
|
1563
|
+
user_id: request.customerId,
|
|
1564
|
+
event_type: "registration",
|
|
1565
|
+
device_fingerprint: request.deviceFingerprint
|
|
1566
|
+
}, requestOptions)
|
|
1567
|
+
]);
|
|
1568
|
+
const blockReasons = this.evaluateRegistrationBlock(geoVerification, cipherTextResult);
|
|
1539
1569
|
if (blockReasons.length > 0) {
|
|
1540
1570
|
if (this.config.debug) {
|
|
1541
1571
|
this.logger.debug("Registration blocked at geo stage", { blockReasons });
|
|
@@ -1547,7 +1577,8 @@ var ComplianceClient = class {
|
|
|
1547
1577
|
requiresKYC: false,
|
|
1548
1578
|
requiresEDD: false,
|
|
1549
1579
|
blockReasons,
|
|
1550
|
-
processingTime: Date.now() - startTime
|
|
1580
|
+
processingTime: Date.now() - startTime,
|
|
1581
|
+
cipherTextValidation: cipherTextResult
|
|
1551
1582
|
};
|
|
1552
1583
|
}
|
|
1553
1584
|
const profile = await this.riskClient.createProfile({
|
|
@@ -1582,7 +1613,8 @@ var ComplianceClient = class {
|
|
|
1582
1613
|
requiresKYC,
|
|
1583
1614
|
requiresEDD,
|
|
1584
1615
|
blockReasons: [],
|
|
1585
|
-
processingTime: Date.now() - startTime
|
|
1616
|
+
processingTime: Date.now() - startTime,
|
|
1617
|
+
cipherTextValidation: cipherTextResult
|
|
1586
1618
|
};
|
|
1587
1619
|
} catch (error) {
|
|
1588
1620
|
if (this.config.debug) {
|
|
@@ -1610,7 +1642,7 @@ var ComplianceClient = class {
|
|
|
1610
1642
|
* @param geoVerification - Geolocation verification result
|
|
1611
1643
|
* @returns Array of block reasons (empty if allowed)
|
|
1612
1644
|
*/
|
|
1613
|
-
evaluateRegistrationBlock(geoVerification) {
|
|
1645
|
+
evaluateRegistrationBlock(geoVerification, cipherTextResult) {
|
|
1614
1646
|
const blockReasons = [];
|
|
1615
1647
|
if (geoVerification.is_blocked) {
|
|
1616
1648
|
blockReasons.push(...geoVerification.risk_reasons);
|
|
@@ -1644,6 +1676,20 @@ var ComplianceClient = class {
|
|
|
1644
1676
|
blockReasons.push("critical_risk_level");
|
|
1645
1677
|
}
|
|
1646
1678
|
}
|
|
1679
|
+
if (cipherTextResult) {
|
|
1680
|
+
if (!cipherTextResult.valid) {
|
|
1681
|
+
blockReasons.push("ciphertext_validation_failed");
|
|
1682
|
+
}
|
|
1683
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
1684
|
+
blockReasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
1685
|
+
}
|
|
1686
|
+
if (cipherTextResult.risk?.location_mismatch) {
|
|
1687
|
+
blockReasons.push("gps_ip_location_mismatch");
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
if (geoVerification.gps_required && !cipherTextResult) {
|
|
1691
|
+
blockReasons.push("gps_verification_required");
|
|
1692
|
+
}
|
|
1647
1693
|
return [...new Set(blockReasons)];
|
|
1648
1694
|
}
|
|
1649
1695
|
/**
|
|
@@ -1774,7 +1820,15 @@ var ComplianceClient = class {
|
|
|
1774
1820
|
if (this.config.debug) {
|
|
1775
1821
|
this.logger.debug("Starting login verification", { customerId: request.customerId });
|
|
1776
1822
|
}
|
|
1777
|
-
const [geoVerification, profileResult] = await Promise.all([
|
|
1823
|
+
const [cipherTextResult, geoVerification, profileResult] = await Promise.all([
|
|
1824
|
+
this.executeCipherTextValidation(
|
|
1825
|
+
request.cipherText,
|
|
1826
|
+
request.customerId,
|
|
1827
|
+
"login",
|
|
1828
|
+
request.ipAddress,
|
|
1829
|
+
void 0,
|
|
1830
|
+
requestOptions
|
|
1831
|
+
),
|
|
1778
1832
|
this.geoClient.verifyIP({
|
|
1779
1833
|
ip_address: request.ipAddress,
|
|
1780
1834
|
user_id: request.customerId,
|
|
@@ -1783,10 +1837,23 @@ var ComplianceClient = class {
|
|
|
1783
1837
|
}, requestOptions),
|
|
1784
1838
|
this.riskClient.getProfile(request.customerId, requestOptions).catch(() => null)
|
|
1785
1839
|
]);
|
|
1840
|
+
const loginBlockReasons = this.getBlockReasons(geoVerification, profileResult, cipherTextResult);
|
|
1841
|
+
const isBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
|
|
1842
|
+
if (isBlocked && !profileResult) {
|
|
1843
|
+
return {
|
|
1844
|
+
allowed: false,
|
|
1845
|
+
geolocation: geoVerification,
|
|
1846
|
+
profile: null,
|
|
1847
|
+
requiresStepUp: false,
|
|
1848
|
+
blockReasons: loginBlockReasons,
|
|
1849
|
+
processingTime: Date.now() - startTime,
|
|
1850
|
+
cipherTextValidation: cipherTextResult
|
|
1851
|
+
};
|
|
1852
|
+
}
|
|
1786
1853
|
let profile;
|
|
1787
1854
|
if (profileResult) {
|
|
1788
1855
|
profile = profileResult;
|
|
1789
|
-
if (this.shouldUpdateProfile(profile, geoVerification.location.city)) {
|
|
1856
|
+
if (!isBlocked && this.shouldUpdateProfile(profile, geoVerification.location.city)) {
|
|
1790
1857
|
profile = await this.riskClient.updateProfile(profile.id, {
|
|
1791
1858
|
last_recorded_activity: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1792
1859
|
location: `${geoVerification.location.city}, ${geoVerification.location.country}`,
|
|
@@ -1799,15 +1866,15 @@ var ComplianceClient = class {
|
|
|
1799
1866
|
}
|
|
1800
1867
|
profile = await this.createProfileFromGeo(request.customerId, geoVerification);
|
|
1801
1868
|
}
|
|
1802
|
-
const
|
|
1803
|
-
const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical";
|
|
1869
|
+
const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical" || cipherTextResult?.risk?.location_mismatch === true;
|
|
1804
1870
|
return {
|
|
1805
|
-
allowed:
|
|
1871
|
+
allowed: !isBlocked && profile.customer_status !== "suspended",
|
|
1806
1872
|
geolocation: geoVerification,
|
|
1807
1873
|
profile,
|
|
1808
1874
|
requiresStepUp,
|
|
1809
|
-
blockReasons: this.getBlockReasons(geoVerification, profile),
|
|
1810
|
-
processingTime: Date.now() - startTime
|
|
1875
|
+
blockReasons: isBlocked || profile.customer_status === "suspended" ? this.getBlockReasons(geoVerification, profile, cipherTextResult) : [],
|
|
1876
|
+
processingTime: Date.now() - startTime,
|
|
1877
|
+
cipherTextValidation: cipherTextResult
|
|
1811
1878
|
};
|
|
1812
1879
|
} catch (error) {
|
|
1813
1880
|
throw new ComplianceError("Login verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -1854,27 +1921,58 @@ var ComplianceClient = class {
|
|
|
1854
1921
|
currency: request.currency
|
|
1855
1922
|
});
|
|
1856
1923
|
}
|
|
1857
|
-
const [geoVerification,
|
|
1924
|
+
const [cipherTextResult, geoVerification, profileResult] = await Promise.all([
|
|
1925
|
+
this.executeCipherTextValidation(
|
|
1926
|
+
request.cipherText,
|
|
1927
|
+
request.customerId,
|
|
1928
|
+
"transaction",
|
|
1929
|
+
request.ipAddress,
|
|
1930
|
+
void 0,
|
|
1931
|
+
requestOptions
|
|
1932
|
+
),
|
|
1858
1933
|
this.geoClient.verifyIP({
|
|
1859
1934
|
ip_address: request.ipAddress,
|
|
1860
1935
|
user_id: request.customerId,
|
|
1861
1936
|
event_type: "transaction",
|
|
1862
1937
|
device_fingerprint: request.deviceFingerprint
|
|
1863
1938
|
}, requestOptions),
|
|
1864
|
-
this.riskClient.getProfile(request.customerId, requestOptions)
|
|
1939
|
+
this.riskClient.getProfile(request.customerId, requestOptions).catch(() => null)
|
|
1865
1940
|
]);
|
|
1941
|
+
const geoBlocked = !geoVerification.is_compliant || geoVerification.is_blocked || !!cipherTextResult?.risk?.is_blocked || cipherTextResult?.valid === false || geoVerification.gps_required && !cipherTextResult;
|
|
1942
|
+
if (geoBlocked && !profileResult) {
|
|
1943
|
+
return {
|
|
1944
|
+
allowed: false,
|
|
1945
|
+
geolocation: geoVerification,
|
|
1946
|
+
profile: null,
|
|
1947
|
+
transactionRisk: { score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1948
|
+
requiresApproval: false,
|
|
1949
|
+
blockReasons: this.getTransactionBlockReasons(
|
|
1950
|
+
geoVerification,
|
|
1951
|
+
{ score: 0, level: "low", factors: [], allowed: false, requiresManualReview: false },
|
|
1952
|
+
true,
|
|
1953
|
+
cipherTextResult
|
|
1954
|
+
),
|
|
1955
|
+
processingTime: Date.now() - startTime,
|
|
1956
|
+
cipherTextValidation: cipherTextResult
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
if (!profileResult) {
|
|
1960
|
+
throw new ComplianceError("Customer profile not found", request.customerId);
|
|
1961
|
+
}
|
|
1962
|
+
const profile = profileResult;
|
|
1866
1963
|
const transactionRisk = this.calculateTransactionRisk(
|
|
1867
1964
|
request.amount,
|
|
1868
1965
|
request.currency,
|
|
1869
1966
|
geoVerification,
|
|
1870
|
-
profile
|
|
1967
|
+
profile,
|
|
1968
|
+
cipherTextResult
|
|
1871
1969
|
);
|
|
1872
1970
|
const jurisdictionAllowed = this.checkJurisdictionLimits(
|
|
1873
1971
|
request.amount,
|
|
1874
1972
|
request.currency,
|
|
1875
1973
|
geoVerification.jurisdiction
|
|
1876
1974
|
);
|
|
1877
|
-
const isAllowed =
|
|
1975
|
+
const isAllowed = !geoBlocked && jurisdictionAllowed && transactionRisk.allowed && profile.customer_status !== "suspended";
|
|
1878
1976
|
return {
|
|
1879
1977
|
allowed: isAllowed,
|
|
1880
1978
|
geolocation: geoVerification,
|
|
@@ -1884,9 +1982,11 @@ var ComplianceClient = class {
|
|
|
1884
1982
|
blockReasons: this.getTransactionBlockReasons(
|
|
1885
1983
|
geoVerification,
|
|
1886
1984
|
transactionRisk,
|
|
1887
|
-
jurisdictionAllowed
|
|
1985
|
+
jurisdictionAllowed,
|
|
1986
|
+
cipherTextResult
|
|
1888
1987
|
),
|
|
1889
|
-
processingTime: Date.now() - startTime
|
|
1988
|
+
processingTime: Date.now() - startTime,
|
|
1989
|
+
cipherTextValidation: cipherTextResult
|
|
1890
1990
|
};
|
|
1891
1991
|
} catch (error) {
|
|
1892
1992
|
throw new ComplianceError("Transaction verification failed", error instanceof Error ? error.message : void 0);
|
|
@@ -1901,12 +2001,22 @@ var ComplianceClient = class {
|
|
|
1901
2001
|
async verifyEvent(request, requestOptions) {
|
|
1902
2002
|
const startTime = Date.now();
|
|
1903
2003
|
this.validateEventRequest(request);
|
|
1904
|
-
const geoVerification = await
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2004
|
+
const [cipherTextResult, geoVerification] = await Promise.all([
|
|
2005
|
+
this.executeCipherTextValidation(
|
|
2006
|
+
request.cipherText,
|
|
2007
|
+
request.customerId,
|
|
2008
|
+
request.eventType,
|
|
2009
|
+
request.ipAddress,
|
|
2010
|
+
void 0,
|
|
2011
|
+
requestOptions
|
|
2012
|
+
),
|
|
2013
|
+
this.geoClient.verifyIP({
|
|
2014
|
+
ip_address: request.ipAddress,
|
|
2015
|
+
user_id: request.customerId,
|
|
2016
|
+
event_type: request.eventType,
|
|
2017
|
+
device_fingerprint: request.deviceFingerprint
|
|
2018
|
+
}, requestOptions)
|
|
2019
|
+
]);
|
|
1910
2020
|
if (this.config.autoCreateProfiles) {
|
|
1911
2021
|
try {
|
|
1912
2022
|
const profile = await this.riskClient.getProfile(request.customerId, requestOptions);
|
|
@@ -1919,11 +2029,26 @@ var ComplianceClient = class {
|
|
|
1919
2029
|
}
|
|
1920
2030
|
}
|
|
1921
2031
|
}
|
|
2032
|
+
const cipherTextBlocked = cipherTextResult ? !cipherTextResult.valid || cipherTextResult.risk?.is_blocked === true : false;
|
|
2033
|
+
const blockReasons = [...geoVerification.risk_reasons];
|
|
2034
|
+
if (cipherTextResult) {
|
|
2035
|
+
if (!cipherTextResult.valid) {
|
|
2036
|
+
blockReasons.push("ciphertext_validation_failed");
|
|
2037
|
+
}
|
|
2038
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
2039
|
+
blockReasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
const gpsBlocked = geoVerification.gps_required && !cipherTextResult;
|
|
2043
|
+
if (gpsBlocked) {
|
|
2044
|
+
blockReasons.push("gps_verification_required");
|
|
2045
|
+
}
|
|
1922
2046
|
return {
|
|
1923
|
-
allowed: geoVerification.is_compliant && !geoVerification.is_blocked,
|
|
2047
|
+
allowed: geoVerification.is_compliant && !geoVerification.is_blocked && !cipherTextBlocked && !gpsBlocked,
|
|
1924
2048
|
geolocation: geoVerification,
|
|
1925
|
-
blockReasons:
|
|
1926
|
-
processingTime: Date.now() - startTime
|
|
2049
|
+
blockReasons: [...new Set(blockReasons)],
|
|
2050
|
+
processingTime: Date.now() - startTime,
|
|
2051
|
+
cipherTextValidation: cipherTextResult
|
|
1927
2052
|
};
|
|
1928
2053
|
}
|
|
1929
2054
|
// ============================================================================
|
|
@@ -1952,7 +2077,29 @@ var ComplianceClient = class {
|
|
|
1952
2077
|
kyc_status: "pending"
|
|
1953
2078
|
});
|
|
1954
2079
|
}
|
|
1955
|
-
|
|
2080
|
+
/**
|
|
2081
|
+
* Execute cipherText validation with graceful degradation.
|
|
2082
|
+
* Returns undefined if cipherText is not provided or validation fails.
|
|
2083
|
+
*/
|
|
2084
|
+
async executeCipherTextValidation(cipherText, userId, eventType, ipAddress, customerData, requestOptions) {
|
|
2085
|
+
if (!cipherText) return void 0;
|
|
2086
|
+
try {
|
|
2087
|
+
return await this.geoClient.validateCipherText(
|
|
2088
|
+
cipherText,
|
|
2089
|
+
userId,
|
|
2090
|
+
eventType,
|
|
2091
|
+
ipAddress,
|
|
2092
|
+
customerData,
|
|
2093
|
+
requestOptions
|
|
2094
|
+
);
|
|
2095
|
+
} catch (err) {
|
|
2096
|
+
this.logger.warn("CipherText validation failed, proceeding with IP-only", {
|
|
2097
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
2098
|
+
});
|
|
2099
|
+
return void 0;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
calculateTransactionRisk(amount, currency, geoVerification, profile, cipherTextResult) {
|
|
1956
2103
|
if (!this._currencyRatesCustomized && !this._currencyRatesWarned) {
|
|
1957
2104
|
this._currencyRatesWarned = true;
|
|
1958
2105
|
this.logger.warn(
|
|
@@ -1985,6 +2132,15 @@ var ComplianceClient = class {
|
|
|
1985
2132
|
riskScore += 50;
|
|
1986
2133
|
factors.push("account_suspended");
|
|
1987
2134
|
}
|
|
2135
|
+
if (cipherTextResult) {
|
|
2136
|
+
if (cipherTextResult.risk?.location_mismatch) {
|
|
2137
|
+
riskScore += 20;
|
|
2138
|
+
factors.push("gps_ip_location_mismatch");
|
|
2139
|
+
}
|
|
2140
|
+
if (cipherTextResult.risk?.score) {
|
|
2141
|
+
riskScore += cipherTextResult.risk.score * 0.2;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
1988
2144
|
return {
|
|
1989
2145
|
score: Math.min(riskScore, 100),
|
|
1990
2146
|
level: this.getRiskLevel(riskScore),
|
|
@@ -2010,20 +2166,33 @@ var ComplianceClient = class {
|
|
|
2010
2166
|
if (score >= 40) return "medium";
|
|
2011
2167
|
return "low";
|
|
2012
2168
|
}
|
|
2013
|
-
getBlockReasons(geoVerification, profile) {
|
|
2169
|
+
getBlockReasons(geoVerification, profile, cipherTextResult) {
|
|
2014
2170
|
const reasons = [];
|
|
2015
2171
|
if (geoVerification.is_blocked) {
|
|
2016
2172
|
reasons.push(...geoVerification.risk_reasons);
|
|
2017
2173
|
}
|
|
2018
|
-
if (profile
|
|
2019
|
-
|
|
2174
|
+
if (profile) {
|
|
2175
|
+
if (profile.customer_status === "suspended") {
|
|
2176
|
+
reasons.push("account_suspended");
|
|
2177
|
+
}
|
|
2178
|
+
if (profile.has_sanctions) {
|
|
2179
|
+
reasons.push("sanctions_match");
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
if (cipherTextResult) {
|
|
2183
|
+
if (!cipherTextResult.valid) {
|
|
2184
|
+
reasons.push("ciphertext_validation_failed");
|
|
2185
|
+
}
|
|
2186
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
2187
|
+
reasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
2188
|
+
}
|
|
2020
2189
|
}
|
|
2021
|
-
if (
|
|
2022
|
-
reasons.push("
|
|
2190
|
+
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2191
|
+
reasons.push("gps_verification_required");
|
|
2023
2192
|
}
|
|
2024
|
-
return reasons;
|
|
2193
|
+
return [...new Set(reasons)];
|
|
2025
2194
|
}
|
|
2026
|
-
getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed) {
|
|
2195
|
+
getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed, cipherTextResult) {
|
|
2027
2196
|
const reasons = [];
|
|
2028
2197
|
if (!geoVerification.is_compliant) {
|
|
2029
2198
|
reasons.push("non_compliant_jurisdiction");
|
|
@@ -2034,7 +2203,18 @@ var ComplianceClient = class {
|
|
|
2034
2203
|
if (!transactionRisk.allowed) {
|
|
2035
2204
|
reasons.push(...transactionRisk.factors);
|
|
2036
2205
|
}
|
|
2037
|
-
|
|
2206
|
+
if (cipherTextResult) {
|
|
2207
|
+
if (!cipherTextResult.valid) {
|
|
2208
|
+
reasons.push("ciphertext_validation_failed");
|
|
2209
|
+
}
|
|
2210
|
+
if (cipherTextResult.risk?.is_blocked) {
|
|
2211
|
+
reasons.push(...cipherTextResult.risk.block_reasons || []);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
if (geoVerification.gps_required && !cipherTextResult) {
|
|
2215
|
+
reasons.push("gps_verification_required");
|
|
2216
|
+
}
|
|
2217
|
+
return [...new Set(reasons)];
|
|
2038
2218
|
}
|
|
2039
2219
|
// ============================================================================
|
|
2040
2220
|
// Location Request Methods
|
|
@@ -2855,235 +3035,93 @@ var TaxClient = class extends BaseClient {
|
|
|
2855
3035
|
};
|
|
2856
3036
|
super(baseConfig);
|
|
2857
3037
|
}
|
|
2858
|
-
//
|
|
2859
|
-
// Tax
|
|
2860
|
-
//
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
*
|
|
2866
|
-
* @example
|
|
2867
|
-
* ```typescript
|
|
2868
|
-
* const config = await client.getTaxConfig();
|
|
2869
|
-
* console.log(`Tax enabled: ${config.tax_enabled}`);
|
|
2870
|
-
* ```
|
|
2871
|
-
*/
|
|
2872
|
-
async getTaxConfig() {
|
|
2873
|
-
const res = await this.request("/api/v1/tax/config");
|
|
2874
|
-
return res.tax_config;
|
|
3038
|
+
// ==========================================================================
|
|
3039
|
+
// P1 — Customer Tax Profile (core compliance flow)
|
|
3040
|
+
// ==========================================================================
|
|
3041
|
+
async getCustomerTaxProfileRecord(customerID) {
|
|
3042
|
+
return this.request(
|
|
3043
|
+
`/api/v1/tax/customer-tax-profiles/${customerID}`
|
|
3044
|
+
);
|
|
2875
3045
|
}
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
*
|
|
2882
|
-
* @example
|
|
2883
|
-
* ```typescript
|
|
2884
|
-
* // Enable tax
|
|
2885
|
-
* const config = await client.updateTaxConfig({ tax_enabled: true });
|
|
2886
|
-
*
|
|
2887
|
-
* // Disable tax
|
|
2888
|
-
* const config = await client.updateTaxConfig({ tax_enabled: false });
|
|
2889
|
-
* ```
|
|
2890
|
-
*/
|
|
2891
|
-
async updateTaxConfig(request) {
|
|
2892
|
-
const res = await this.request("/api/v1/tax/config", {
|
|
2893
|
-
method: "PUT",
|
|
2894
|
-
body: JSON.stringify({ tax_config: request })
|
|
2895
|
-
});
|
|
2896
|
-
return res.tax_config;
|
|
3046
|
+
async requestTaxForm(customerID) {
|
|
3047
|
+
return this.request(
|
|
3048
|
+
`/api/v1/tax/customer-tax-profiles/${customerID}/request-form`,
|
|
3049
|
+
{ method: "POST" }
|
|
3050
|
+
);
|
|
2897
3051
|
}
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
* Get solicitation triggers for the tenant
|
|
2903
|
-
*
|
|
2904
|
-
* @returns List of solicitation triggers with their enabled state
|
|
2905
|
-
*
|
|
2906
|
-
* @example
|
|
2907
|
-
* ```typescript
|
|
2908
|
-
* const triggers = await client.getSolicitationTriggers();
|
|
2909
|
-
* triggers.forEach(t => console.log(`${t.label}: ${t.enabled}`));
|
|
2910
|
-
* ```
|
|
2911
|
-
*/
|
|
2912
|
-
async getSolicitationTriggers() {
|
|
2913
|
-
const res = await this.request(
|
|
2914
|
-
"/api/v1/tax/solicitation/config"
|
|
3052
|
+
async checkTINStatus(customerID) {
|
|
3053
|
+
return this.requestWithRetry(
|
|
3054
|
+
`/api/v1/tax/customer-tax-profiles/${customerID}/check-tin`,
|
|
3055
|
+
{ method: "POST" }
|
|
2915
3056
|
);
|
|
2916
|
-
return res.solicitation_triggers;
|
|
2917
3057
|
}
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
* @param triggers - Array of triggers with updated enabled/threshold values
|
|
2922
|
-
* @returns Updated triggers
|
|
2923
|
-
*
|
|
2924
|
-
* @example
|
|
2925
|
-
* ```typescript
|
|
2926
|
-
* const triggers = await client.updateSolicitationTriggers([
|
|
2927
|
-
* { type: 'first_withdrawal', enabled: true, label: 'First Withdrawal', description: '...' },
|
|
2928
|
-
* { type: 'threshold_based', enabled: true, label: 'Threshold', description: '...', threshold_amount: 600 },
|
|
2929
|
-
* ]);
|
|
2930
|
-
* ```
|
|
2931
|
-
*/
|
|
2932
|
-
async updateSolicitationTriggers(triggers) {
|
|
2933
|
-
const res = await this.request(
|
|
2934
|
-
"/api/v1/tax/solicitation/config",
|
|
3058
|
+
async reRequestTaxForm(customerID, input) {
|
|
3059
|
+
return this.request(
|
|
3060
|
+
`/api/v1/tax/customer-tax-profiles/${customerID}/re-request-form`,
|
|
2935
3061
|
{
|
|
2936
|
-
method: "
|
|
2937
|
-
body: JSON.stringify(
|
|
3062
|
+
method: "POST",
|
|
3063
|
+
body: JSON.stringify(input)
|
|
2938
3064
|
}
|
|
2939
3065
|
);
|
|
2940
|
-
return res.solicitation_triggers;
|
|
2941
3066
|
}
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
/**
|
|
2946
|
-
* Get the reminder configuration for the tenant
|
|
2947
|
-
*
|
|
2948
|
-
* @returns Reminder config (enabled, max_reminders, frequency_days)
|
|
2949
|
-
*
|
|
2950
|
-
* @example
|
|
2951
|
-
* ```typescript
|
|
2952
|
-
* const config = await client.getReminderConfig();
|
|
2953
|
-
* console.log(`Reminders enabled: ${config.enabled}, every ${config.frequency_days} days`);
|
|
2954
|
-
* ```
|
|
2955
|
-
*/
|
|
2956
|
-
async getReminderConfig() {
|
|
2957
|
-
const res = await this.request(
|
|
2958
|
-
"/api/v1/tax/solicitation/reminder-config"
|
|
2959
|
-
);
|
|
2960
|
-
return res.reminder_config;
|
|
2961
|
-
}
|
|
2962
|
-
/**
|
|
2963
|
-
* Update the reminder configuration for the tenant
|
|
2964
|
-
*
|
|
2965
|
-
* @param config - Reminder configuration to set
|
|
2966
|
-
* @returns Updated reminder config
|
|
2967
|
-
*
|
|
2968
|
-
* @example
|
|
2969
|
-
* ```typescript
|
|
2970
|
-
* const updated = await client.updateReminderConfig({
|
|
2971
|
-
* enabled: true,
|
|
2972
|
-
* max_reminders: 3,
|
|
2973
|
-
* frequency_days: 7,
|
|
2974
|
-
* });
|
|
2975
|
-
* ```
|
|
2976
|
-
*/
|
|
2977
|
-
async updateReminderConfig(config) {
|
|
2978
|
-
const res = await this.request(
|
|
2979
|
-
"/api/v1/tax/solicitation/reminder-config",
|
|
3067
|
+
async enableBackupWithholding(customerID, input) {
|
|
3068
|
+
return this.request(
|
|
3069
|
+
`/api/v1/tax/customer-tax-profiles/${customerID}/enable-withholding`,
|
|
2980
3070
|
{
|
|
2981
|
-
method: "
|
|
2982
|
-
body: JSON.stringify(
|
|
3071
|
+
method: "POST",
|
|
3072
|
+
body: JSON.stringify(input)
|
|
2983
3073
|
}
|
|
2984
3074
|
);
|
|
2985
|
-
return res.reminder_config;
|
|
2986
3075
|
}
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
* @param filters - Optional filters (customer_id, form_type, form_status, etc.)
|
|
2994
|
-
* @returns Paginated list of tax forms
|
|
2995
|
-
*
|
|
2996
|
-
* @example
|
|
2997
|
-
* ```typescript
|
|
2998
|
-
* const result = await client.listTaxForms({ form_type: 'W-9', form_status: 'Pending' });
|
|
2999
|
-
* console.log(`Found ${result.total} forms`);
|
|
3000
|
-
* ```
|
|
3001
|
-
*/
|
|
3002
|
-
async listTaxForms(filters) {
|
|
3003
|
-
const params = {};
|
|
3004
|
-
if (filters) {
|
|
3005
|
-
if (filters.customer_id) params.customer_id = filters.customer_id;
|
|
3006
|
-
if (filters.form_type) params.form_type = filters.form_type;
|
|
3007
|
-
if (filters.form_status) params.form_status = filters.form_status;
|
|
3008
|
-
if (filters.tin_status) params.tin_status = filters.tin_status;
|
|
3009
|
-
if (filters.avalara_company_id) params.avalara_company_id = filters.avalara_company_id;
|
|
3010
|
-
if (filters.search) params.search = filters.search;
|
|
3011
|
-
if (filters.start_date) params.start_date = filters.start_date;
|
|
3012
|
-
if (filters.end_date) params.end_date = filters.end_date;
|
|
3013
|
-
if (filters.page) params.page = filters.page;
|
|
3014
|
-
if (filters.page_size) params.limit = filters.page_size;
|
|
3015
|
-
}
|
|
3016
|
-
return this.request(`/api/v1/tax/forms${this.buildQueryString(params)}`);
|
|
3017
|
-
}
|
|
3018
|
-
/**
|
|
3019
|
-
* Get a tax form by ID
|
|
3020
|
-
*
|
|
3021
|
-
* @param formId - Tax form UUID
|
|
3022
|
-
* @returns Tax form details
|
|
3023
|
-
*/
|
|
3024
|
-
async getTaxForm(formId) {
|
|
3025
|
-
return this.request(`/api/v1/tax/forms/${formId}`);
|
|
3026
|
-
}
|
|
3027
|
-
/**
|
|
3028
|
-
* Get lifecycle events for a tax form
|
|
3029
|
-
*
|
|
3030
|
-
* @param formId - Tax form UUID
|
|
3031
|
-
* @returns List of lifecycle events
|
|
3032
|
-
*/
|
|
3033
|
-
async getTaxFormLifecycleEvents(formId) {
|
|
3034
|
-
const res = await this.request(
|
|
3035
|
-
`/api/v1/tax/forms/${formId}/lifecycle`
|
|
3076
|
+
async downloadTaxForm(customerID, requestOptions) {
|
|
3077
|
+
return this.request(
|
|
3078
|
+
`/api/v1/tax/customer-tax-profiles/${customerID}/download-form`,
|
|
3079
|
+
{ method: "GET" },
|
|
3080
|
+
void 0,
|
|
3081
|
+
{ ...requestOptions, responseType: "arraybuffer" }
|
|
3036
3082
|
);
|
|
3037
|
-
return res.lifecycle_events;
|
|
3038
3083
|
}
|
|
3039
|
-
//
|
|
3040
|
-
//
|
|
3041
|
-
//
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
* @param customerID - Customer ID
|
|
3046
|
-
* @returns Customer tax profile with all forms and events
|
|
3047
|
-
*
|
|
3048
|
-
* @example
|
|
3049
|
-
* ```typescript
|
|
3050
|
-
* const profile = await client.getCustomerTaxProfile('cust_123');
|
|
3051
|
-
* console.log(`Customer has ${profile.tax_forms.length} tax forms`);
|
|
3052
|
-
* ```
|
|
3053
|
-
*/
|
|
3054
|
-
async getCustomerTaxProfile(customerID) {
|
|
3055
|
-
return this.request(`/api/v1/tax/profile/${customerID}`);
|
|
3084
|
+
// ==========================================================================
|
|
3085
|
+
// P2 — Tenant Tax Rules
|
|
3086
|
+
// ==========================================================================
|
|
3087
|
+
async getTaxRules() {
|
|
3088
|
+
const res = await this.request("/api/v1/tax/rules");
|
|
3089
|
+
return res.rules;
|
|
3056
3090
|
}
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
* @returns Paginated list of tax companies
|
|
3066
|
-
*/
|
|
3067
|
-
async listTaxCompanies(page, pageSize) {
|
|
3091
|
+
async updateTaxRules(input) {
|
|
3092
|
+
const res = await this.request("/api/v1/tax/rules", {
|
|
3093
|
+
method: "PUT",
|
|
3094
|
+
body: JSON.stringify({ rules: input })
|
|
3095
|
+
});
|
|
3096
|
+
return res.version;
|
|
3097
|
+
}
|
|
3098
|
+
async getComplianceStats(filters) {
|
|
3068
3099
|
const params = {};
|
|
3069
|
-
if (
|
|
3070
|
-
if (
|
|
3100
|
+
if (filters?.time_range) params.time_range = filters.time_range;
|
|
3101
|
+
if (filters?.from_date) params.from_date = filters.from_date;
|
|
3102
|
+
if (filters?.to_date) params.to_date = filters.to_date;
|
|
3071
3103
|
return this.request(
|
|
3072
|
-
`/api/v1/tax/
|
|
3104
|
+
`/api/v1/tax/tenant/w-form-tenant-stats${this.buildQueryString(params)}`
|
|
3073
3105
|
);
|
|
3074
3106
|
}
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
return
|
|
3107
|
+
// ==========================================================================
|
|
3108
|
+
// P3 — Global Tax Rule & Treaty Countries
|
|
3109
|
+
// ==========================================================================
|
|
3110
|
+
async getCurrentGlobalTaxRule() {
|
|
3111
|
+
const res = await this.request(
|
|
3112
|
+
"/api/v1/tm/tenant/global-tax-rules/current"
|
|
3113
|
+
);
|
|
3114
|
+
return res.data;
|
|
3115
|
+
}
|
|
3116
|
+
async listTreatyCountries() {
|
|
3117
|
+
return this.request("/api/v1/tax/treaty-countries");
|
|
3118
|
+
}
|
|
3119
|
+
async getTreatyCountry(code) {
|
|
3120
|
+
const res = await this.request(
|
|
3121
|
+
`/api/v1/tax/treaty-countries/${encodeURIComponent(code)}`
|
|
3122
|
+
);
|
|
3123
|
+
return res.treaty_country;
|
|
3083
3124
|
}
|
|
3084
|
-
// ============================================================================
|
|
3085
|
-
// Utility Methods (inherited from BaseClient: healthCheck, updateConfig, getConfig, buildQueryString)
|
|
3086
|
-
// ============================================================================
|
|
3087
3125
|
};
|
|
3088
3126
|
|
|
3089
3127
|
// src/transaction/client.ts
|