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